分类 无序区域 下的文章

作者不详,防止没有数据,备份一份
第四章 在UI窗口下需要处理下列windows消息.

1、WM_IME_SETCONTEXT

激活或休眠输入法

LRESULT CALLBACK UIWndProc(HWND hUIWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{

case WM_IME_SETCONTEXT:
fSet= (BOOL) wParam;

lISCBits = lParam;

}

如果fSet为TRUE,系统将激活当前输入法的某个窗口(状态窗、列表窗等),为FALSE时休眠当前输入法.

其中lISCBits中指出对哪个窗口操作。

数值 含义

ISC_SHOWUICOMPOSITIONWINDOW 显示编码窗口
ISC_SHOWUIGUIDWINDOW 显示信息窗口
ISC_SHOWUICANDIDATEWINDOW 显示0号列表窗口
(ISC_SHOWUICANDIDATEWINDOW << 1) 显示1号列表窗口.
(ISC_SHOWUICANDIDATEWINDOW << 2) 显示2号列表窗口.
(ISC_SHOWUICANDIDATEWINDOW << 3) 显示3号列表窗口.

2、WM_IME_CONTROL

管理当前输入法

wSubMessage= wParam; 受WM_IME_CONTROL 控制的消息

lpData = (LPVOID) lParam; 对应的数据

其中子消息有下列消息:

1)IMC_GETCANDIDATEPOS

获取列表窗口的位置.此时lParam传送的是CANDIDATEFORM结构地址。

如果此消息成功返回0,否则非零。

通常如果你设计此部分了,返回0。否则返回1。

2)IMC_GETCOMPOSITONFONT

获取编码窗口字体结构, lParam为LOGFONT结构地址

如果此消息成功返回0,否则非零。

通常如果你设计此部分了,返回0。否则返回1。

3)IMC_GETCOMPOSITONWINDOW

获取编码窗口位置,lParam为COMPOSITIONFORM结构地址。

如果此消息成功返回0,否则非零。

通常如果你设计此部分了,返回0。否则返回1。

4)IMC_GETSOFTKBDFONT

获取软键盘字体。 lParam字体结构LOGFONT地址。

5)IMC_GETSOFTKBDPOS

获取软键盘位置,lParam = 0;

返回软键盘在屏幕窗口中的坐标结构POINTS。

6)IMC_GETSOFTKBDSUBTYPE

wSubMessage= IMC_GETSOFTKBDSUBTYPE;

lParam = 0;

7)IMC_GETSTATUSWINDOWPOS

获取状态窗口位置

wSubMessage= IMC_GETSTATUSWINDOWPOS;

lParam = 0;

返回状态窗口坐标原点在屏幕窗口中的坐标结构POINTS。

8)IMC_SETCANDIDATEPOS

wSubMessage= IMC_SETCANDIDATEPOS;

lpCANDIDATEFORM= (LPCANDIDATEFORM) lParam;

设置列表窗口的位置.此时lParam传送的是CANDIDATEFORM结构地址。

如果此消息成功返回0,否则非零。

注意:UI窗口不接受此消息,它的管理函数是NotifyIME。

9)IMC_SETCOMPOSITONFONT

设置编码窗口的字体.此时lParam传送的是LOGFONT结构地址。

wSubMessage= IMC_SETCOMPOSITIONFONT;

lpLogFont= (LPLOGFONT) lParam;

注意:UI窗口不接受此消息,它的管理函数是NotifyIME。

10)IMC_SETCOMPOSITONWINDOW

设置编码窗口属性,此时lParam传送的是COMPOSITIONFORM结构地址。

wSubMessage= IMC_SETCOMPOSITIONWINDOW;

lpCOMPOSITIONFORM= (LPCOMPOSITIONFORM) lParam;

如果此消息成功返回0,否则非零。

注意:UI窗口不接受此消息,它的管理函数是NotifyIME。

11)IMC_SETSOFTKBDDATA

设置软键盘数据,此时lParam传送的是SOFTKBDDATA结构地址,用户设定自己的软键盘字符。

wSubMessage= IMC_SETSOFTKBDDATA;

lpSoftKbdData= (LPSOFTKBDDATA) lParam;

如果此消息成功返回0,否则非零。

注意:UI窗口不接受此消息,它的管理函数是NotifyIME。

12)IMC_SETSOFTKBDSUBTYPE

设置软键盘类型

wSubMessage= IMC_SETSOFTKBDSUBTYPE;

lSubType= lParam;

成功返回subtype,否则返回-1.

注意:UI窗口不接受此消息,它的管理函数是NotifyIME。

13)IMC_SETSOFTKBDFONT

设置软键盘字体,此时lParam传送的是LOGFONT结构地址

wSubMessage= IMC_SETSOFTKBDFONT;

lpLogFont= (LPLOGFONT)lParam;

如果此消息成功返回0,否则非零。

注意:UI窗口不接受此消息,它的管理函数是NotifyIME。

14)IMC_SETSOFTKBDPOS

设置软件位置,此时lParam传送的是POINTS结构

wSubMessage= IMC_SETSOFTKBDPOS;

ptsPt= (POINTS)lParam;

如果此消息成功返回0,否则非零。

15)IMC_SETSTATUSWINDOWPOS

设置状态窗口位置,此时lParam传送的是POINTS结构

wSubMessage= IMC_SETSTATUSWINDOWPOS;

ptsPt= (POINTS)lParam;

如果此消息成功返回0,否则非零。

3、WM_IME_COMPOSITION

当用户改变了编码状态时,发送此消息WM_IME_COMPOSITION

应用程序可以通过调用ImmGetCompositionString获取新的编码状态。

wChar= wParam; 最后输入到编码窗口的2字节的DBCS字符

lAttribute= lParam; 当前编码的含义。

lAttribute可取下列值得组合:

值 含义

GCR_ERRORSTR 修正错误
GCR_INFORMATIONSTR 修正信息串
GCS_COMPATTR 修正编码串属性.
GCS_COMPCLAUSE 修正编码信息.
GCS_COMPREADATTR 修正读入串的属性
GCS_COMPREADCLAUSE 修正读入串的属性.
GCS_COMPREADSTR 修正读入串。
GCS_COMPSTR 修正当前的编码
GCS_CURSORPOS 修正当前编码的光标位置.
GCS_DELTASTART 修正当前编码的开始位置
GCS_RESULTCLAUSE 修正结果串的信息.
GCS_RESULTREADCLAUSE 修正读入串的信息.
GCS_RESULTREADSTR 修正读入串.
GCS_RESULTSTR 修正编码结果串.
CS_INSERTCHAR 在当前位置插入一个字符
CS_NOMOVECARET 替换结果串

4、WM_IME_COMPOSITIONFULL

用户接口窗口不能增加编码窗口的尺寸时,ime用户接口窗口将发送WM_IME_COMPOSITIONFULL消息,可不处理。

wParam = 0

lParam= 0

5、WM_IME_ENDCOMPOSITION

当编码结束时ime发送此消息WM_IME_ENDCOMPOSITION

wParam = 0

lParam= 0

用户程序可以接受此消息,以便自己显示用户输入的编码。

6、WM_IME_SELECT

系统发出WM_IME_SELECT以便选择一个新的ime。

fSelect= (BOOL)wParam; TRUE表示新的IME已选择,FALSE表示不被选择或关闭该输入法。

hKL= lParam;

系统利用这个消息产生或关闭老的输入法用户窗口。

7、WM_IME_STARTCOMPOSITION

当用户开始输入编码时,系统立即发送该消息到IME中,IME打开编码窗口。

wParam = 0

lParam= 0

8、WM_IME_NOTIFY

IME消息组:

wSubMessage= wParam;

lParam= lParam;

各消息说明:

1)IMN_CLOSESTATUSWINDOW

关闭状态窗口时,系统发送IMN_CLOSESTATUSWINDOW消息。

wSubMessage = IMN_CLOSESTATUSWINDOW;

lParam= 0;

当用户接口窗口接收到此消息时,将关闭状态窗口。

2)IMN_OPENSTATUSWINDOW

产生或打开状态窗口

wSubMessage = IMN_OPENSTATUSWINDOW;

lParam= 0;

当ime接收到此消息时,将产生状态窗口.

有关状态串口的信息可用ImmGetConversionStatus获取,设置状态窗口的信息可用ImmSetConversionStatus.

3)IMN_OPENCANDIDATE

打开或产生列表选择窗口

wSubMessage = IMN_OPENCANDIDATE;

lCandidateList= lParam;

4)IMN_CHANGECANDIDATE

更新当前的列表选择窗口

WM_IME_NOTIFY

wSubMessage = IMN_CHANGECANDIDATE;

lCandidateList= lParam;

5)IMN_CLOSECANDIDATE

关闭选择窗口

wSubMessage = IMN_CLOSECANDIDATE;

lCandidateList= lParam;

UI窗口接收此消息后,将销毁列表选择窗口

IMN_SETCONVERSIONMODE

改变输入法状态模式管理

wSubMessage = IMN_SETCONVERSIONMODE;

lParam= 0;

IMN_SETOPENSTATUS

设置输入法状态

wSubMessage = IMN_SETOPENSTATUS;

lParam= 0;

IMN_SETCANDIDATEPOS

设置列表窗口位置

wSubMessage = IMN_SETCANDIDATEPOS;

lCandidateList= lParam;

Parameters

IMN_SETCOMPOSITIONFONT

设置编码窗口字体

wSubMessage = IMN_SETCOMPOSITIONFONT;

lParam= 0;

IMN_SETCOMPOSITIONWINDOW

设置编码窗口

wSubMessage = IMN_SETCOMPOSITIONWINDOW;

lParam= 0;

IMN_GUIDELINE

错误信息处理

wSubMessage = IMN_GUIDELINE;

lParam= 0;

IMN_SOFTKBDDESTROYED

关闭软键盘
wSubMessage = IMN_SOFTKBDDESTROYED;

lParam= 0;

作者不详,防止没有数据,备份一份
第三章 ime文件中必须使用的结构

前二章我们讲述了ime和imm函数,二者之间是靠下列结构通讯的。

1、IMEINFO

struct tagIMEInfo { //输入法的接口信息 用于ImeInquire函数中

DWORD dwPrivateDataSize;//用户设计的数据结构的字节数

DWORD fdwProperty; //输入法对键盘事件的相应特性

//其中其高字可为下列字节位的组合:

//=IME_PROP_AT_CARET 转换窗口是否放置在需插入字符的位置

//=IME_PROP_SPECIAL_UI 该输入法具有特殊用户接口

//=IME_PROP_CANDLIST_START_FROM_1 输入法的选择窗口中汉字串的起始序号为1

//=IME_PROP_UNICODE 支持UNICODE字符

//其中其低字可为下列字节位的组合:

//=IME_PROP_END_UNLOAD

//=IME_PROP_KBD_CHAR_FIRST 首先由键盘转换字符

//=IME_PORP_NEED_ALTKEY 将ALT键盘事件传送到IME输入法内

//=IME_PROP_IGNORE_UPKEYS 禁止上位键事件进入输入法内

//=IME_PROP_COMPLETE_ON_UNSELECT 当关闭输入法时,完成编码的转换

// 用于 W98及2000 中

DWORD fdwConversionCaps;//当前输入法具有的功能特性,如有软键、标点、中西文切换等功能

//=IME_CMODE_NATIVE 设置活动模式

//=IME_CMODE_FULLSHAPE 设置全角模式

//=IME_CMODE_CHARCODE 设置为字符模式

//=IME_CMODE_SOFTKBD //设置软键盘模式

//=IME_CMODE_NOCONVERSION //不支持模式变换

//=IME_CMODE_EUDC //

//=IME_CMODE_SYMBOL //设置标点字符模式

DWORD fdwSentenceCaps; //

//=IME_SMODE_PLAURALCLAUSE

//=IME_SMODE_SINGLECONVERT

//=IME_SMODE_AUTOMETIC

//=IME_SMODE_CONVERSATION

DWORD fdwUICaps; // 用户界面能力:支持软键盘等

//=UI_CAP_2700

//=UI_CAP_ROT90

//=UI_CAP_ROTANY

//=UI_CAP_SOFKBD

DWORD fdwSCSCaps; // 用户设置编码串的能力

//=SCS_CAP_COMPSTR

//=SCS_CAP_MAKEREAD

DWORD fdwSelectCaps; // 输入法切换时是否使用以前输入法的模式

//=SELECT_CAP_CONVMODE

//=SELECT_CAP_SENTENCE

} IIMEINFO;

2、COMPOSITIONSTR 用于编码管理

typedef struct tagCOMPOSITIONSTR { //用于存放编码信息的信息:所有的实际信息放在本结构的后面

DWORD dwSize; //当前编码信息需要的存储空间=读入的编码+属性+子串+属性+编码+属性+结果+属性

DWORD dwCompReadAttrLen; //读入的编码属性长度

DWORD dwCompReadAttrOffset; //存放在内存的位置

DWORD dwCompReadClsLen; //读入的子串长度

DWORD dwCompReadClsOffset; //存放在内存的位置

DWORD dwCompReadStrLen; //读入的编码长度

DWORD dwCompReadStrOffset; //存放在内存的位置

DWORD dwCompAttrLen; //编码属性长度

DWORD dwCompAttrOffset; //存放在内存的位置

DWORD dwCompClsLen; //编码子串长度

DWORD dwCompClsOffset; //存放在内存的位置

DWORD dwCompStrLen; //编码串长度

DWORD dwCompStrOffset; //存放在内存的位置

DWORD dwCursorPos; //当前光标位置

DWORD dwDeltaStart; //被修改编码的位置

DWORD dwResultReadClsLen; //读入结果子串长度

DWORD dwResultReadClsOffset; //存放在内存的位置

DWORD dwResultReadStrLen; //读入的编码长度

DWORD dwResultReadStrOffset; //存放在内存的位置

DWORD dwResultClsLen; //结果子串长度

DWORD dwResultClsOffset; //存放在内存的位置

DWORD dwResultStrLen; //结果串长度

DWORD dwResultStrOffset; //存放在内存的位置

DWORD dwPrivateSize; //用户自定义数据长度

DWORD dwPrivateOffset; //存放在内存的位置

} COMPOSITIONSTR;

3、CANDIDATEINFO 用于编码选择管理

typedef struct tagCANDIDATEINFO { //编码选择信息的信息,其后为实际编码列表数据

DWORD dwSize; //数据所占内存大小

DWORD dwCount; //表马列表个数

DWORD dwOffset[32]; //各个编码列表的内存位置

DWORD dwPrivateSize; //自定义数据尺寸

DWORD dwPrivateOffset; //缓冲区位置

} CANDIDATEINFO;

4、GUIDELINE

typedef struct tagGUIDELINE {

DWORD dwSize;

DWORD dwLevel; // the error level.

// GL_LEVEL_NOGUIDELINE,

// GL_LEVEL_FATAL,

// GL_LEVEL_ERROR,

// GL_LEVEL_WARNNING,

// GL_LEVEL_INFORMATION

DWORD dwIndex; // GL_ID_NODICTIONARY and so on.

DWORD dwStrLen; // Error Strings, if this is 0, there

// is no error string.

DWORD dwStrOffset;

DWORD dwPrivateSize;

DWORD dwPrivateOffset;

} GUIDELINE;

5、CANDIDATELIST

The CANDIDATELIST structure contains information about a candidate list.

typedef struct tagCANDIDATELIST { //编码选择列表信息 =〉管理编码窗口中的列表信息

DWORD dwSize; // 用字节表示的内存大小:=sizeof(CANDIDATELIST)+选择字符数据

DWORD dwStyle; // 列表串的取值方式

//=IME_CAND_UNKNOWN 列表数据的格式无定义

//=IME_CAND_READ 读到什么数据即为什么数据,一般我们使用该属性

//=IME_CAND_CODE 如果dwCount=1,dwOffset不是地址,而是实际数据,

// >1 dwOffset 表示地址

//=IME_CAND_MEANING

//=IME_CAND_RADICAL

//=IME_CAND_STROKES

DWORD dwCount; // 当前列表个数

DWORD dwSelection; // 当前选择的列表序号

DWORD dwPageStart; // 在列表窗口中所显示的列表的起始序号(上下翻页时用)

DWORD dwPageSize; // 一页显示的列表个数

DWORD dwOffset[]; // 列表数据存放区地址:[阿];[大]。。。。

} CANDIDATELIST;

6、COMPOSITIONFORM

typedef tagCOMPOSITIONFORM { //窗口位置、大小信息:

//由IMC_SETCOMPOSITIONWINDOW和IMC_SETCANDIDATEPOS消息使用

DWORD dwStyle; //管理窗口方式

//=CFS_DEFAULT 将编码窗口显示到隐含的位置

//=CFS_FORCE_POSITION // 以给定的坐标显示窗口,不受IME控制

//=CFS_POINT // 以给定的坐标显示窗口,受IME控制

//=CFS_RECT //以给定的大小显示窗口

POINT ptCurrentPos; //给定坐标

RECT rcArea; //给定窗口的小

}COMPOSITIONFORM;

7、CANDIDATEFORM

The CANDIDATEFORM structure is used for IMC_GETCANDIDATEPOS and IMC_SETCANDIDATEPOS messages.

typedef tagCANDIDATEFORM { //列表窗口信息

//由IMC_GETCANDIDATEPOS和IMC_SETCANDIDATEPOS消息处理

DWORD dwIndex; //列表窗口序号

DWORD dwStyle; //属性:

//=CFS_CANDIDATEPOS 指定显示位置

//=CFS_EXCLUDE 不可显示

//=CFS_DEFAULT 根据需要显示

POINT ptCurrentPos; //坐标位置

REC rcArea; //不可显示区

} CANDIDATEFORM;

8、STYLEBUF

typedef struct tagSTYLEBUF { //注册字结构

DWORD dwStyle;

TCHAR szDes cription[32]

} STYLEBUF;

9、SOFTKBDDATA

typedef struct tagSOFTKBDDATA { //软键盘中各键对应的汉字

UINT uCount; //键码数组个数(可以为1,2,当区分SHIFT键时为2,即:一组带SHIFT,一组不带SHIFT)

WORD wCode[][256] //对应的键码数据

} SOFTKBDDATA;

10、RECONVERTSTRING

typedef struct _tagRECONVERTSTRING { //用于W98和2000

DWOPD dwSize;

DWORD dwVersion;

DWORD dwStrLen;

DWORD dwStrOffset;

DWORD dwCompStrLen;

DWORD dwCompStrOffset;

DWORD dwTargetStrLen;

DWORD dwTargetStrOffset;

} RECONVERTSTRING;

11、IMEMENUITEMINFO

typedef _tagIMEMENUITEMINFO { //输入法菜单结构,W98/2000

UINT cbSize;

UINT fType;

UINT fState;

UINT wID;

HBITMAP hbmpChecked;

HBITMAP hbmpUnchecked;

DWORD dwItemData;

TCHAR szString[48];

HBITMAP hbmpItem;

}

12、INPUTCONTEXT

The INPUTCONTEXT structure is an internal data structure that stores Input Context data.

typedef struct tagINPUTCONTEXT { //IMC 数据存放区

HWND hWnd; //使用该IMC的窗口

BOOL fOpen; //IME的打开与关闭状态

POINT ptStatusWndPos; //状态窗口的位置

POINT ptSoftKbdPos; //软键盘的位置

DWORD fdwConversion; //IME状态(活动、不活动,全角等)

DWORD fdwSentence; //编码方式

union {

LOGFONTA A;

LOGFONTW W;

} lfFont; //字体

COMPOSITIONFORM cfCompForm; //编码格式结构

CANDIDATEFORM cfCandForm[4]; //列表选择结构

HIMCC hCompStr; //

HIMCC hCandInfo;

HIMCC hGuideLine

HIMCC hPrivate;

DWORD dwNumMsgBuf; //存放在hMsgBuf中的消息数

HIMCC hMsgBuf; //存放的消息,格式: [消息1] [wParam1] [lParam1] {[消息] [wParam2] [lParam2]...

//注意:我们输入的汉字串存放在这里

DWORD fdwInit //系统根据此值来初始本结构相应的信息

//=INIT_STATUSWNDPOS 初始化ptStatusWndPos

//=INIT_CONVERSION 初始化fdwConversion

//=INIT_SENTENCE 初始化fdwSentence

//=INIT_LOGFONT 初始化lfFont

//=INIT_COMPFORM 初始化cfCompForm

//=INIT_SOFTKBDPOS 初始化ptSoftKbdPos

DWORD dwReserve[3]; //将来版本扩展的信息

} INPUTCONTEXT;

作者不详,防止没有数据,备份一份
第二章 Windows9x系统提供的ime管理函数

上一章,我们介绍了ime文件中必须设计的函数,这些函数要靠我们自己来设计。要完成这些函数的设计,需用到windows系统提供的管理函数(Input Method Manager,简称IMM)。

IMM函数可以被IME函数使用,也可用于应用软件直接管理IME。

相关术语:

(1)input method context 简称IMC--输入法相关部分,在这里解释为:相关连的应用程序(进程)

(2)component of the input context 简称IMCC--IMC的部件,是INPUTCONTEXT 结构的成员。

一、IME中使用的IMM函数清单

ImmGetCompositionWindow //取编码窗口信息

ImmSetCompositionWindow //设置编码窗口信息

ImmGetCandidateWindow //取选择窗口信息

ImmSetCandidateWindow //设置选择窗口信息

ImmGetCompositionString //取编码窗口的某一信息

ImmSetCompositionString //设置编码窗口的某一信息

ImmGetCompositionFont //取编码字体

ImmSetCompositionFont //设置编码字体

ImmGetNumCandidateList //取选择区中编码数

ImmGetCandidateList //取选择区中编码

ImmGetGuideLine

ImmGetConversionStatus //取当前输入法的状态(ACSII,SHAPE,FULL等)

ImmGetConversionList //重新获得选择区转换表

ImmGetOpenStatus //取输入法打开属性

ImmSetConversionStatus //设置输入法状态

ImmSetOpenStatus //设置输入法打开状态

ImmNotifyIME //通报IME,输入法状态被改变

ImmGenerateMessage //将我们的汉字串法发送到与当前输入法相关联的应用软件中
ImmRequestMessage //向应用程序发送WM_IME_REQUEST

ImmLockIMC //获取当前IMC的INPUTCONTEXT结构信息,增加IMC 计数器
ImmUnlockIMC //释放IMC计数器
ImmGetIMCLockCount //取计数器值
ImmCreateIMCC //创建INPUTCONTEXT结构的一个成员
ImmDestroyIMCC //删除IMC成员缓冲区
ImmLockIMCC //取IMCC缓冲地址,同时使IMCC的计数器值增加
ImmUnlockIMCC //递减IMCC计数器
ImmReSizeIMCC //重新设置IMC的成员的缓冲区大小
ImmGetIMCCSize //取IMC成员的缓冲区大小
ImmGetIMCCLockCount //返回IMC计数器值
ImmGetHotKey //取输入法状态键,该函数供控制面板使用

ImmSetHotKey //设置输入法的热键
ImmCreateSoftKeyboard //产生一个软键盘
ImmDestroySoftKeyboard //销毁软键盘
ImmShowSoftKeyboard //显示或隐藏软键盘
二、IMM函数使用格式说明

1、BOOL WINAPI ImmGenerateMessage( //将我们的汉字串法发送到与当前输入法相关联的应用软件中
HIMC hIMC //与当前输入法相关联的应用软件的句柄,

//该结构的hMsgBuf项即为汉字串消息
)

成功为TRUE,否则为FALSE

2、LRESULT WINAPI ImmRequestMessage( //向应用程序发送WM_IME_REQUEST

//只是用于w98及w2000
HIMC hIMC, //与当前输入法相关联的应用软件的句柄
WPARAM wParam, //与WM_IME_REQUEST相关的wP
LPARAM lParam //与WM_IME_REQUEST相关的LP

//=IMR_COMPOSITIONWINOW

//=IMR_CANDIDATEWINDOW

//=IMR_COMPOSITIONFONT

//=IMR_RECONVERTSTRING

//=IMR_CONFIRMRECONVERTSTRING

//=IMR_QUERYCHARPOSITION

//=IMR_DOCUMENTFEED

)

3、LPINPUTCONTEXT WINAPI ImmLockIMC( //获取当前IMC的INPUTCONTEXT结构信息,增加IMC 计数器
HIMC hIMC //当前应用程序句柄
)

成功返回INPUTCONTEXT 结构指针,否则为NULL

4、BOOL WINAPI ImmUnlockIMC( //释放IMC计数器
HIMC hIMC //当前应用程序句柄
)

返回:如果IMC计数器被减少到0了,返回FALSE,否则为TRUE.

注意:ImmLockIMC与ImmUnlockIMC必须成对出现,必须是相同的HIMC

5、HIMCC WINAPI ImmGetIMCLockCount( //取计数器值
HIMC hIMC //当前应用程序句柄
)

如果成功返回HIMC的计数器值,否则为NULL.

6、HIMCC WINAPI ImmCreateIMCC( //创建INPUTCONTEXT结构的一个成员
DWORD dwSize //成员的缓冲区长度
)

如果成功返回IMC的成员句柄,否则为NULL

7、HIMCC WINAPI ImmDestroyIMCC( //删除IMC成员缓冲区
HIMCC hIMCC //被删除的IMC的成员
)

如果成功返回NULL,否则等于该HIMCC.

8、LPVOID WINAPI ImmLockIMCC( //取IMCC缓冲地址,同时使IMCC的计数器值增加
HIMCC hIMCC //IMC成员句柄
)

If the function is successful, the return value is the pointer for the IMC component. Otherwise, the return value is NULL.

9、BOOL WINAPI ImmUnlockIMCC( //递减IMCC计数器
HIMCC hIMCC //IMC成员句柄
)

如果IMCC的计数器值为零,则返回 FALSE,否则为TRUE.

10、HIMCC WINAPI ImmReSizeIMCC( //重新设置IMC的成员的缓冲区大小
HIMCC hIMCC, //IMC的成员句柄
DWORD dwSize //新缓冲区大小
)

如果成功,返回新的HIMCC,否则为 NULL.

11、DWORD WINAPI ImmGetIMCCSize( //取IMC成员的缓冲区大小
HIMCC hIMCC //IMC成员句柄
)

返回IMC成员的缓冲区大小

12、DWORD WINAPI ImmGetIMCCLockCount( //返回IMC计数器值
HIMCC hIMCC //IMC成员的句柄
)

成功返回该IMCC的计数器值,否则为0

13、BOOL WINAPI ImmGetHotKey( //取输入法状态键,该函数供控制面板使用
DWORD dwHotKeyID,
LPUINT lpuModifiers,
LPUINT lpuVKey,
LPHKL lphKL
)

14、BOOL WINAPI ImmSetHotKey( //设置输入法的热键
DWORD dwHotKeyID,
UINT uModifiers,
UINT uVKey,
hKL hKL
)

15、HWND WINAPI ImmCreateSoftKeyboard( //产生一个软键盘
UINT uType, //软件盘上的键码含义的定义方式

//=SOFTKEYBOARD_TYPE_T1

//=SOFTKEYBOARD_TYPE_C1
UINT hOwner, //该输入法的UI窗口
int x, //定位坐标
int y //定位坐标
)

成功返回软键盘的窗口句柄

16、BOOL WINAPI ImmDestroySoftKeyboard( //销毁软键盘
HWND hSoftKbdWnd //软年盘窗口句柄
)

成功为TRUE,法哦则为FALSE.

17、BOOL WINAPI ImmShowSoftKeyboard( //显示或隐藏软键盘
HWND hSoftKbdWnd, //软年盘窗口句柄
int nCmdShow //窗口状态=SW_HIDE 表示隐藏,=SW_SHOWNOACTIVATE表示显示
)

作者不详,防止没有数据,备份一份

第一章 Windows9x系统下汉字输入法的基本原理

Windows系统下汉字输入法实际上是将输入的标准ascii字符串按照一定的编码规则转换为汉字或汉字串,进入到目的地。由于应用程序各不相同,用户不可能自己去设计转换程序,因此,汉字输入自然而然落到WINDOWS系统管理中。

一、输入法与系统的关系

键盘事件  应用程序
|    |
Windows的USER.EXE

输入法管理器

输入法

系统的键盘事件有windows的user.exe软件接收后,user.exe在将键盘事件传导输入法管理器(Input Method Manager,简称IMM)中,管理器 再将键盘事件传到输入法中,输入法根据用户编码字典,翻译键盘事件为对应的汉字(或汉字串),然后再反传到user.exe中,user.exe再将翻译后的键盘事件传给当前正运行的应用程序,从而完成汉字的输入。

二、汉字输入法的组成

微软Windows9x系统中汉字输入法的名称是"Input Method Editor" ,简称IME,输入法的程序名称为:

.ime,数据文件名称为

.MB,即通常说的输入法编码表(字典).

实际上IME文件是一个动态连接库程序(DLL),它与dll文件没有区别,只是名称不同而已。

一般汉字输入法都由三个窗口组成:

状态窗口(Status Windows)-显示当前的输入法状态(中文还是英文等站环信息);

编码输入窗口(Composition Windows)-显示当前击键情况;

汉字选择窗口(Candidates Windows)-列出当前编码的全部汉字(串),供用户选择或查询。

上述三个窗口由基本的用户接口(User Interface )函数管理着。

现在我们用Dumpbin.exe打开微软提供的拼音输入法(WINDOWS\SYSTEM\WINPY.IME)看看它有什么组成(这里一WINDOWS98为例,并假定windows系统安装在c:盘下):

C:\Dumpbin c:\windows\system\winpy.ime

Microsoft (R) COFF Binary File Dumper Version 6.00.8168
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

Dump of file WINPY.IME

File Type: DLL       //IME 实际为dll程序

Section contains the following exports for WINPY.ime

0 characteristics
34A37323 time date stamp Fri Dec 26 17:04:35 1997
0.00 version
1 ordinal base
19 number of functions //共有19个函数
19 number of names     // 对应19个名称

ordinal hint RVA name

1 0 0000A010 CandWndProc  //"选择汉字窗口"注册函数
2 1 0000E750 CompWndProc  //"输入编码窗口"注册函数
3 2 0000FB50 ImeConfigure  //配置当前ime参数函数
4 3 0000FEC0 ImeConversionList//将字符或字符串转换成目标字符
5 4 0000FFA0 ImeDestroy   //退出当前使用的IME
6 5 000030D0 ImeEnumRegisterWord
7 6 0000FFB0 ImeEscape //应用软件访问输入法的接口函数.
8 7 00003080 ImeGetRegisterWordStyle
9 8 0000E9A0 ImeInquire      //启动并初始化当前IME输入法
10 9 0000A800 ImeProcessKey    //IME输入键盘事件管理函数
11 A 00002C20 ImeRegisterWord //向输入法字典注册字符串
12 B 000109A0 ImeSelect //启动当前IME输入法
13 C 000109E0 ImeSetActiveContext //设置当前的输入处于活动状态.
14 D 0000C850 ImeSetCompositionString 由应用程序设置输入法编码
15 E 0000AEE0 ImeToAsciiEx    //将输入的键盘事件转换为汉字编码事件
16 F 00002F40 ImeUnregisterWord //删除被注册的字符串.
17 10 0000CA90 NotifyIME   //IME事件管理函数
18 11 00005160 StatusWndProc //状态窗口注册函数
19 12 00002350 UIWndProc   //用户界面接口函数

Summary

5000 .ShareDa
7000 .data
2000 .idata
1000 .rdata
3000 .reloc
5000 .rsrc
2000 .sgroup
18000 .text

从上述可以看出,IME程序共有19个出口函数组成,每一个函数都有特定的格式,它们担负着与windows 系统传递信息的作用,这些函数是供Windows系统调用的。

三、输入法的函数简介

下面我们将介绍上述各个函数的功能及接口格式。

  1. BOOL ImeInquire( //初始化IME
    LPIMEINFO lpIMEInfo, //用于初始化该输入法的结构地址
    LPTSTR lpszWndClass, //当前输入法的名称
    LPCTSTR或者dword lpszData //系统信息,9X系列值为0,NT/2000下有实际值
    )

如果该函数初始化成功,返回TURE,否则为FALSE

用户应该搞清楚IMEINFO结构,特关系着你设计的输入法是否成功.有关该结构请看"结构"一章.

2.DWORD IMEConversionList( // 将某字符或字符串转换成目标字符串
HIMC hIMC, // 与当前输入法相关的应用程序句柄
LPCTSTRlpSrc, // 要转换的字符串 (也可能是结果串,可由uFlag指定)
LPCANDIDATELIST lpDst, /// 转换后的字符串(也可能是源串,可由uFlag指定)
DWORD dwBufLen, //转换后有几个字符
UINT uFlag //指定结果的存放位置
)

如果成功,返回转换后的字符串长度

3.BOOL ImeConfigure( //用户设置输入法接口
HKL hKL, //当前输入法句柄
HWND hWnd, //配置窗口的父窗口
DWORD dwMode, //配置什么
LPVOID lpData //用户设置的数据
)

该函数的功能是提供给输入法使用者一个可以更改某些隐含设置的能力.

如果你用过别人的输入法,其中的"配置输入法..."功能既是也!

对于一个初写输入法的人,可以不予理它.

4.BOOL ImeDestroy( //关闭当前输入法
UINT uReserved //无用 (0)
)

成功返回TURE,否则为FALSE

5.LRESULT ImeEscape( //用户软件访问输入法内部信息的接口
HIMC hIMC, //当前的应用程序句柄
UINT uEscape, //设置函数功能

//=IME_ESC_QUERY _SUPPORT

//=IME_ESC_RESERVED_LAST IME_ESC_RESERVED_FIRST

//=IME_ESC_PRIVATE_FIRST IME_ESC_PRIVATE_LAST

//=IME_ESC_SEQUENCE_TO_ INTERNAL

//=IME_ESC_GET_EUDC_ DICTIONARY

//=IME_ESC_SET_EUDC_ DICTIONARY

//=IME_ESC_MAX_KEY

//=IME_ESC_IME_NAME

//=IME_ESC_SYNC_HOTKEY

//=IME_ESC_HANJA_MODE

//=IME_ESC_GETHELPFILENAME(只适应 Windows 98和Windows 2000)

//=IME_ESC_PRIVATE_HOTKEY(w95下不可用)

LPVOID lpData //当前功能所需的数据
)

如果失败,返回0,否则有个功能决定

有时,人们可以用此函数怀区输入法的名称、帮助文件名称等。当然,我们可以不提供这些功能。

6、BOOL ImeSetActiveContext( //激活或搁置当前的输入法
HIMC hIMC, //当前用户程序句柄
BOOL fFlag //激活或搁置:=TRUE 激活 =FALSE 搁置
)

成功返回TRUE,否则为FALSE

7、BOOL ImeProcessKey( //处理应用程序传入的所有击键事件,监测是否是当前输入法所需的
HIMC hIMC, //应用程序句柄
UINT uVirKey, //需处理的虚键
DWORD lParam, //击键消息参数
CONST LPBYTE lpbKeyState //当前键盘状态(256字节)
)

如果此键是该输入法需要的,则返回TRUE,否则为FALSE

只有返回true的击键,IME才去处理

8、BOOL NotifyIME( //输入法选择窗口状态管理函数:
HIMC hIMC, //当前的应用程序句柄
DWORD dwAction, //状态值
DWORD dwIndex, //与状态值有关的序号
DWORD dwValue //与状态值有关的值
)

状态值说明:

=NI_OPENCANDIDATE 打开编码选择窗口

=NI_CLOSECANDIDATE 关闭当前的编码选择窗

=NI_SELECTCANDIDATESTR 选摘编码

此时:dwIndex 被选择的编码列表序号.

dwValue 被选中的编码在当前的编码列表中的序号

=NI_CHANGECANDIDATELIST 改变当前的编码列表(按pageup等键操作)

此时:dwIndex 被选择的编码列表序号.

dwValue 不用

=NI_SETCANDIDATE_PAGESTART 设置编码开始页号

此时: dwIndex 被改变的编码列表序号

dwValue 新页的开始序号.

=NI_SETCANDIDATE_PAGESIZE 改变编码列表页的大小

此时:dwIndex 当前编码页序号

dwValue 新的页大小

=NI_CONTEXTUPDATED 更新应用程序的信息的输入法的信息:移动位置,设置模式,设置编码窗口,字体。

此时:dwIndex 只用于 dwValue=IMC_SETCONVERSIONMODE, IMC_SETSENTENCEMODE

dwValue 可取由 WM_IME_CONTROL 发送的下列值:

IMC_SETCANDIDATEPOS

IMC_SETCOMPOSITIONFONT

IMC_SETCOMPOSITIONWINDOW

IMC_SETCONVERSIONMODE

IMC_SETSENTENCEMODE

IMC_SETOPENSTATUS

=NI_COMPOSITIONSTR 改变编码窗口中的编码

此时:dwIndex 取下列值:CPS_COMPLETE 完成编码转换

CPS_CONVERT 转换编码

CPS_REVERT 取消当前的编码

CPS_CANCEL 清除编码,并关闭编码窗

dwValue 不用

此函数成功,返回TRUE,否则为FALSE

9、BOOL ImeSelect( //初始化输入法
HIMC hIMC, //当前应用程序句柄
BOOL fSelect //是否初始化当前输入法,TRUE表示初始化
)

返回:成功返回true,否则为FALSE

The ImeSetCompositionString function is used by an application to set the IME composition string structure with the data contained in the lpComp or lpRead parameters. The IME then generates a message.

10、BOOL WINAPI ImeSetCompositionString( //将编码窗口中输入的编码保存的编码结构中,

//同志发送编码完成的消息

//( WM_IME_COMPOSITION)给系统,
HIMC hIMC, //当前的应用程序句柄
DWORD dwIndex, //设置此函数功能

//=SCS_SETSTR

//=SCS_CHANGEATTR

//=SCS_CHANGECLAUSE

//= SCS_QUERYRECONVERTSTRING

//=SCS_RECONVERTSTRING

//=SCS_SETRECONVERTSTRING

LPCVOID lpComp, //编码数据区
DWORD dwCompLen, //编码数据区长度
LPCVOID lpRead, //读入的编码数据
DWORD dwReadLen //读入的编码数据长度

11、UINT ImeToAsciiEx( //转换编码称汉字(串)
UINT uVirKey, //虚键
UINT uScanCode, //扫描码
CONST LPBYTE lpbKeyState, //用户定义的键盘状态
LPDWORD lpdwTransBuf, //转换后的数据存放区
UINT fuState, //活动菜单标志
HIMC hIMC //当前的应用程序句柄
)

返回:返回值表示有几个消息,可理解为:本编码对应的汉字串有几个汉字组成(当然,这并不相等)。

12、BOOL WINAPI ImeRegisterWord(
LPCTSTR lpszReading,
DWORD dwStyle,
LPCTSTR lpszString
)

13、BOOL WINAPI ImeUnregisterWord(
LPCTSTR lpszReading,
DWORD dwStyle,
LPCTSTR lpszString
)

14、UINT WINAPI
ImeGetRegisterWordStyle(
UINT nItem,
LPSTYLEBUF lpStyleBuf
)

15、UINT WINAPI ImeEnumRegisterWord(
hKL,
REGISTERWORDENUMPROC lpfnEnumProc,
LPCTSTR lpszReading,
DWORD dwStyle,
LPCTSTR lpszString,
LPVOID lpData
)

16、DWORD WINAPI ImeGetImeMenuItems(
HIMC hIMC,
DWORD dwFlags,
DWORD dwType,
LPIMEMENUITEMINFO lpImeParentMenu,
LPIMEMENUITEMINFO lpImeMenu,
DWORD dwSize
)

四.ime的版本信息(与普通DLL的区别)

VS_VERSION_INFO VERSIONINFO 代表字符 含义
FILEVERSION 4,0,0,950 //4.00.950 95版
PRODUCTVERSION 4,0,0,950 //4.00.950 95版
FILEFLAGSMASK 0x3fL
FILEFLAGS 0xaL
FILEOS 0x10004L //VOS_DOS_WINDOWS32 WIN32软件,可在DOS下运行
FILETYPE 0x3L //VFT_DRV 驱动程序
FILESUBTYPE 0xbL //VFT2_DRV_INPUTMETHOD 输入法驱动程序
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "080403a8"
BEGIN
VALUE "Comments", "\0"
VALUE "CompanyName", "唐码软件开发工作室\0"
VALUE "FileDes cription", "唐码输入法 版本1.0\0"
VALUE "FileVersion", "4.00.950\0"
VALUE "InternalName", "唐码输入法 版本1.0\0"
VALUE "LegalCopyright", "Copyright (C) 唐码软件开发工作室 1999-1999\0"
VALUE "LegalTrademarks", "\0"
VALUE "OriginalFilename", "TM.IME\0"
VALUE "PrivateBuild", "\0"
VALUE "ProductName", "唐码输入法 版本1.0\0"
VALUE "ProductVersion", "4.00.950\0"
VALUE "SpecialBuild", "\0"
END

作者不详,防止没有数据,备份一份
Windows 95输入法编辑器(IME)

原著:Microsoft
翻译:TBsoft Software Studio

一、关于Windows 95混合语言IME

在Windows 95中,IME是一个动态链接库(DLL),与Windows 3.1远东版本IME不同
的是,每一个运行的IME相当于混合语言键盘布局中的一种。与Windows 3.1 IME相
比较,Windows 95混合语言IME提供下列增强功能:
●运行时相当于混合语言环境的一个部件
●为每一个应用程序任务提供多重输入上下文
●为每一个应用程序线程提供一个活动的IME
●通过应用程序消息循环给应用程序提供信息(消息顺序不能改变)
●为无IME支持应用程序和部分IME支持应用程序提供有力的支持
要得到全部的增强功能,应用程序需要支持Windows 95 IME应用程序I/F。
本文档描述了Windows 95 IME体系结构的应用程序I/F。

1、IME的结构

Windows 95 IME必须提供两个部件:IME转换接口和IME用户接口。IME转换接口由
一组IME模块引出函数提供,这些函数被IMM(输入法管理器——译者注)调用。
IME用户接口由一组窗口提供,这些窗口接收消息并提供IME的用户界面。

2、IME支持应用程序(IME感知应用程序——译者注)

应用程序有下列类型:
●无IME支持应用程序:这种应用程序不控制IME,然而,如果应用程序接受DBCS字
符,用户可以通过IME在应用程序中输入DBCS字符。
●部分IME支持应用程序:这种应用程序只控制不同的IME上下文,例如打开和关闭
IME、写作窗口等等,但是不重新显示任何IME用户界面。
●完全IME支持应用程序:这种应用程序负责管理通过IME显示给应用程序的任何信
息。
在Windows 95中,一个无IME支持应用程序有一个缺省的IME窗口和一个缺省的输入
上下文。
部分IME支持应用程序使用预定义的“IME”类创建自己的IME窗口,可以管理或者
不管理自己的输入上下文。
完全IME支持应用程序自己管理输入上下文,显示输入上下文给出的任何需要的信
息,不使用IME窗口。

二、IME用户界面

IME用户界面包括IME窗口、用户界面(UI)窗口以及UI窗口的部件。

1、特征

IME类是实现IME用户界面部分的预定义全局窗口类。“IME”类与预定义的公共控
制窗口类有许多相同的特点,IME窗口实例与静态控制一样通过CreateWindowEx函
数创建,IME类窗口自己不响应用户输入,取而代之的是接收不同类型的控制消息
实现全部IME用户接口。应用程序可以使用IME类创建自己的IME窗口,还可以使用
ImmGetDefaultIMEWnd函数获取缺省IME窗口。创建自己的IME窗口或者使用缺省
IME窗口的应用程序被称为IME支持应用程序,具有以下优点(与对应的Windows
3.1应用程序比较):
●包括候选字列表窗口(候选窗口),每一个应用程序可以有自己的用户界面窗口
实例,使得用户可以在任何输入过程的中途停止并切换到另一个应用程序。在
Windows 3.1日文版本中,用户切换到另一个应用程序是必须放弃当前输入过程。

●因为IME用户界面窗口包括应用程序窗口句柄,IME用户界面窗口可以为应用程序
提供缺省行为。例如当应用程序移动时IME用户界面窗口自动移动,自动跟随窗口
中的插入符号位置,为每一个应用程序标示模式等等。
即使系统仅仅只提供一个IME类,IME窗口仍然有两种类型。一种类型是系统为无
IME支持应用程序创建的IME窗口,DefWindowProc函数为该窗口处理消息,
DefWindowProc函数的IME用户接口被线程的所有无IME支持窗口共享,在文档中,
这种窗口称为缺省IME窗口。另一种类型是IME支持应用程序创建的IME窗口,在文
档中,IME支持应用程序创建的IME窗口称作应用程序IME窗口。

2、缺省和应用程序IME窗口

当线程初始化时系统创建缺省IME窗口,这就是说,线程自动获取缺省IME窗口。缺
省IME窗口为无IME支持应用程序提供IME用户界面,当IME或者IMM生成一个IME消息
(WM_IME_*)时,无IME支持应用程序传递该消息到DefWindowProc函数,
DefWindowProc函数发送需要的消息到为应用程序提供缺省IME用户界面的缺省IME
窗口。IME支持应用程序当不从IME获取消息时也可以使用缺省IME窗口,需要时可
以使用自身的IME窗口。

3、IME类

IME类是Windows 95远东版本预定义的窗口类,就像Edit是预定义的窗口类一样。
预定义的IME类实现全部的IME用户接口,处理所有来自IME和包含IMM函数的应用程
序的消息,应用程序使用IME类创建自己的IME窗口。系统IME类不能被被任何IME替
换。
窗口过程与IME类通过WM_IME_SELECT消息交互,该消息包括新选中的IME的键盘布
局,IME类使用键盘布局查找到每一个IME定义的类名。使用类名,IME类为当前活
动的IME创建IME用户界面窗口。

4、IME UI类

每一个IME必须向系统注册自己的用户界面(UI)类,UI类提供IME相关功能。当
IME附加在进程上时IME注册自己的UI类,这就是说,当DLLEntry函数被调用
DLL_PROCESS_ATTACH功能时,IME必须在对ImeInquire函数的调用过程中指定UI类
名。UI类应该使用CS_IME窗口风格注册以使得每一个应用程序都可以使用UI类。
UI类名(包括空终结符)可以使用16位的TCHAR字符,这个限制可能延续到
Windows的未来版本。
当注册一个UI类时,应该指定8个字节的窗口附加数据(这就是说,设置
WNDCLASSEX类的cbWndExtra成员的值为2*sizeof(LONG)),系统使用该窗口附加数
据。
IME可以在为应用程序执行任务时注册任何类和创建任何窗口。
下面的实例显示了怎样注册IME窗口类:

BOOL WINAPI DLLEntry (
HINSTANCE hInstDLL,
DWORD dwFunction,
LPVOID lpNot)
{
switch (dwFunction) {
case DLL_PROCESS_ATTACH:
hInst= hInstDLL;

wc.style = CS_MYCLASSFLAG | CS_IME;
wc.lpfnWndProc = MyUIServerWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 2 * sizeof(LONG);
wc.hInstance = hInst;
wc.hCursor = LoadCursor( NULL, IDC_ARROW);
wc.hIcon = NULL;
wc.lpszMenuName = (LPSTR) NULL;
wc.lpszClassName = (LPSTR) szUIClassName;
wc.hbrBackground = NULL;

if(!RegisterClass((LPWNDCLASS)&wc))
return FALSE;

wc.style = CS_MYCLASSFLAG | CS_IME;
wc.lpfnWndProc = MyCompStringWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = cbMyWndExtra;
wc.hInstance = hInst;

wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = NULL;
wc.lpszMenuName = (LPSTR) NULL;
wc.lpszClassName = (LPSTR) szUICompStringClassName;
wc.hbrBackground = NULL;

if(!RegisterClass((LPWNDCLASS)&wc))
return FALSE;

break;

case DLL_PROCESS_DETACH:
UnregisterClass(szUIClassName,hInst);
UnregisterClass(szUICompStringClassName,hInst);
break;
}
return TRUE;
}

5、UI窗口

IME类对应的IME窗口被应用程序或者系统创建,当IME窗口被创建时,IME自身提供
的UI窗口被创建并被IME窗口所拥有。每一个UI窗口有一个当前的输入上下文,当
UI窗口接收到IME消息(WM_IME_*)时,可以通过调用GetWindowLong函数和指定
IMMGWL_IMC索引值查找到输入上下文,UI窗口可以根据输入上下文处理消息,UI窗
口可以在除响应WM_CREATE消息以外的任何时间查找到输入上下文。
IME不允许改变UI窗口的窗口附加数据,如果UI窗口的某个实例需要窗口附加数据
,可以使用IMMGWL_PRIVATE参数值调用SetWindowLong和GetWindowLong函数,
IMMGWL_PRIVATE参数值提供为UI窗口的某个实例存取附加数据中LONG类型值的能力
,如果需要大于LONG类型值的附加数据,可以保存一个内存块的句柄到
IMMGWL_PRIVATE域。
UI窗口过程可以使用DefWindowProc函数,但是UI窗口不允许传递IME消息给
DefWindowProc函数,即使某个IME消息没有被处理,UI窗口也不允许传递该消息给
DefWindowProc函数。

LRESULT UIWndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
HIMC hIMC;
HGLOBAL hMyExtra;

switch(msg){
case WM_CREATE:
// Allocate the memory bloack for the window instance.
hMyExtra = GlobalAlloc(GHND,size_of_MyExtra);
if (!hMyExtra)
MyError();

// Set the memory handle into IMMGWL_PRIVATE
SetWindowLong(hWnd, IMMGWL_PRIVATE, (LONG)hMyExtra);
.
.
.
break;

case WM_IME_xxxx:
// Get IMC;
hIMC = GetWindowLong(hWnd,IMMGWL_IMC);

// Get the memory handle for the window instance.
hMyExtra = GetWindowLong(hWnd, IMMGWL_PRIVATE);

lpMyExtra = GlobalLock(hMyExtra);
.
.
.

GlobalUnlock(hMyExtra);

break;

.
.
.

case WM_DESTROY:
// Get the memory handle for the window instance.
hMyExtra = GetWindowLong(hWnd, IMMGWL_PRIVATE);

// Free the memory block for the window instance.
GlobalFree(hMyExtra);
break;

default:
return DefWindowProc(hWnd, msg, wParam, lParam);

}
}

UI窗口必须在当前选定的输入上下文中执行动作,当一个窗口被激活时,UI窗口接
收到提供当前输入上下文的消息,此后,UI窗口运行在当前选中的输入上下文上。
输入上下文必须包括UI窗口显示写作窗口、状态窗口等需要的所有信息。
UI窗口要求输入上下文,但是窗口不必自己更新输入上下文。当UI窗口需要更新输
入上下文时,应该调用IMM函数,因为输入上下文由IMM函数管理,当输入上下文更
新时,IMM和IME接收到通知消息。
例如,有时UI窗口当鼠标单击时需要改变输入上下文的转换模式,为了设置转换模
式,UI窗口调用ImmSetConversionMode函数,该函数为NotifyIME生成一个通知消
息并发送WM_IME_NOTIFY消息到UI窗口,如果UI窗口改变转换模式的显示,UI窗口
会等待处理WM_IME_NOTIFY消息。

6、UI窗口的部件

UI窗口可以根据输入上下文注册和显示写作窗口和状态窗口,UI窗口的部件类的窗
口风格必须包括CS_IME。UI窗口的一个窗口实例从当前输入上下文接收例如写作字
符串、字体、位置等信息,当应用程序的一个窗口获得焦点时,系统获取该窗口自
己的输入上下文并将当前输入上下文传递给UI窗口,系统发送WM_IME_SETCONTEXT
消息和输入上下文的句柄给应用程序,应用程序传递该消息给UI窗口。如果当前输
入上下文被更新,UI窗口应该重新绘制写作窗口,无论何时输入上下文改变,UI窗
口都应该显示正确的写作窗口,可以保证IME的状态。
UI窗口可以创建子窗口或者弹出式窗口显示状态、写作字符串或者候选字列表,这
些窗口必须是UI窗口的附属窗口,而且必须创建为不可接收输入(Disable)窗口
,任何IME创建的窗口都不应该获取焦点。

三、输入上下文

1、缺省输入上下文

缺省情况下系统给每个线程一个输入上下文,该输入上下文被线程的所有无IME支
持窗口共享。

2、输入上下文与窗口的交互

应用程序的一个窗口可以使用窗口句柄与输入上下文交互以维护任何IME状态,包
括中间写作字符串。一旦应用程序使得输入上下文与窗口句柄交互,无论何时窗口
被激活,系统自动选中输入上下文。使用这个特点,应用程序可以轻松地完成
Windows 3.1下必须的复杂切换处理。

3、使用输入上下文

当应用程序或者系统创建新的输入上下文时,系统准备新的输入上下文,新的输入
上下文已经包括IMCC,这个IMC的部件由hCompStr、hCandInfo、hGuideLine、
hPrivate和hMsgBuf组成。IME基本上不需要创建输入上下文和输入上下文的部件,
不过IME可以改变它们的大小,可以通过锁定它们查找到部件的指针。

⑴存取HIMC

为了存取输入上下文,IME必须调用ImmLockIMC函数以查找到输入上下文的指针,
ImmLockIMC函数给IMC增加imm锁定计数,ImmUnlockIMC函数减少之。

⑵存取HIMCC

为了存取输入上下文中的一个部件,IME必须调用ImmLockIMCC函数获取IMCC的指针
,ImmLockIMCC函数给IMCC增加imm锁定计数,ImmUnlockIMCC函数减少之,
ImmReSizeIMCC函数可以修改IMCC的大小以指定新的大小。
某些情况下,IME可能需要自己创建输入上下文的一个部件,这种情况下,IME可以
调用ImmCreateIMCC函数获取IMCC的句柄,这个IMCC可以是INPUTCONTEXT结构的成
员(hCompStr、hCandInfo、hGuideLine、hPrivate或者hMsgBuf)。
ImmDestroyIMCC清除输入上下文的一个部件。

⑶怎样使用输入上下文

下面的实例显示了怎样使用输入上下文

LPINPUTCONTEXT lpIMC;
LPCOMOSITIONSTRING lpCompStr;
HIMCC hMyCompStr;

if (hIMC) { // It is not NULL context.
lpIMC = ImmLockIMC(hIMC);

if (!lpIMC) {
MyError( "Can not lock hIMC");
return FALSE;
}

// Use lpIMC->hCompStr.
lpCompStr = (LPCOMPOSITIONSTRING) ImmLockIMCC(lpIMC->hCompStr);

// Access lpCompStr.
ImmUnlockIMCC(lpIMC->hCompStr);

// ReSize lpIMC->hCompStr.
if (!(hMyCompStr = ImmReSizeIMCC(lpIMC->hCompStr,dwNewSize)) {
MyError("Can not resize hCompStr");
ImmUnlockIMC(hIMC);
return FALSE;
}
lpIMC->hCompStr = hMyCompStr;
ImmUnlockIMC(hIMC);
}

四、生成消息

IME需要生成IME消息。当IME开始转换时,IME必须生成WM_IME_STARTCOMPOSITION
消息,如果IME改变了写作字符串,IME必须生成WM_IME_COMPOSITION消息,IME引
发的事件导致生成消息给与输入上下文进行交互的窗口。IME基本上使用
ImeToAsciiEx函数参数提供的lpdwTransKey缓冲区生成消息,当ImeToAsciiEx函数
被调用时IME存储消息到lpdwTransKey缓冲区中,不过即使ImeToAsciiEx函数没有
被调用,IME也可以生成消息给使用输入上下文的消息缓冲区与输入上下文交互的
窗口。输入上下文有一个内存块的句柄作为消息缓冲区,IME存储消息到被消息缓
冲区句柄提供的内存块中,以后IME调用ImmGenerateMessage函数,
ImmGenerateMessage函数发送保存在消息缓冲区中的消息到适当的窗口。

1、在ImeToAsciiEx函数中使用消息缓冲区

下面的实例显示了怎样通过传递缓冲区到ImeToAsciiEx函数生成消息:

UINT ImeToAsciiEx(uVirKey, uScanCode, lpbKeyState, lpdwTransBuf,
fuState , hIMC )
{
DWORD dwMyNumMsg = 0;

.
.
.

// Set the messages that the IME needs to generate.
*lpdwTransBuf++ = (DWORD) msg;
*lpdwTransBuf++ = (DWORD) wParam;
*lpdwTransBuf++ = (DWORD) lParam;

// Count the number of the messages that the IME needs to generate.

dwMyNumMsg++;
.
.
.

return dwMyNumMsg;
}

系统提供lpdwTransBuf参数指定的缓冲区,IMEToAsciiEx函数可以一次存储所有的
消息到该缓冲区中,缓冲区的第一个双字给出存储在缓冲区中的消息个数。如果
ImeToAsciiEx函数需要生成比这个给定的个数更多的消息,函数可以存储所有的消
息到输入上下文的hMsgBuf域中,然后函数ImeToAsciiEx返回消息个数。当
ImeToAsciiEx函数的返回值大于lpdwTransBuf中指定的值时,系统不从
lpdwTransBuf中取出消息,系统查找作为ImeToAsciiEx函数参数传递的输入上下文
中的hMsgBuf域。

2、使用消息缓冲区

下面的实例显示了怎样使用消息缓冲区:

MyGenerateMesage(HIMC hIMC, UINT msg, WPARAM wParam, LPARAMlParam)
{
LPINPUTCONTEXT lpIMC;
HGLOBAL hTemp;
LPDWORD lpdwMsgBuf;
DWORD dwMyNumMsg = 1;

// Lock the input context.
lpIMC = ImmLockIMC(hIMC);
if (!lpIMC)
// Error!

// re-allocate the memory bloack for the message buffer.
hTemp = ImmReSizeIMCC(lpIMC->hMsgBuf,
(lpIMC->dwNumMsgBuf + dwMyNumMsg) * sizeof(DWORD) * 3);
if (!hTemp)
// Error!

lpIMC->hMsgBuf = hTemp;

// Lock the memory for the message buffer.
lpdwMsgBuf = ImmLockIMCC(lpIMC->hMsgBuf);
if (!lpdwMsgBuf)
// Error!

lpdwNumMsgBuf += 3 * lpIMC->dwNumMsgBuf.
// Set the number of the messages.
lpIMC->dwNumMsgBuf += dwMyNumMsg;

// Set the messages that the IME needs to generate.
*lpdwMsgBuf++ = (DWORD) msg;
*lpdwMsgBuf++ = (DWORD) wParam;
*lpdwMsgBuf++ = (DWORD) lParam;

// Unlock the memory for the message buffer and the input context.

ImmUnlockIMCC(lpIMC->hMsgBuf);
ImmLockIMC(hIMC);

// Call ImmGenerateMessage function.
ImmGenerateMessage(hIMC);
}

3、WM_IME_COMPOSITION消息

当IME生成WM_IME_COMPOSITION消息时,IME指定lParam参数为GCS位。GCS位的意义
是COMPOSITIONSTRING结构中的有效成员,即使IME没有更新,成员目前仍然有效,
IME也会设置GCS位。

为IME定义服务

当IME生成WM_IME_COMPOSITION消息时,IME可能会立刻改变字符串、属性以及子句
信息。IME使用下列定义:

GCS_COMP
GCS_COMPREAD
GCS_RESULT
GCS_RESULTREAD

五、关于ImeSetCompositionString函数

1、ImeSetCompositionString函数能力

如果IME没有ImeSetCompositionString函数能力,IME将不能在IMEINFO结构中指定
任何SCS能力。如果IME可以处理ImeSetCompositionString函数,IME设置
SCS_COMPSTR位。如果IME可以通过写作字符串生成解释(本文中的“解释”是单词
“reading”的直译,真正意义可能是“原始输入的”,例如输入的汉语拼音字母
字符串,下同)字符串,IME可以设置SCS_CAP_MAKEREAD位。
如果IME有SCS_CAP_COMPSTR能力,ImeSetCompositionString函数将被调用,IME从
应用程序获取新的写作字符串并生成WM_IME_COMPOSITION消息。
如果IME有SCS_CAP_MAKEREAD能力,IME可以通过写作字符串建立解释字符串。

2、关于SCS_SETSTR

如果ImeSetCompositionString函数的dwIndex参数值为SCS_SETSTR,IME可以清除
hIMC中的COMPOSITIONSTR结构中所有的域。
如果IME需要,IME可以更新候选信息并生成候选消息IMN_OPENCANDIDATE、
IMN_CHANGECANDIDATE或者IMN_CLOSECANDIDATE。
如果ImeSetCompositionString函数的lpRead参数有效,IME应该通过lpRead参数中
的解释字符串建立写作字符串,另外IME为新的写作字符串和lpRead参数中的解释
字符串建立属性和子句信息,IME生成lParam参数为(GCS_COMP|GCS_COMPREAD)的
WM_IME_COMPOSITION消息。有时IME需要自动确定建立上述信息,这种情况下,
IME可以生成lParam参数以(GCS_RESULT|GCS_RESULTREAD)代替GCS_COMPxxx的消
息。
如果ImeSetCompositionString函数的lpComp参数有效,IME应该通过lpComp参数中
的写作字符串建立写作属性和子句信息,IME生成lParam参数为GCS_COMP的
WM_IME_COMPOSITON消息。如果IME有SCS_CAP_MAKEREAD能力,IME应该同时建立解
释字符串,IME生成lParam参数为(GCS_COMP|GCS_COMPREAD)的
WM_IME_COMPOSITION消息。有时IME需要自动确定建立上述信息,这种情况下,
IME可以生成lParam参数以(GCS_RESULT|GCS_RESULTREAD)代替GCS_COMPxxx的消
息。
如果lpRead参数和lpComp参数同时有效,IME应该建立写作字符串和解释字符串,
这时IME不需要完全按照lpRead参数和lpComp参数。如果IME不能建立应用程序指定
的lpRead参数和lpComp参数之间的关系,IME应该修正写作字符串,IME为新的写作
字符串和lpRead参数指定的解释字符串建立属性和子句信息,IME生成lParam参数
为(GCS_COMP|GCS_COMPREAD)的WM_IME_COMPOSITION消息。有时IME需要自动完成
建立上述信息,这种情况下,IME可以生成lParam参数以(
GCS_RESULT|GCS_RESULTREAD)代替GCS_COMPxxx的消息。

3、关于SCS_CHANGEATTR

SCS_CHANGEATTR只影响属性信息,IME不应该更新写作字符串、写作字符串的子句
信息、写作字符串的解释以及写作字符串的解释子句信息。
首先IME检查新的属性并判断新的属性是否可用,然后IME设置属性到hIMC中的
COMPOSITIONSTRING结构中,最后IME生成WM_IME_COMPOSITION消息。
如果需要,IME可以更新候选信息并生成候选消息IMN_OPENCANDIDATE、
IMN_CHANGECANDIDATA、IMN_CLOSECANDIDATE。
IME不能确定写作字符串。
如果ImeSetCompositionString函数的lpRead参数有效,IME使用lpRead参数中的新
属性。IME也应该为当前写作字符串建立写作字符串的新属性,这时子句信息不被
修改。
写作字符串、属性、子句信息、解释字符串、解释属性和解释子句信息必须有效。
IME生成lParam参数为(GCS_COMP|GCS_COMPREAD)的WM_IME_COMPOSITION消息,如
果IME不能接受lpComp参数中的新属性,IME不需要生成任何消息并返回FALSE。
如果ImeSetCompositionString函数的lpComp参数有效,IME使用lpComp参数中的新
属性,这时子句信息不被修改。
如果IME有SCS_CAP_MAKEREAD能力,并且解释字符串有效,IME应该为当前写作字符
串的解释建立写作字符串的解释的新属性。
如果lpRead参数和lpComp参数同时有效,并且如果IME能够接受新的信息,IME设置
新的信息到hIMC中的COMPOSITION结构中并生成lParam参数为(
GCS_COMP|GCS_COMPREAD)的WM_IME_COMPOSITION消息。

4、关于SCS_CHANGECLAUSE

SCS_CHANGECLAUSE影响写作字符串和写作字符串的解释的字符串和属性。
如果需要,IME可以更新候选信息并生成候选消息IMN_OPENCANDIDATE、
IMN_CHANGECANDIDATA、IMN_CLOSECANDIDATE。
IME不能确定写作字符串。
如果ImeSetCompositionString函数的lpRead参数有效,IME使用lpRead参数中的解
释子句信息。IME必须修正写作字符串的解释的属性,IME可以更新写作字符串、属
性和写作字符串的子句信息,IME生成lParam参数为(GCS_COMP|GCS_COMPREAD)的
WM_IME_COMPOSITION消息。
如果ImeSetCompositionString函数的lpComp参数有效,IME使用新的子句信息。
IME必须修正写作字符串和写作字符串的属性,IME可以更新解释属性和解释的子句
信息,IME生成lParam参数为(GCS_COMP|GCS_COMPREAD)的WM_IME_COMPOSITION消
息。
如果lpRead参数和lpComp参数同时有效,并且如果IME能够接受新的信息,IME设置
新的信息到hIMC中的COMPOSITION结构中并生成lParam参数为(
GCS_COMP|GCS_COMPREAD)的WM_IME_COMPOSITION消息。

六、软键盘

1、关于软键盘

一些IME有特殊的解释字符,例如一个IME可能使用注音符号作为解释字符(这里指
台湾中文版Windows 95,即CWin95中的注音符号,PWin95中可能指汉语拼音字母或
者音调符号——译者注),另一个IME使用了一些字根符号(原文单词是“
radials”,但实际可能是“radicals”——译者注)作为解释字符,IME可以提供
一个软键盘显示这些特殊解释字符使得用户不必逐键记忆解释字符。
IME需要根据不同的变换状态改变键表示的解释字符,使用软键盘可以通知用户键
的改变。在选择候选字时,IME可以只显示那些选择键给用户。

2、使用软键盘

IME可能需要为软键盘创建一个更好的用户界面,或者可能需要系统预定义的软键
盘,如果IME需要使用系统预定义的软键盘,IME需要在调用ImeInquire函数时将
IMEINFO结构的fdwUICaps成员指定为UI_CAP_SOFTKBD。
IME可以调用ImmCreateSoftKeyboard函数为软键盘创建窗口,还可以调用
ImmShowSoftKeyboard函数显示或者隐藏软键盘。软键盘窗口是UI窗口的一个组件
,所以软键盘窗口应该附属于UI窗口。
IME可能需要决定是否在无论何时焦点移走的情况下删除窗口,软键盘可能占有一
些系统资源(可能需要释放——译者注)
软键盘有不同的类型,一种类型可能是为特定的国家或者特定的目的设计的。为每
一种类型的软键盘改变解释字符的方式可能不同,有两种改变解释字符的方式:使
用IMC_SETSOFKBDSUBTYPE或者IMC_SETSOFKBDDATA。不同类型的软键盘有不同的窗
口过程并存在不同的用户界面给用户。

七、IME接口

在Windows 95中,IME与设备驱动程序一样是动态链接库(DLL),输入法管理器(
IMM)应该处理所有安装的IME。因为IME在运行时是可以改变的,不需要重新启动
系统,IMM有一个结构用于维护每一个IME的所有入口点。
IME函数列表是所有远东版本Windows 95公共IME功能函数的描述,这些函数不应该
在应用程序中直接调用。

UI窗口中的IMM函数

下面是可以在UI窗口中调用的IMM函数:

ImmGetCompositionWindow
ImmSetCompositionWindow
ImmGetCandidateWindow
ImmSetCandidateWindow
ImmGetCompositionString
ImmSetCompositionString
ImmGetCompositionFont
ImmSetCompositionFont
ImmGetNumCandidateList
ImmGetCandidateList
ImmGetGuideLine
ImmGetConversionStatus
ImmGetConversionList
ImmGetOpenStatus
ImmSetConversionStatus
ImmSetOpenStatus
ImmNotifyIME
ImmCreateSoftKeyboard
ImmDestroySoftKeyboard
ImmShowSoftKeyboard