漫谈WinCE输入法的编写(一)
//========================================================================
//TITLE:
// 漫谈WinCE输入法的编写(一)
//AUTHOR:
// norains
//DATE:
// Saturday 10-February -2007
//Environment:
// EVC4.0 + Standard SDK
//========================================================================
WinCE的输入法编写,说复杂也不复杂,说简单亦不简单.说复杂嘛,是因为输入法是一个COM,需要实现某些接口,并且由于其特殊性,不能像普通应用程序一样进行调试;说简单嘛,只要把层次搞清,剩下的就和普通应用程序没什么太多的区别.
我觉得如果光谈概念,以我的文字功底,让人明白内中的机理,估计不是一件非常容易的事情.所以,我还是实际点,以我写过的一个输入法来做为例子.
因为这篇文章不是专门介绍COM接口技术的原理,我们的目的仅仅是让输入法给跑起来,因此我们只需要了解输入法用到了什么接口,以及我们应该如何定义该接口的功能即可.
为了代码层次分明,我这个例子采用了三个类:CClassFactory,CInputMethod和CIMWnd.前面两个类分别继承于IClassFactory和IInputMethod,是能让系统正常调用输入法所必须的com接口;而CIMWnd则是输入法的窗口,和普通的应用程序无异.
这三个类的关系是CClassFactory通过自身的CreateInstance()函数来创建一个CInputMethod类的对象,然后CInputMethod类中会调用CIMWnd类来显示一个输入法窗口.以图片的形式来说,三者的关系如下:
现在就让我们来看看CClassFactory类的声明:
IUnknown标准接口:
QueryInterface:该函数用来查看对象支持哪种方法,这也是COM接口最先调用的函数.
AddRef:增加一次对象调用计数.
Release:减少一次对象调用计数.
IClassFactory特有的接口:
CreateInstance:系统调用该函数去创建另一个所需的实例.本文的例子中,这个函数体内创建了一个CInputMethod类的对象.
LockServer:用来标识该DLL是否被卸载.本文中,只有检测到m_plDllCnt变量为0值,也就是说该DLL已经没有被引用,此时管理器才会卸载该DLL.
接下来就让我们再来看看CInputMethod类:
CInputMethod的IUnknown标准接口的作用和CClassFactory相同,在此就不赘述.
IInputMethod特有接口:
SetImData:应用程序可以通过该接口来获取输入法(IM)的信息.
GetImData:传递特定的信息给输入法.
RegisterCallback:SIP提供给输入法的回调函数接口.通过该回调函数接口,输入法可以给调用输入法的应用程序发送字符或键盘信息等等.这个是比较重要的一个函数,输入法就是通过该函数传递过来的接口函数来建立和外部的联系.
ReceiveSipInfo:SIP通过该接口传递消息给输入法.
GetInfo:SIP通过该接口来获取输入法的信息.
Hiding:隐藏输入法.
Showing:显示输入法.
Deselect:输入法即将从内存中卸载的时候将调用该接口.
Select:输入法装载到内存之前调用该接口.最明显的用户感受是在输入法管理器中选择某种输入法时,该接口即被调用.
UserOptionsDlg:控制面板通过该接口用来设置输入法的属性.
CClassFactory和CInputMethod的具体实现我们将在下一章中再详细解说,请容我们稍微休息一会.
//TITLE:
// 漫谈WinCE输入法的编写(一)
//AUTHOR:
// norains
//DATE:
// Saturday 10-February -2007
//Environment:
// EVC4.0 + Standard SDK
//========================================================================
WinCE的输入法编写,说复杂也不复杂,说简单亦不简单.说复杂嘛,是因为输入法是一个COM,需要实现某些接口,并且由于其特殊性,不能像普通应用程序一样进行调试;说简单嘛,只要把层次搞清,剩下的就和普通应用程序没什么太多的区别.
我觉得如果光谈概念,以我的文字功底,让人明白内中的机理,估计不是一件非常容易的事情.所以,我还是实际点,以我写过的一个输入法来做为例子.
因为这篇文章不是专门介绍COM接口技术的原理,我们的目的仅仅是让输入法给跑起来,因此我们只需要了解输入法用到了什么接口,以及我们应该如何定义该接口的功能即可.
为了代码层次分明,我这个例子采用了三个类:CClassFactory,CInputMethod和CIMWnd.前面两个类分别继承于IClassFactory和IInputMethod,是能让系统正常调用输入法所必须的com接口;而CIMWnd则是输入法的窗口,和普通的应用程序无异.
这三个类的关系是CClassFactory通过自身的CreateInstance()函数来创建一个CInputMethod类的对象,然后CInputMethod类中会调用CIMWnd类来显示一个输入法窗口.以图片的形式来说,三者的关系如下:
现在就让我们来看看CClassFactory类的声明:
class CClassFactory : public IClassFactory
{
public:
CClassFactory(long *plDllCnt,HINSTANCE hInst);
virtual ~CClassFactory();
//IUnknown methods
STDMETHODIMP QueryInterface (THIS_ REFIID riid, LPVOID *ppv);
STDMETHODIMP_(ULONG) AddRef (THIS);
STDMETHODIMP_(ULONG) Release (THIS);
//IClassFactory methods
STDMETHODIMP CreateInstance (LPUNKNOWN pUnkOuter, REFIID riid,LPVOID *ppv);
STDMETHODIMP LockServer (BOOL fLock);
private:
long *m_plDllCnt;//point to the Global DLL reference count
long m_lRef;
HINSTANCE m_hInst;
};
{
public:
CClassFactory(long *plDllCnt,HINSTANCE hInst);
virtual ~CClassFactory();
//IUnknown methods
STDMETHODIMP QueryInterface (THIS_ REFIID riid, LPVOID *ppv);
STDMETHODIMP_(ULONG) AddRef (THIS);
STDMETHODIMP_(ULONG) Release (THIS);
//IClassFactory methods
STDMETHODIMP CreateInstance (LPUNKNOWN pUnkOuter, REFIID riid,LPVOID *ppv);
STDMETHODIMP LockServer (BOOL fLock);
private:
long *m_plDllCnt;//point to the Global DLL reference count
long m_lRef;
HINSTANCE m_hInst;
};
IUnknown标准接口:
QueryInterface:该函数用来查看对象支持哪种方法,这也是COM接口最先调用的函数.
AddRef:增加一次对象调用计数.
Release:减少一次对象调用计数.
IClassFactory特有的接口:
CreateInstance:系统调用该函数去创建另一个所需的实例.本文的例子中,这个函数体内创建了一个CInputMethod类的对象.
LockServer:用来标识该DLL是否被卸载.本文中,只有检测到m_plDllCnt变量为0值,也就是说该DLL已经没有被引用,此时管理器才会卸载该DLL.
接下来就让我们再来看看CInputMethod类:
class CInputMethod : public IInputMethod
{
public:
//IUnknown methods
STDMETHODIMP_(ULONG) Release(THIS);
STDMETHODIMP_(ULONG) AddRef(THIS);
STDMETHODIMP QueryInterface(THIS_ REFIID riid, LPVOID *ppv);
//IInputMethod
HRESULT STDMETHODCALLTYPE SetImData (DWORD dwSize, void *pvImData);
HRESULT STDMETHODCALLTYPE GetImData (DWORD dwSize, void *pvImData);
HRESULT STDMETHODCALLTYPE RegisterCallback(IIMCallback *pIMCallback);
HRESULT STDMETHODCALLTYPE ReceiveSipInfo(SIPINFO *psi);
HRESULT STDMETHODCALLTYPE GetInfo(IMINFO *pimi);
HRESULT STDMETHODCALLTYPE Hiding();
HRESULT STDMETHODCALLTYPE Showing();
HRESULT STDMETHODCALLTYPE Deselect();
HRESULT STDMETHODCALLTYPE Select(HWND hWndSip);
HRESULT STDMETHODCALLTYPE UserOptionsDlg (HWND hwndParent);
CInputMethod(long *plDllCnt,HINSTANCE hInst);
virtual ~CInputMethod();
protected:
CIMWnd *m_pIMWnd; //The input method window pointer
HINSTANCE m_hInst; //The dll instance
long *m_plDllCnt;//point to the Global DLL reference count
long m_lRef;
};
{
public:
//IUnknown methods
STDMETHODIMP_(ULONG) Release(THIS);
STDMETHODIMP_(ULONG) AddRef(THIS);
STDMETHODIMP QueryInterface(THIS_ REFIID riid, LPVOID *ppv);
//IInputMethod
HRESULT STDMETHODCALLTYPE SetImData (DWORD dwSize, void *pvImData);
HRESULT STDMETHODCALLTYPE GetImData (DWORD dwSize, void *pvImData);
HRESULT STDMETHODCALLTYPE RegisterCallback(IIMCallback *pIMCallback);
HRESULT STDMETHODCALLTYPE ReceiveSipInfo(SIPINFO *psi);
HRESULT STDMETHODCALLTYPE GetInfo(IMINFO *pimi);
HRESULT STDMETHODCALLTYPE Hiding();
HRESULT STDMETHODCALLTYPE Showing();
HRESULT STDMETHODCALLTYPE Deselect();
HRESULT STDMETHODCALLTYPE Select(HWND hWndSip);
HRESULT STDMETHODCALLTYPE UserOptionsDlg (HWND hwndParent);
CInputMethod(long *plDllCnt,HINSTANCE hInst);
virtual ~CInputMethod();
protected:
CIMWnd *m_pIMWnd; //The input method window pointer
HINSTANCE m_hInst; //The dll instance
long *m_plDllCnt;//point to the Global DLL reference count
long m_lRef;
};
CInputMethod的IUnknown标准接口的作用和CClassFactory相同,在此就不赘述.
IInputMethod特有接口:
SetImData:应用程序可以通过该接口来获取输入法(IM)的信息.
GetImData:传递特定的信息给输入法.
RegisterCallback:SIP提供给输入法的回调函数接口.通过该回调函数接口,输入法可以给调用输入法的应用程序发送字符或键盘信息等等.这个是比较重要的一个函数,输入法就是通过该函数传递过来的接口函数来建立和外部的联系.
ReceiveSipInfo:SIP通过该接口传递消息给输入法.
GetInfo:SIP通过该接口来获取输入法的信息.
Hiding:隐藏输入法.
Showing:显示输入法.
Deselect:输入法即将从内存中卸载的时候将调用该接口.
Select:输入法装载到内存之前调用该接口.最明显的用户感受是在输入法管理器中选择某种输入法时,该接口即被调用.
UserOptionsDlg:控制面板通过该接口用来设置输入法的属性.
CClassFactory和CInputMethod的具体实现我们将在下一章中再详细解说,请容我们稍微休息一会.