//========================================================================
//TITLE:
// 漫谈WinCE输入法的编写(五)--以DLL替代CIMWnd
//AUTHOR:
// norains
//DATE:
// Friday 12-October-2007
//Environment:
// EVC4.0 + Windows CE 5.0 Standard SDK
//========================================================================
之前的一系列文章(恩,好久以前的文章),輸入法的功能實現都是在CIMWnd中,而本文则是以外部的DLL为替代CIMWnd.以DLL替代CIMWnd类有什么好处呢?恩,这个~其实我也说不上,不过嘛,知道一种新方式,有多一种选择,毕竟不是一件坏事,不是么?何况,这个方法,以我个人观点,还更为灵活些.更换输入法部件时,只需要更新dll即可.
我们首先来回顾一下之前一系列文章中定义的CIMWnd接口功能:
class CIMWnd
{
public:
//获取窗口句柄
HWND GetWindow();;
//显示输入法的设置窗口
void ShowUserOptionsDlg(HWND hWndParent,HINSTANCE hInst = NULL);
//显示输入法界面
void ShowWindow(BOOL bShow);
//销毁输入法界面
void DestroyWindow();
//初始化窗口,hWndSip是输入法管理器的句柄
BOOL Initialize(HINSTANCE hInst, HWND hWndSip);
...
}
也就是说,为了和CInputMethod(漫谈WinCE输入法的编写(二))衔接起来,我们在dll中也必须实现这五个功能接口.我们新建一个名为DllWnd工程的DLL工程,并且为了避免和系统的函数重复从而导致出现获取函数入口失败,我们将这五个功能接口分别添上IM前缀:
//The interface
//获取窗口句柄
HWND IMGetWindow();
//显示输入法的设置窗口
void IMShowUserOptionsDlg(HWND hWndParent,HINSTANCE hInst);
//显示输入法界面
void IMShowWindow(BOOL bShow);
//销毁输入法界面
void IMDestroyWindow();
//初始化窗口
BOOL IMInitialize(HINSTANCE hInstSip, HWND hWndSip);
下面是一个完整的DllWnd代码,其功能是实现一个输入法窗口的创建,并且当点击该窗口时会输出一串测试字符.
#include " sip.h "
#include " resource.h "
// ===================================================================
#define MYMSG_REGCALLBACK(WM_USER+100)
// Description:
// Themessageisusingforregisteringtheinputmethodcallbackfunction
//
// Parameters:
// pImCallback=(IIMCallback*)wParam
// 0=lParam
// =====================================================================
// ====================================================================
// Macrodefine
#define WINDOW_CLASSTEXT("IMWND_Class")
#define WINDOW_TITLETEXT("IMWND_Title")
// Thetaskbarheight
#define TASKBAR_HEIGHT_AUTOHIDE5
#define TASKBAR_HEIGHT26
#define IMG_IMWND_WIDTH370
#define IMG_IMWND_HEIGHT206
#define SCREEN_WIDTH800
#define SCREEN_HEIGHT480
// ==================================================================
// ForwardDeclare
// ------------------------------------------------------------------------
// Theinterface
HWNDIMGetWindow();
void IMShowUserOptionsDlg(HWNDhWndParent,HINSTANCEhInst);
void IMShowWindow(BOOLbShow);
void IMDestroyWindow();
BOOLIMInitialize(HINSTANCEhInstSip,HWNDhWndSip);
// ------------------------------------------------------------------------
void OnDestroy(HWNDhWnd,UINTwMsg,WPARAMwParam,LPARAMlParam);
void OnPaint(HWNDhWnd,UINTwMsg,WPARAMwParam,LPARAMlParam);
void OnRegCallback(HWNDhWnd,UINTwMsg,WPARAMwParam,LPARAMlParam);
void OnLButtonUp(HWNDhWnd,UINTwMsg,WPARAMwParam,LPARAMlParam);
LRESULTWndProc(HWNDhWnd,UINTwMsg,WPARAMwParam,LPARAMlParam);
// ---------------------------------------------------------------------
// Theglobalmember
HWNDg_hWnd = NULL; // 输入法功能窗口
HWNDg_hWndSip = NULL; // IM父窗口
HMODULEg_hInst = NULL; // dll的实例句柄
HINSTANCEg_hInstSip = NULL; // sipdll的实例句柄
IIMCallback * g_pIMCallback; // 回调函数指针
// -------------------------------------------------------------------
// Description:
// TheDLLMAIN
//
// ------------------------------------------------------------------
BOOLAPIENTRYDllMain(HANDLEhModule,
DWORDul_reason_for_call,
LPVOIDlpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
g_hInst = (HMODULE)hModule;
break ;
}
}
return TRUE;
}
// -------------------------------------------------------------------
// Description:
// Getthewindowhandle
//
// ------------------------------------------------------------------
HWNDIMGetWindow()
{
return g_hWnd;
}
// -------------------------------------------------------------------
// Description:
// Showtheuseroptionsdialog
//
// ------------------------------------------------------------------
void IMShowUserOptionsDlg(HWNDhWndParent,HINSTANCEhInst)
{
MessageBox(NULL,TEXT( " 控制面板可以調出的輸入法設置 " ),TEXT( " 設置 " ),MB_OK);
}
// -------------------------------------------------------------------
// Description:
// Showthewindow
//
// ------------------------------------------------------------------
void IMShowWindow(BOOLbShow)
{
if (bShow == TRUE)
{
::ShowWindow(g_hWnd,SW_SHOW);
}
else
{
::ShowWindow(g_hWnd,SW_HIDE);
}
}
// -------------------------------------------------------------------
// Description:
// Destroythewindow
//
// ------------------------------------------------------------------
void IMDestroyWindow()
{
::DestroyWindow(g_hWnd);
}
// -------------------------------------------------------------------
// Description:
// Initializethewindow
//
// ------------------------------------------------------------------
BOOLIMInitialize(HINSTANCEhInstSip,HWNDhWndSip)
{
g_hInstSip = hInstSip;
g_hWndSip = hWndSip;
UnregisterClass(WINDOW_CLASS,g_hInst);
WNDCLASSwc = { 0 };
wc.style = CS_VREDRAW | CS_HREDRAW;;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0 ;
wc.cbWndExtra = 0 ;
wc.hInstance = g_hInst;
wc.hIcon = NULL;
wc.hCursor = NULL;
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = WINDOW_CLASS;
if (RegisterClass( & wc) == 0 )
{
return FALSE;
}
// Setthewindowareatosuitwiththeimage
RECTrcClientWnd = { 0 };
GetClientRect(hWndSip, & rcClientWnd);
RECTrcSipWnd = { 0 };
GetWindowRect(hWndSip, & rcSipWnd);
// Itmaybetheframefortheparentwindow,sowemustholdit.
int iWidth = (rcSipWnd.right - rcSipWnd.left) - (rcClientWnd.right - rcClientWnd.left) + IMG_IMWND_WIDTH;
int iHeight = (rcSipWnd.bottom - rcSipWnd.top) - (rcClientWnd.bottom - rcClientWnd.top) + IMG_IMWND_HEIGHT;
rcSipWnd.left = SCREEN_WIDTH - iWidth;
rcSipWnd.top = SCREEN_HEIGHT - iHeight - TASKBAR_HEIGHT;
SetWindowPos(hWndSip,hWndSip,rcSipWnd.left,rcSipWnd.top,iWidth,iHeight,NULL);
// CreateSIPwindow.
g_hWnd = CreateWindowEx( 0 ,
WINDOW_CLASS,
WINDOW_TITLE,
WS_CHILD | WS_BORDER,
rcClientWnd.left,
rcClientWnd.top,
IMG_IMWND_WIDTH, // rcWnd.right-rcWnd.left,
IMG_IMWND_HEIGHT, // rcWnd.bottom-rcWnd.top,
hWndSip,
NULL,
g_hInst,
NULL
);
if (IsWindow(g_hWnd) == FALSE)
{
return FALSE;
}
return TRUE;
}
// -------------------------------------------------------------------
// Description:
// Thewindowprocess
//
// ------------------------------------------------------------------
LRESULTWndProc(HWNDhWnd,UINTwMsg,WPARAMwParam,LPARAMlParam)
{
switch (wMsg)
{
case WM_PAINT:
OnPaint(hWnd,wMsg,wParam,lParam);
return 0 ;
case MYMSG_REGCALLBACK:
OnRegCallback(hWnd,wMsg,wParam,lParam);
return 0 ;
case WM_ERASEBKGND:
// Donothinginordernottoflashthewindow
return 0 ;
case WM_LBUTTONUP:
OnLButtonUp(hWnd,wMsg,wParam,lParam);
return 0 ;
}
return DefWindowProc(hWnd,wMsg,wParam,lParam);
}
// -------------------------------------------------------------------
// Description:
// OnmessageWM_PAINT
//
// ------------------------------------------------------------------
void OnPaint(HWNDhWnd,UINTwMsg,WPARAMwParam,LPARAMlParam)
{
PAINTSTRUCTps;
HDChdc = BeginPaint(hWnd, & ps);
// CreateaDCthatmatchesthedevice
HBITMAPhBitmap = CreateCompatibleBitmap(hdc,IMG_IMWND_WIDTH,IMG_IMWND_HEIGHT);
HDChdcMem = CreateCompatibleDC(hdc);
// Selectthebitmapintotothecompatibledevicecontext
HGDIOBJhOldSel = SelectObject(hdcMem,hBitmap);
// CreateaDCthatmatchesthedevice
HDChdcBmp = CreateCompatibleDC(hdc);
// Loadthebitmap
HANDLEhBmp = LoadImage(g_hInst,MAKEINTRESOURCE(IDB_PANNEL),IMAGE_BITMAP, 0 , 0 , 0 );
// Selectthebitmapintotothecompatibledevicecontext
HGDIOBJhOldBmpSel = SelectObject(hdcBmp,hBmp);
// CopythebitmapimagetothememoryDC.
BitBlt(hdcMem, 0 , 0 ,IMG_IMWND_WIDTH,IMG_IMWND_HEIGHT,hdcBmp, 0 , 0 ,SRCCOPY);
// Drawtothescreen
BitBlt(hdc, 0 , 0 ,IMG_IMWND_WIDTH,IMG_IMWND_HEIGHT,hdcMem, 0 , 0 ,SRCCOPY);
// RestoreoriginalbitmapselectionanddestroythememoryDC
SelectObject(hdcBmp,hOldBmpSel);
SelectObject(hdcMem,hOldSel);
DeleteObject(hBitmap);
DeleteDC(hdcBmp);
DeleteDC(hdcMem);
EndPaint(hWnd, & ps);
}
// -------------------------------------------------------------------
// Description:
// OnmessageMYMSG_REGCALLBACK
//
// ------------------------------------------------------------------
void OnRegCallback(HWNDhWnd,UINTwMsg,WPARAMwParam,LPARAMlParam)
{
g_pIMCallback = (IIMCallback * )wParam;
}
// -------------------------------------------------------------------
// Description:
// OnmessageWM_LBUTTONUP
//
// ------------------------------------------------------------------
void OnLButtonUp(HWNDhWnd,UINTwMsg,WPARAMwParam,LPARAMlParam)
{
if (g_pIMCallback != NULL)
{
g_pIMCallback -> SendString(TEXT( " 輸入法測試程序 " ), 8 );
}
}
当然,上部接口CInputMethod也需要更改.为了方便和CIMWnd契合,我们设置两个宏定义:IMWND_FROM_CODE和IMWND_FROM_DLL.
IMWND_FROM_CODE定义时,我们采用CIMWnd作为功能实现窗口;而IMWND_FROM_DLL则是采用上文所说的dllwnd.dll.
/ //
// InputMethod.h:interfacefortheCInputMethodclass.
//
/ /
#ifndefIMPUTMETHOD_H
#define IMPUTMETHOD_H
#include " stdafx.h "
#include " sip.h "
#include " IMWnd.h "
// -----------------------------------------------------------------
class CInputMethod: public IInputMethod
{
public :
// IUnknownmethods
STDMETHODIMP_(ULONG)Release(THIS);
STDMETHODIMP_(ULONG)AddRef(THIS);
STDMETHODIMPQueryInterface(THIS_REFIIDriid,LPVOID * ppv);
// IInputMethod
HRESULTSTDMETHODCALLTYPESetImData(DWORDdwSize, void * pvImData);
HRESULTSTDMETHODCALLTYPEGetImData(DWORDdwSize, void * pvImData);
HRESULTSTDMETHODCALLTYPERegisterCallback(IIMCallback * pIMCallback);
HRESULTSTDMETHODCALLTYPEReceiveSipInfo(SIPINFO * psi);
HRESULTSTDMETHODCALLTYPEGetInfo(IMINFO * pimi);
HRESULTSTDMETHODCALLTYPEHiding();
HRESULTSTDMETHODCALLTYPEShowing();
HRESULTSTDMETHODCALLTYPEDeselect();
HRESULTSTDMETHODCALLTYPESelect(HWNDhWndSip);
HRESULTSTDMETHODCALLTYPEUserOptionsDlg(HWNDhwndParent);
CInputMethod( long * plDllCnt,HINSTANCEhInst);
virtual ~ CInputMethod();
protected :
HINSTANCEm_hInst; // Thedllinstance
long * m_plDllCnt; // pointtotheGlobalDLLreferencecount
long m_lRef;
#ifdefIMWND_FROM_CODE
CIMWnd * m_pIMWnd; // Theinputmethodwindowpointer
#define GETINSTANCE()(m_pIMWnd=CIMWnd::GetInstance())
#define GETWINDOW()(m_pIMWnd->GetWindow())
#define SHOWUSEROPTIONSDLG(x,y)(m_pIMWnd->ShowUserOptionsDlg(x,y))
#define SHOWWINDOW(x)(m_pIMWnd->ShowWindow(x))
#define DESTROYWINDOW()(m_pIMWnd->DestroyWindow())
#define INITIALIZE(x,y)(m_pIMWnd->Initialize(x,y))
#endif // #ifdefIMWND_FROM_CODE
#ifdefIMWND_FROM_DLL
BOOLm_bLoadLib;
// Idon'tneedgetinstancefromthedll.
#define GETINSTANCE()
typedefHWND(WINAPI * DLL_GETWINDOW)( void );
typedef void (WINAPI * DLL_SHOWUSEROPTIONSDLG)(HWND,HINSTANCE = NULL);
typedef void (WINAPI * DLL_SHOWWINDOW)(BOOL);
typedef void (WINAPI * DLL_DESTROYWINDOW)( void );
typedefBOOL(WINAPI * DLL_INITIALIZE)(HINSTANCE,HWND);
DLL_GETWINDOWGETWINDOW;
DLL_SHOWUSEROPTIONSDLGSHOWUSEROPTIONSDLG;
DLL_SHOWWINDOWSHOWWINDOW;
DLL_DESTROYWINDOWDESTROYWINDOW;
DLL_INITIALIZEINITIALIZE;
#endif // #ifdefIMWND_FROM_DLL
};
// --------------------------------------------------------------------------------
#endif // IMPUTMETHOD_H
/ /
// InputMethod.cpp:implementationoftheCInputMethodclass.
//
/ /
#include " InputMethod.h "
// --------------------------------------------------------------------
// Macrodefine
#define SIP_WND_WIDTH200
#define SIP_WND_HEIGHT180
#define IMWND_DLL_PATHTEXT("window/dllwnd.dll")
// ----------------------------------------------------------------------
/ /
// Construction/Destruction
/ /
CInputMethod::CInputMethod( long * plDllCnt,HINSTANCEhInst)
{
GETINSTANCE();
m_hInst = hInst;
m_plDllCnt = plDllCnt;
( * m_plDllCnt) ++ ;
m_lRef = 1 ; // Setrefcountto1oncreate.
#ifdefIMWND_FROM_DLL
GETWINDOW = NULL;
SHOWUSEROPTIONSDLG = NULL;
SHOWWINDOW = NULL;
DESTROYWINDOW = NULL;
INITIALIZE = NULL;
HINSTANCEhInstDll;
hInstDll = LoadLibrary(IMWND_DLL_PATH);
if (hInstDll != NULL)
{
GETWINDOW = (DLL_GETWINDOW)GetProcAddress(hInstDll,TEXT( " IMGetWindow " ));
SHOWUSEROPTIONSDLG = (DLL_SHOWUSEROPTIONSDLG)GetProcAddress(hInstDll,TEXT( " IMShowUserOptionsDlg " ));
SHOWWINDOW = (DLL_SHOWWINDOW)GetProcAddress(hInstDll,TEXT( " IMShowWindow " ));
DESTROYWINDOW = (DLL_DESTROYWINDOW)GetProcAddress(hInstDll,TEXT( " IMDestroyWindow " ));
INITIALIZE = (DLL_INITIALIZE)GetProcAddress(hInstDll,TEXT( " IMInitialize " ));
}
if (GETWINDOW == NULL ||
SHOWUSEROPTIONSDLG == NULL ||
SHOWWINDOW == NULL ||
DESTROYWINDOW == NULL ||
INITIALIZE == NULL)
{
m_bLoadLib = FALSE;
}
else
{
m_bLoadLib = TRUE;
}
#endif
}
CInputMethod:: ~ CInputMethod()
{
( * m_plDllCnt) -- ;
}
// -------------------------------------------------------------------------------------------
// Description:
// Thismethodisimplementedtocreatethewindowsandimagelistfortheinputmethod(IM).
// ----------------------------------------------------------------------------------------------
HRESULTSTDMETHODCALLTYPECInputMethod::Select(HWNDhWndSip)
{
if (INITIALIZE(m_hInst,hWndSip) == FALSE)
{
return E_FAIL;
}
SHOWWINDOW(TRUE);
return S_OK;
}
// -------------------------------------------------------------------------------------------
// Description:
// Thismethodisimplementedtoselecttheinputmethod(IM)outofthesoftware-based
// inputpanelwindowandtodestroytheIMwindows.
// ----------------------------------------------------------------------------------------------
HRESULTSTDMETHODCALLTYPECInputMethod::Deselect()
{
DESTROYWINDOW();
return S_OK;
}
// -------------------------------------------------------------------------------------------
// Description:
// Thismethodisimplementedtoperformanyinitializationbeforethesoftware-based
// inputpanelwindowisdisplayed
// ----------------------------------------------------------------------------------------------
HRESULTSTDMETHODCALLTYPECInputMethod::Showing()
{
SHOWWINDOW(TRUE);
return S_OK;
}
// -------------------------------------------------------------------------------------------
// Description:
// Thismethodisimplementedtoperformanysavingroutinesbeforethesoftware-based
// inputpanelishidden.
// ----------------------------------------------------------------------------------------------
HRESULTSTDMETHODCALLTYPECInputMethod::Hiding()
{
SHOWWINDOW(FALSE);
return S_OK;
}
// -------------------------------------------------------------------------------------------
// Description:
// Thismethodisimplementedtoreturninformationaboutthecurrentinput
// method(IM)totheoperatingsystem.
// ----------------------------------------------------------------------------------------------
HRESULTSTDMETHODCALLTYPECInputMethod::GetInfo(IMINFO * pimi)
{
pimi -> cbSize = sizeof (IMINFO);
pimi -> hImageNarrow = 0 ;
pimi -> hImageWide = 0 ;
pimi -> iNarrow = 0 ;
pimi -> iWide = 0 ;
pimi -> fdwFlags = SIPF_DOCKED;
pimi -> rcSipRect.left = 0 ;
pimi -> rcSipRect.top = 0 ;
pimi -> rcSipRect.right = SIP_WND_WIDTH;
pimi -> rcSipRect.bottom = SIP_WND_HEIGHT;
return S_OK;
}
// -------------------------------------------------------------------------------------------
// Description:
// ThismethodisimplementedfortheIMtoreceiveinformationaboutthesize,
// placement,anddockedstatusofthesoftware-basedinputpanel.
// ----------------------------------------------------------------------------------------------
HRESULTSTDMETHODCALLTYPECInputMethod::ReceiveSipInfo(SIPINFO * psi)
{
return S_OK;
}
// -------------------------------------------------------------------------------------------
// Description:
// ThismethodisimplementedtoreceiveapointertoanIIMCallbackinterface.
// Aninputmethod(IM)usestheIIMCallbackinterfacetosendkeystrokestoapplications
// andtochangetheiconsontheInputPanelbutton.
// ----------------------------------------------------------------------------------------------
HRESULTSTDMETHODCALLTYPECInputMethod::RegisterCallback(IIMCallback * pIMCallback)
{
// TelltheIMwindowtoregisterthecallback
HWNDhWnd = GETWINDOW();
SendMessage(hWnd,MYMSG_REGCALLBACK,(WPARAM)pIMCallback, 0 );
return S_OK;
}
// -------------------------------------------------------------------------------------------
// Description:
// Thismethodisimplementedtosenddatafromthecurrent
// inputmethod(IM)tothecurrentapplication.
// ----------------------------------------------------------------------------------------------
HRESULTSTDMETHODCALLTYPECInputMethod::GetImData(DWORDdwSize, void * pvImData)
{
return S_OK;
}
// -------------------------------------------------------------------------------------------
// Description:
// Thismethodisimplementedtorespondtoanapplication'srequestto
// setinputmethod(IM)-specificdatawithintheIM.
// ----------------------------------------------------------------------------------------------
HRESULTSTDMETHODCALLTYPECInputMethod::SetImData(DWORDdwSize, void * pvImData)
{
return S_OK;
}
// ---------------------------------------------------------------------
// Description:
// Incrementobjectrefcount
// ----------------------------------------------------------------------
STDMETHODIMPCInputMethod::QueryInterface(REFIIDriid,LPVOID * ppv)
{
#ifdefIMWND_FROM_DLL
if (m_bLoadLib == FALSE)
{
return E_NOINTERFACE;
}
#endif // #ifdefIMWND_FROM_DLL
// IfcallerwantsourIUnknownorIID_IInputMethod2object,
// returnapointertotheobject.
if (IsEqualIID(riid,IID_IUnknown) || IsEqualIID(riid,IID_IInputMethod) || IsEqualIID(riid,IID_IInputMethod2))
{
// Returnptrtoobject.
* ppv = (IInputMethod * ) this ;
AddRef(); // Incrementreftopreventdeleteonreturn.
return NOERROR;
}
* ppv = NULL;
return (E_NOINTERFACE);
}
// ---------------------------------------------------------------------
// Description:
// Incrementobjectrefcount
// ----------------------------------------------------------------------
STDMETHODIMP_(ULONG)CInputMethod::AddRef()
{
ULONGcnt;
cnt = (ULONG)InterlockedIncrement( & m_lRef);
return cnt;
}
// ---------------------------------------------------------------------
// Description:
// Incrementobjectrefcount
// ----------------------------------------------------------------------
STDMETHODIMP_(ULONG)CInputMethod::Release()
{
ULONGcnt;
cnt = (ULONG)InterlockedDecrement( & m_lRef);
if (cnt == 0 )
{
delete this ;
return 0 ;
}
return cnt;
}
// ---------------------------------------------------------------------
// Description:
// TheSIPControlPanelappletisaskingforaconfigurationdialogboxtobedisplayed.
// ----------------------------------------------------------------------
HRESULTSTDMETHODCALLTYPECInputMethod::UserOptionsDlg(HWNDhwndParent)
{
SHOWUSEROPTIONSDLG(hwndParent,m_hInst);
return S_OK;
}
OK,编译完毕,大功告成!
//TITLE:
// 漫谈WinCE输入法的编写(五)--以DLL替代CIMWnd
//AUTHOR:
// norains
//DATE:
// Friday 12-October-2007
//Environment:
// EVC4.0 + Windows CE 5.0 Standard SDK
//========================================================================
之前的一系列文章(恩,好久以前的文章),輸入法的功能實現都是在CIMWnd中,而本文则是以外部的DLL为替代CIMWnd.以DLL替代CIMWnd类有什么好处呢?恩,这个~其实我也说不上,不过嘛,知道一种新方式,有多一种选择,毕竟不是一件坏事,不是么?何况,这个方法,以我个人观点,还更为灵活些.更换输入法部件时,只需要更新dll即可.
我们首先来回顾一下之前一系列文章中定义的CIMWnd接口功能:
class CIMWnd
{
public:
//获取窗口句柄
HWND GetWindow();;
//显示输入法的设置窗口
void ShowUserOptionsDlg(HWND hWndParent,HINSTANCE hInst = NULL);
//显示输入法界面
void ShowWindow(BOOL bShow);
//销毁输入法界面
void DestroyWindow();
//初始化窗口,hWndSip是输入法管理器的句柄
BOOL Initialize(HINSTANCE hInst, HWND hWndSip);
...
}
也就是说,为了和CInputMethod(漫谈WinCE输入法的编写(二))衔接起来,我们在dll中也必须实现这五个功能接口.我们新建一个名为DllWnd工程的DLL工程,并且为了避免和系统的函数重复从而导致出现获取函数入口失败,我们将这五个功能接口分别添上IM前缀:
//The interface
//获取窗口句柄
HWND IMGetWindow();
//显示输入法的设置窗口
void IMShowUserOptionsDlg(HWND hWndParent,HINSTANCE hInst);
//显示输入法界面
void IMShowWindow(BOOL bShow);
//销毁输入法界面
void IMDestroyWindow();
//初始化窗口
BOOL IMInitialize(HINSTANCE hInstSip, HWND hWndSip);
下面是一个完整的DllWnd代码,其功能是实现一个输入法窗口的创建,并且当点击该窗口时会输出一串测试字符.
#include " sip.h "
#include " resource.h "
// ===================================================================
#define MYMSG_REGCALLBACK(WM_USER+100)
// Description:
// Themessageisusingforregisteringtheinputmethodcallbackfunction
//
// Parameters:
// pImCallback=(IIMCallback*)wParam
// 0=lParam
// =====================================================================
// ====================================================================
// Macrodefine
#define WINDOW_CLASSTEXT("IMWND_Class")
#define WINDOW_TITLETEXT("IMWND_Title")
// Thetaskbarheight
#define TASKBAR_HEIGHT_AUTOHIDE5
#define TASKBAR_HEIGHT26
#define IMG_IMWND_WIDTH370
#define IMG_IMWND_HEIGHT206
#define SCREEN_WIDTH800
#define SCREEN_HEIGHT480
// ==================================================================
// ForwardDeclare
// ------------------------------------------------------------------------
// Theinterface
HWNDIMGetWindow();
void IMShowUserOptionsDlg(HWNDhWndParent,HINSTANCEhInst);
void IMShowWindow(BOOLbShow);
void IMDestroyWindow();
BOOLIMInitialize(HINSTANCEhInstSip,HWNDhWndSip);
// ------------------------------------------------------------------------
void OnDestroy(HWNDhWnd,UINTwMsg,WPARAMwParam,LPARAMlParam);
void OnPaint(HWNDhWnd,UINTwMsg,WPARAMwParam,LPARAMlParam);
void OnRegCallback(HWNDhWnd,UINTwMsg,WPARAMwParam,LPARAMlParam);
void OnLButtonUp(HWNDhWnd,UINTwMsg,WPARAMwParam,LPARAMlParam);
LRESULTWndProc(HWNDhWnd,UINTwMsg,WPARAMwParam,LPARAMlParam);
// ---------------------------------------------------------------------
// Theglobalmember
HWNDg_hWnd = NULL; // 输入法功能窗口
HWNDg_hWndSip = NULL; // IM父窗口
HMODULEg_hInst = NULL; // dll的实例句柄
HINSTANCEg_hInstSip = NULL; // sipdll的实例句柄
IIMCallback * g_pIMCallback; // 回调函数指针
// -------------------------------------------------------------------
// Description:
// TheDLLMAIN
//
// ------------------------------------------------------------------
BOOLAPIENTRYDllMain(HANDLEhModule,
DWORDul_reason_for_call,
LPVOIDlpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
g_hInst = (HMODULE)hModule;
break ;
}
}
return TRUE;
}
// -------------------------------------------------------------------
// Description:
// Getthewindowhandle
//
// ------------------------------------------------------------------
HWNDIMGetWindow()
{
return g_hWnd;
}
// -------------------------------------------------------------------
// Description:
// Showtheuseroptionsdialog
//
// ------------------------------------------------------------------
void IMShowUserOptionsDlg(HWNDhWndParent,HINSTANCEhInst)
{
MessageBox(NULL,TEXT( " 控制面板可以調出的輸入法設置 " ),TEXT( " 設置 " ),MB_OK);
}
// -------------------------------------------------------------------
// Description:
// Showthewindow
//
// ------------------------------------------------------------------
void IMShowWindow(BOOLbShow)
{
if (bShow == TRUE)
{
::ShowWindow(g_hWnd,SW_SHOW);
}
else
{
::ShowWindow(g_hWnd,SW_HIDE);
}
}
// -------------------------------------------------------------------
// Description:
// Destroythewindow
//
// ------------------------------------------------------------------
void IMDestroyWindow()
{
::DestroyWindow(g_hWnd);
}
// -------------------------------------------------------------------
// Description:
// Initializethewindow
//
// ------------------------------------------------------------------
BOOLIMInitialize(HINSTANCEhInstSip,HWNDhWndSip)
{
g_hInstSip = hInstSip;
g_hWndSip = hWndSip;
UnregisterClass(WINDOW_CLASS,g_hInst);
WNDCLASSwc = { 0 };
wc.style = CS_VREDRAW | CS_HREDRAW;;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0 ;
wc.cbWndExtra = 0 ;
wc.hInstance = g_hInst;
wc.hIcon = NULL;
wc.hCursor = NULL;
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = WINDOW_CLASS;
if (RegisterClass( & wc) == 0 )
{
return FALSE;
}
// Setthewindowareatosuitwiththeimage
RECTrcClientWnd = { 0 };
GetClientRect(hWndSip, & rcClientWnd);
RECTrcSipWnd = { 0 };
GetWindowRect(hWndSip, & rcSipWnd);
// Itmaybetheframefortheparentwindow,sowemustholdit.
int iWidth = (rcSipWnd.right - rcSipWnd.left) - (rcClientWnd.right - rcClientWnd.left) + IMG_IMWND_WIDTH;
int iHeight = (rcSipWnd.bottom - rcSipWnd.top) - (rcClientWnd.bottom - rcClientWnd.top) + IMG_IMWND_HEIGHT;
rcSipWnd.left = SCREEN_WIDTH - iWidth;
rcSipWnd.top = SCREEN_HEIGHT - iHeight - TASKBAR_HEIGHT;
SetWindowPos(hWndSip,hWndSip,rcSipWnd.left,rcSipWnd.top,iWidth,iHeight,NULL);
// CreateSIPwindow.
g_hWnd = CreateWindowEx( 0 ,
WINDOW_CLASS,
WINDOW_TITLE,
WS_CHILD | WS_BORDER,
rcClientWnd.left,
rcClientWnd.top,
IMG_IMWND_WIDTH, // rcWnd.right-rcWnd.left,
IMG_IMWND_HEIGHT, // rcWnd.bottom-rcWnd.top,
hWndSip,
NULL,
g_hInst,
NULL
);
if (IsWindow(g_hWnd) == FALSE)
{
return FALSE;
}
return TRUE;
}
// -------------------------------------------------------------------
// Description:
// Thewindowprocess
//
// ------------------------------------------------------------------
LRESULTWndProc(HWNDhWnd,UINTwMsg,WPARAMwParam,LPARAMlParam)
{
switch (wMsg)
{
case WM_PAINT:
OnPaint(hWnd,wMsg,wParam,lParam);
return 0 ;
case MYMSG_REGCALLBACK:
OnRegCallback(hWnd,wMsg,wParam,lParam);
return 0 ;
case WM_ERASEBKGND:
// Donothinginordernottoflashthewindow
return 0 ;
case WM_LBUTTONUP:
OnLButtonUp(hWnd,wMsg,wParam,lParam);
return 0 ;
}
return DefWindowProc(hWnd,wMsg,wParam,lParam);
}
// -------------------------------------------------------------------
// Description:
// OnmessageWM_PAINT
//
// ------------------------------------------------------------------
void OnPaint(HWNDhWnd,UINTwMsg,WPARAMwParam,LPARAMlParam)
{
PAINTSTRUCTps;
HDChdc = BeginPaint(hWnd, & ps);
// CreateaDCthatmatchesthedevice
HBITMAPhBitmap = CreateCompatibleBitmap(hdc,IMG_IMWND_WIDTH,IMG_IMWND_HEIGHT);
HDChdcMem = CreateCompatibleDC(hdc);
// Selectthebitmapintotothecompatibledevicecontext
HGDIOBJhOldSel = SelectObject(hdcMem,hBitmap);
// CreateaDCthatmatchesthedevice
HDChdcBmp = CreateCompatibleDC(hdc);
// Loadthebitmap
HANDLEhBmp = LoadImage(g_hInst,MAKEINTRESOURCE(IDB_PANNEL),IMAGE_BITMAP, 0 , 0 , 0 );
// Selectthebitmapintotothecompatibledevicecontext
HGDIOBJhOldBmpSel = SelectObject(hdcBmp,hBmp);
// CopythebitmapimagetothememoryDC.
BitBlt(hdcMem, 0 , 0 ,IMG_IMWND_WIDTH,IMG_IMWND_HEIGHT,hdcBmp, 0 , 0 ,SRCCOPY);
// Drawtothescreen
BitBlt(hdc, 0 , 0 ,IMG_IMWND_WIDTH,IMG_IMWND_HEIGHT,hdcMem, 0 , 0 ,SRCCOPY);
// RestoreoriginalbitmapselectionanddestroythememoryDC
SelectObject(hdcBmp,hOldBmpSel);
SelectObject(hdcMem,hOldSel);
DeleteObject(hBitmap);
DeleteDC(hdcBmp);
DeleteDC(hdcMem);
EndPaint(hWnd, & ps);
}
// -------------------------------------------------------------------
// Description:
// OnmessageMYMSG_REGCALLBACK
//
// ------------------------------------------------------------------
void OnRegCallback(HWNDhWnd,UINTwMsg,WPARAMwParam,LPARAMlParam)
{
g_pIMCallback = (IIMCallback * )wParam;
}
// -------------------------------------------------------------------
// Description:
// OnmessageWM_LBUTTONUP
//
// ------------------------------------------------------------------
void OnLButtonUp(HWNDhWnd,UINTwMsg,WPARAMwParam,LPARAMlParam)
{
if (g_pIMCallback != NULL)
{
g_pIMCallback -> SendString(TEXT( " 輸入法測試程序 " ), 8 );
}
}
当然,上部接口CInputMethod也需要更改.为了方便和CIMWnd契合,我们设置两个宏定义:IMWND_FROM_CODE和IMWND_FROM_DLL.
IMWND_FROM_CODE定义时,我们采用CIMWnd作为功能实现窗口;而IMWND_FROM_DLL则是采用上文所说的dllwnd.dll.
/ //
// InputMethod.h:interfacefortheCInputMethodclass.
//
/ /
#ifndefIMPUTMETHOD_H
#define IMPUTMETHOD_H
#include " stdafx.h "
#include " sip.h "
#include " IMWnd.h "
// -----------------------------------------------------------------
class CInputMethod: public IInputMethod
{
public :
// IUnknownmethods
STDMETHODIMP_(ULONG)Release(THIS);
STDMETHODIMP_(ULONG)AddRef(THIS);
STDMETHODIMPQueryInterface(THIS_REFIIDriid,LPVOID * ppv);
// IInputMethod
HRESULTSTDMETHODCALLTYPESetImData(DWORDdwSize, void * pvImData);
HRESULTSTDMETHODCALLTYPEGetImData(DWORDdwSize, void * pvImData);
HRESULTSTDMETHODCALLTYPERegisterCallback(IIMCallback * pIMCallback);
HRESULTSTDMETHODCALLTYPEReceiveSipInfo(SIPINFO * psi);
HRESULTSTDMETHODCALLTYPEGetInfo(IMINFO * pimi);
HRESULTSTDMETHODCALLTYPEHiding();
HRESULTSTDMETHODCALLTYPEShowing();
HRESULTSTDMETHODCALLTYPEDeselect();
HRESULTSTDMETHODCALLTYPESelect(HWNDhWndSip);
HRESULTSTDMETHODCALLTYPEUserOptionsDlg(HWNDhwndParent);
CInputMethod( long * plDllCnt,HINSTANCEhInst);
virtual ~ CInputMethod();
protected :
HINSTANCEm_hInst; // Thedllinstance
long * m_plDllCnt; // pointtotheGlobalDLLreferencecount
long m_lRef;
#ifdefIMWND_FROM_CODE
CIMWnd * m_pIMWnd; // Theinputmethodwindowpointer
#define GETINSTANCE()(m_pIMWnd=CIMWnd::GetInstance())
#define GETWINDOW()(m_pIMWnd->GetWindow())
#define SHOWUSEROPTIONSDLG(x,y)(m_pIMWnd->ShowUserOptionsDlg(x,y))
#define SHOWWINDOW(x)(m_pIMWnd->ShowWindow(x))
#define DESTROYWINDOW()(m_pIMWnd->DestroyWindow())
#define INITIALIZE(x,y)(m_pIMWnd->Initialize(x,y))
#endif // #ifdefIMWND_FROM_CODE
#ifdefIMWND_FROM_DLL
BOOLm_bLoadLib;
// Idon'tneedgetinstancefromthedll.
#define GETINSTANCE()
typedefHWND(WINAPI * DLL_GETWINDOW)( void );
typedef void (WINAPI * DLL_SHOWUSEROPTIONSDLG)(HWND,HINSTANCE = NULL);
typedef void (WINAPI * DLL_SHOWWINDOW)(BOOL);
typedef void (WINAPI * DLL_DESTROYWINDOW)( void );
typedefBOOL(WINAPI * DLL_INITIALIZE)(HINSTANCE,HWND);
DLL_GETWINDOWGETWINDOW;
DLL_SHOWUSEROPTIONSDLGSHOWUSEROPTIONSDLG;
DLL_SHOWWINDOWSHOWWINDOW;
DLL_DESTROYWINDOWDESTROYWINDOW;
DLL_INITIALIZEINITIALIZE;
#endif // #ifdefIMWND_FROM_DLL
};
// --------------------------------------------------------------------------------
#endif // IMPUTMETHOD_H
/ /
// InputMethod.cpp:implementationoftheCInputMethodclass.
//
/ /
#include " InputMethod.h "
// --------------------------------------------------------------------
// Macrodefine
#define SIP_WND_WIDTH200
#define SIP_WND_HEIGHT180
#define IMWND_DLL_PATHTEXT("window/dllwnd.dll")
// ----------------------------------------------------------------------
/ /
// Construction/Destruction
/ /
CInputMethod::CInputMethod( long * plDllCnt,HINSTANCEhInst)
{
GETINSTANCE();
m_hInst = hInst;
m_plDllCnt = plDllCnt;
( * m_plDllCnt) ++ ;
m_lRef = 1 ; // Setrefcountto1oncreate.
#ifdefIMWND_FROM_DLL
GETWINDOW = NULL;
SHOWUSEROPTIONSDLG = NULL;
SHOWWINDOW = NULL;
DESTROYWINDOW = NULL;
INITIALIZE = NULL;
HINSTANCEhInstDll;
hInstDll = LoadLibrary(IMWND_DLL_PATH);
if (hInstDll != NULL)
{
GETWINDOW = (DLL_GETWINDOW)GetProcAddress(hInstDll,TEXT( " IMGetWindow " ));
SHOWUSEROPTIONSDLG = (DLL_SHOWUSEROPTIONSDLG)GetProcAddress(hInstDll,TEXT( " IMShowUserOptionsDlg " ));
SHOWWINDOW = (DLL_SHOWWINDOW)GetProcAddress(hInstDll,TEXT( " IMShowWindow " ));
DESTROYWINDOW = (DLL_DESTROYWINDOW)GetProcAddress(hInstDll,TEXT( " IMDestroyWindow " ));
INITIALIZE = (DLL_INITIALIZE)GetProcAddress(hInstDll,TEXT( " IMInitialize " ));
}
if (GETWINDOW == NULL ||
SHOWUSEROPTIONSDLG == NULL ||
SHOWWINDOW == NULL ||
DESTROYWINDOW == NULL ||
INITIALIZE == NULL)
{
m_bLoadLib = FALSE;
}
else
{
m_bLoadLib = TRUE;
}
#endif
}
CInputMethod:: ~ CInputMethod()
{
( * m_plDllCnt) -- ;
}
// -------------------------------------------------------------------------------------------
// Description:
// Thismethodisimplementedtocreatethewindowsandimagelistfortheinputmethod(IM).
// ----------------------------------------------------------------------------------------------
HRESULTSTDMETHODCALLTYPECInputMethod::Select(HWNDhWndSip)
{
if (INITIALIZE(m_hInst,hWndSip) == FALSE)
{
return E_FAIL;
}
SHOWWINDOW(TRUE);
return S_OK;
}
// -------------------------------------------------------------------------------------------
// Description:
// Thismethodisimplementedtoselecttheinputmethod(IM)outofthesoftware-based
// inputpanelwindowandtodestroytheIMwindows.
// ----------------------------------------------------------------------------------------------
HRESULTSTDMETHODCALLTYPECInputMethod::Deselect()
{
DESTROYWINDOW();
return S_OK;
}
// -------------------------------------------------------------------------------------------
// Description:
// Thismethodisimplementedtoperformanyinitializationbeforethesoftware-based
// inputpanelwindowisdisplayed
// ----------------------------------------------------------------------------------------------
HRESULTSTDMETHODCALLTYPECInputMethod::Showing()
{
SHOWWINDOW(TRUE);
return S_OK;
}
// -------------------------------------------------------------------------------------------
// Description:
// Thismethodisimplementedtoperformanysavingroutinesbeforethesoftware-based
// inputpanelishidden.
// ----------------------------------------------------------------------------------------------
HRESULTSTDMETHODCALLTYPECInputMethod::Hiding()
{
SHOWWINDOW(FALSE);
return S_OK;
}
// -------------------------------------------------------------------------------------------
// Description:
// Thismethodisimplementedtoreturninformationaboutthecurrentinput
// method(IM)totheoperatingsystem.
// ----------------------------------------------------------------------------------------------
HRESULTSTDMETHODCALLTYPECInputMethod::GetInfo(IMINFO * pimi)
{
pimi -> cbSize = sizeof (IMINFO);
pimi -> hImageNarrow = 0 ;
pimi -> hImageWide = 0 ;
pimi -> iNarrow = 0 ;
pimi -> iWide = 0 ;
pimi -> fdwFlags = SIPF_DOCKED;
pimi -> rcSipRect.left = 0 ;
pimi -> rcSipRect.top = 0 ;
pimi -> rcSipRect.right = SIP_WND_WIDTH;
pimi -> rcSipRect.bottom = SIP_WND_HEIGHT;
return S_OK;
}
// -------------------------------------------------------------------------------------------
// Description:
// ThismethodisimplementedfortheIMtoreceiveinformationaboutthesize,
// placement,anddockedstatusofthesoftware-basedinputpanel.
// ----------------------------------------------------------------------------------------------
HRESULTSTDMETHODCALLTYPECInputMethod::ReceiveSipInfo(SIPINFO * psi)
{
return S_OK;
}
// -------------------------------------------------------------------------------------------
// Description:
// ThismethodisimplementedtoreceiveapointertoanIIMCallbackinterface.
// Aninputmethod(IM)usestheIIMCallbackinterfacetosendkeystrokestoapplications
// andtochangetheiconsontheInputPanelbutton.
// ----------------------------------------------------------------------------------------------
HRESULTSTDMETHODCALLTYPECInputMethod::RegisterCallback(IIMCallback * pIMCallback)
{
// TelltheIMwindowtoregisterthecallback
HWNDhWnd = GETWINDOW();
SendMessage(hWnd,MYMSG_REGCALLBACK,(WPARAM)pIMCallback, 0 );
return S_OK;
}
// -------------------------------------------------------------------------------------------
// Description:
// Thismethodisimplementedtosenddatafromthecurrent
// inputmethod(IM)tothecurrentapplication.
// ----------------------------------------------------------------------------------------------
HRESULTSTDMETHODCALLTYPECInputMethod::GetImData(DWORDdwSize, void * pvImData)
{
return S_OK;
}
// -------------------------------------------------------------------------------------------
// Description:
// Thismethodisimplementedtorespondtoanapplication'srequestto
// setinputmethod(IM)-specificdatawithintheIM.
// ----------------------------------------------------------------------------------------------
HRESULTSTDMETHODCALLTYPECInputMethod::SetImData(DWORDdwSize, void * pvImData)
{
return S_OK;
}
// ---------------------------------------------------------------------
// Description:
// Incrementobjectrefcount
// ----------------------------------------------------------------------
STDMETHODIMPCInputMethod::QueryInterface(REFIIDriid,LPVOID * ppv)
{
#ifdefIMWND_FROM_DLL
if (m_bLoadLib == FALSE)
{
return E_NOINTERFACE;
}
#endif // #ifdefIMWND_FROM_DLL
// IfcallerwantsourIUnknownorIID_IInputMethod2object,
// returnapointertotheobject.
if (IsEqualIID(riid,IID_IUnknown) || IsEqualIID(riid,IID_IInputMethod) || IsEqualIID(riid,IID_IInputMethod2))
{
// Returnptrtoobject.
* ppv = (IInputMethod * ) this ;
AddRef(); // Incrementreftopreventdeleteonreturn.
return NOERROR;
}
* ppv = NULL;
return (E_NOINTERFACE);
}
// ---------------------------------------------------------------------
// Description:
// Incrementobjectrefcount
// ----------------------------------------------------------------------
STDMETHODIMP_(ULONG)CInputMethod::AddRef()
{
ULONGcnt;
cnt = (ULONG)InterlockedIncrement( & m_lRef);
return cnt;
}
// ---------------------------------------------------------------------
// Description:
// Incrementobjectrefcount
// ----------------------------------------------------------------------
STDMETHODIMP_(ULONG)CInputMethod::Release()
{
ULONGcnt;
cnt = (ULONG)InterlockedDecrement( & m_lRef);
if (cnt == 0 )
{
delete this ;
return 0 ;
}
return cnt;
}
// ---------------------------------------------------------------------
// Description:
// TheSIPControlPanelappletisaskingforaconfigurationdialogboxtobedisplayed.
// ----------------------------------------------------------------------
HRESULTSTDMETHODCALLTYPECInputMethod::UserOptionsDlg(HWNDhwndParent)
{
SHOWUSEROPTIONSDLG(hwndParent,m_hInst);
return S_OK;
}
OK,编译完毕,大功告成!