//========================================================================
//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"
//===================================================================
#defineMYMSG_REGCALLBACK(WM_USER+100)
//Description:
//Themessageisusingforregisteringtheinputmethodcallbackfunction
//
//Parameters:
//pImCallback=(IIMCallback*)wParam
//0=lParam
//=====================================================================
//====================================================================
//Macrodefine
#defineWINDOW_CLASSTEXT("IMWND_Class")
#defineWINDOW_TITLETEXT("IMWND_Title")
//Thetaskbarheight
#defineTASKBAR_HEIGHT_AUTOHIDE5
#defineTASKBAR_HEIGHT26
#defineIMG_IMWND_WIDTH370
#defineIMG_IMWND_HEIGHT206
#defineSCREEN_WIDTH800
#defineSCREEN_HEIGHT480
//==================================================================
//ForwardDeclare
//------------------------------------------------------------------------
//Theinterface
HWNDIMGetWindow();
voidIMShowUserOptionsDlg(HWNDhWndParent,HINSTANCEhInst);
voidIMShowWindow(BOOLbShow);
voidIMDestroyWindow();
BOOLIMInitialize(HINSTANCEhInstSip,HWNDhWndSip);
//------------------------------------------------------------------------
voidOnDestroy(HWNDhWnd,UINTwMsg,WPARAMwParam,LPARAMlParam);
voidOnPaint(HWNDhWnd,UINTwMsg,WPARAMwParam,LPARAMlParam);
voidOnRegCallback(HWNDhWnd,UINTwMsg,WPARAMwParam,LPARAMlParam);
voidOnLButtonUp(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)
{
caseDLL_PROCESS_ATTACH:
{
g_hInst=(HMODULE)hModule;
break;
}
}
returnTRUE;
}
//-------------------------------------------------------------------
//Description:
//Getthewindowhandle
//
//------------------------------------------------------------------
HWNDIMGetWindow()
{
returng_hWnd;
}
//-------------------------------------------------------------------
//Description:
//Showtheuseroptionsdialog
//
//------------------------------------------------------------------
voidIMShowUserOptionsDlg(HWNDhWndParent,HINSTANCEhInst)
{
MessageBox(NULL,TEXT("控制面板可以調出的輸入法設置"),TEXT("設置"),MB_OK);
}
//-------------------------------------------------------------------
//Description:
//Showthewindow
//
//------------------------------------------------------------------
voidIMShowWindow(BOOLbShow)
{
if(bShow==TRUE)
{
::ShowWindow(g_hWnd,SW_SHOW);
}
else
{
::ShowWindow(g_hWnd,SW_HIDE);
}
}
//-------------------------------------------------------------------
//Description:
//Destroythewindow
//
//------------------------------------------------------------------
voidIMDestroyWindow()
{
::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)
{
returnFALSE;
}
//Setthewindowareatosuitwiththeimage
RECTrcClientWnd={0};
GetClientRect(hWndSip,&rcClientWnd);
RECTrcSipWnd={0};
GetWindowRect(hWndSip,&rcSipWnd);
//Itmaybetheframefortheparentwindow,sowemustholdit.
intiWidth=(rcSipWnd.right-rcSipWnd.left)-(rcClientWnd.right-rcClientWnd.left)+IMG_IMWND_WIDTH;
intiHeight=(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)
{
returnFALSE;
}
returnTRUE;
}
//-------------------------------------------------------------------
//Description:
//Thewindowprocess
//
//------------------------------------------------------------------
LRESULTWndProc(HWNDhWnd,UINTwMsg,WPARAMwParam,LPARAMlParam)
{
switch(wMsg)
{
caseWM_PAINT:
OnPaint(hWnd,wMsg,wParam,lParam);
return0;
caseMYMSG_REGCALLBACK:
OnRegCallback(hWnd,wMsg,wParam,lParam);
return0;
caseWM_ERASEBKGND:
//Donothinginordernottoflashthewindow
return0;
caseWM_LBUTTONUP:
OnLButtonUp(hWnd,wMsg,wParam,lParam);
return0;
}
returnDefWindowProc(hWnd,wMsg,wParam,lParam);
}
//-------------------------------------------------------------------
//Description:
//OnmessageWM_PAINT
//
//------------------------------------------------------------------
voidOnPaint(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
//
//------------------------------------------------------------------
voidOnRegCallback(HWNDhWnd,UINTwMsg,WPARAMwParam,LPARAMlParam)
{
g_pIMCallback=(IIMCallback*)wParam;
}
//-------------------------------------------------------------------
//Description:
//OnmessageWM_LBUTTONUP
//
//------------------------------------------------------------------
voidOnLButtonUp(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
#defineIMPUTMETHOD_H
#include"stdafx.h"
#include"sip.h"
#include"IMWnd.h"
//-----------------------------------------------------------------
classCInputMethod:publicIInputMethod
{
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
longm_lRef;
#ifdefIMWND_FROM_CODE
CIMWnd*m_pIMWnd;//Theinputmethodwindowpointer
#defineGETINSTANCE()(m_pIMWnd=CIMWnd::GetInstance())
#defineGETWINDOW()(m_pIMWnd->GetWindow())
#defineSHOWUSEROPTIONSDLG(x,y)(m_pIMWnd->ShowUserOptionsDlg(x,y))
#defineSHOWWINDOW(x)(m_pIMWnd->ShowWindow(x))
#defineDESTROYWINDOW()(m_pIMWnd->DestroyWindow())
#defineINITIALIZE(x,y)(m_pIMWnd->Initialize(x,y))
#endif//#ifdefIMWND_FROM_CODE
#ifdefIMWND_FROM_DLL
BOOLm_bLoadLib;
//Idon'tneedgetinstancefromthedll.
#defineGETINSTANCE()
typedefHWND(WINAPI*DLL_GETWINDOW)(void);
typedefvoid(WINAPI*DLL_SHOWUSEROPTIONSDLG)(HWND,HINSTANCE=NULL);
typedefvoid(WINAPI*DLL_SHOWWINDOW)(BOOL);
typedefvoid(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
#defineSIP_WND_WIDTH200
#defineSIP_WND_HEIGHT180
#defineIMWND_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)
{
returnE_FAIL;
}
SHOWWINDOW(TRUE);
returnS_OK;
}
//-------------------------------------------------------------------------------------------
//Description:
//Thismethodisimplementedtoselecttheinputmethod(IM)outofthesoftware-based
//inputpanelwindowandtodestroytheIMwindows.
//----------------------------------------------------------------------------------------------
HRESULTSTDMETHODCALLTYPECInputMethod::Deselect()
{
DESTROYWINDOW();
returnS_OK;
}
//-------------------------------------------------------------------------------------------
//Description:
//Thismethodisimplementedtoperformanyinitializationbeforethesoftware-based
//inputpanelwindowisdisplayed
//----------------------------------------------------------------------------------------------
HRESULTSTDMETHODCALLTYPECInputMethod::Showing()
{
SHOWWINDOW(TRUE);
returnS_OK;
}
//-------------------------------------------------------------------------------------------
//Description:
//Thismethodisimplementedtoperformanysavingroutinesbeforethesoftware-based
//inputpanelishidden.
//----------------------------------------------------------------------------------------------
HRESULTSTDMETHODCALLTYPECInputMethod::Hiding()
{
SHOWWINDOW(FALSE);
returnS_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;
returnS_OK;
}
//-------------------------------------------------------------------------------------------
//Description:
//ThismethodisimplementedfortheIMtoreceiveinformationaboutthesize,
//placement,anddockedstatusofthesoftware-basedinputpanel.
//----------------------------------------------------------------------------------------------
HRESULTSTDMETHODCALLTYPECInputMethod::ReceiveSipInfo(SIPINFO*psi)
{
returnS_OK;
}
//-------------------------------------------------------------------------------------------
//Description:
//ThismethodisimplementedtoreceiveapointertoanIIMCallbackinterface.
//Aninputmethod(IM)usestheIIMCallbackinterfacetosendkeystrokestoapplications
//andtochangetheiconsontheInputPanelbutton.
//----------------------------------------------------------------------------------------------
HRESULTSTDMETHODCALLTYPECInputMethod::RegisterCallback(IIMCallback*pIMCallback)
{
//TelltheIMwindowtoregisterthecallback
HWNDhWnd=GETWINDOW();
SendMessage(hWnd,MYMSG_REGCALLBACK,(WPARAM)pIMCallback,0);
returnS_OK;
}
//-------------------------------------------------------------------------------------------
//Description:
//Thismethodisimplementedtosenddatafromthecurrent
//inputmethod(IM)tothecurrentapplication.
//----------------------------------------------------------------------------------------------
HRESULTSTDMETHODCALLTYPECInputMethod::GetImData(DWORDdwSize,void*pvImData)
{
returnS_OK;
}
//-------------------------------------------------------------------------------------------
//Description:
//Thismethodisimplementedtorespondtoanapplication'srequestto
//setinputmethod(IM)-specificdatawithintheIM.
//----------------------------------------------------------------------------------------------
HRESULTSTDMETHODCALLTYPECInputMethod::SetImData(DWORDdwSize,void*pvImData)
{
returnS_OK;
}
//---------------------------------------------------------------------
//Description:
//Incrementobjectrefcount
//----------------------------------------------------------------------
STDMETHODIMPCInputMethod::QueryInterface(REFIIDriid,LPVOID*ppv)
{
#ifdefIMWND_FROM_DLL
if(m_bLoadLib==FALSE)
{
returnE_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.
returnNOERROR;
}
*ppv=NULL;
return(E_NOINTERFACE);
}
//---------------------------------------------------------------------
//Description:
//Incrementobjectrefcount
//----------------------------------------------------------------------
STDMETHODIMP_(ULONG)CInputMethod::AddRef()
{
ULONGcnt;
cnt=(ULONG)InterlockedIncrement(&m_lRef);
returncnt;
}
//---------------------------------------------------------------------
//Description:
//Incrementobjectrefcount
//----------------------------------------------------------------------
STDMETHODIMP_(ULONG)CInputMethod::Release()
{
ULONGcnt;
cnt=(ULONG)InterlockedDecrement(&m_lRef);
if(cnt==0)
{
deletethis;
return0;
}
returncnt;
}
//---------------------------------------------------------------------
//Description:
//TheSIPControlPanelappletisaskingforaconfigurationdialogboxtobedisplayed.
//----------------------------------------------------------------------
HRESULTSTDMETHODCALLTYPECInputMethod::UserOptionsDlg(HWNDhwndParent)
{
SHOWUSEROPTIONSDLG(hwndParent,m_hInst);
returnS_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"
//===================================================================
#defineMYMSG_REGCALLBACK(WM_USER+100)
//Description:
//Themessageisusingforregisteringtheinputmethodcallbackfunction
//
//Parameters:
//pImCallback=(IIMCallback*)wParam
//0=lParam
//=====================================================================
//====================================================================
//Macrodefine
#defineWINDOW_CLASSTEXT("IMWND_Class")
#defineWINDOW_TITLETEXT("IMWND_Title")
//Thetaskbarheight
#defineTASKBAR_HEIGHT_AUTOHIDE5
#defineTASKBAR_HEIGHT26
#defineIMG_IMWND_WIDTH370
#defineIMG_IMWND_HEIGHT206
#defineSCREEN_WIDTH800
#defineSCREEN_HEIGHT480
//==================================================================
//ForwardDeclare
//------------------------------------------------------------------------
//Theinterface
HWNDIMGetWindow();
voidIMShowUserOptionsDlg(HWNDhWndParent,HINSTANCEhInst);
voidIMShowWindow(BOOLbShow);
voidIMDestroyWindow();
BOOLIMInitialize(HINSTANCEhInstSip,HWNDhWndSip);
//------------------------------------------------------------------------
voidOnDestroy(HWNDhWnd,UINTwMsg,WPARAMwParam,LPARAMlParam);
voidOnPaint(HWNDhWnd,UINTwMsg,WPARAMwParam,LPARAMlParam);
voidOnRegCallback(HWNDhWnd,UINTwMsg,WPARAMwParam,LPARAMlParam);
voidOnLButtonUp(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)
{
caseDLL_PROCESS_ATTACH:
{
g_hInst=(HMODULE)hModule;
break;
}
}
returnTRUE;
}
//-------------------------------------------------------------------
//Description:
//Getthewindowhandle
//
//------------------------------------------------------------------
HWNDIMGetWindow()
{
returng_hWnd;
}
//-------------------------------------------------------------------
//Description:
//Showtheuseroptionsdialog
//
//------------------------------------------------------------------
voidIMShowUserOptionsDlg(HWNDhWndParent,HINSTANCEhInst)
{
MessageBox(NULL,TEXT("控制面板可以調出的輸入法設置"),TEXT("設置"),MB_OK);
}
//-------------------------------------------------------------------
//Description:
//Showthewindow
//
//------------------------------------------------------------------
voidIMShowWindow(BOOLbShow)
{
if(bShow==TRUE)
{
::ShowWindow(g_hWnd,SW_SHOW);
}
else
{
::ShowWindow(g_hWnd,SW_HIDE);
}
}
//-------------------------------------------------------------------
//Description:
//Destroythewindow
//
//------------------------------------------------------------------
voidIMDestroyWindow()
{
::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)
{
returnFALSE;
}
//Setthewindowareatosuitwiththeimage
RECTrcClientWnd={0};
GetClientRect(hWndSip,&rcClientWnd);
RECTrcSipWnd={0};
GetWindowRect(hWndSip,&rcSipWnd);
//Itmaybetheframefortheparentwindow,sowemustholdit.
intiWidth=(rcSipWnd.right-rcSipWnd.left)-(rcClientWnd.right-rcClientWnd.left)+IMG_IMWND_WIDTH;
intiHeight=(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)
{
returnFALSE;
}
returnTRUE;
}
//-------------------------------------------------------------------
//Description:
//Thewindowprocess
//
//------------------------------------------------------------------
LRESULTWndProc(HWNDhWnd,UINTwMsg,WPARAMwParam,LPARAMlParam)
{
switch(wMsg)
{
caseWM_PAINT:
OnPaint(hWnd,wMsg,wParam,lParam);
return0;
caseMYMSG_REGCALLBACK:
OnRegCallback(hWnd,wMsg,wParam,lParam);
return0;
caseWM_ERASEBKGND:
//Donothinginordernottoflashthewindow
return0;
caseWM_LBUTTONUP:
OnLButtonUp(hWnd,wMsg,wParam,lParam);
return0;
}
returnDefWindowProc(hWnd,wMsg,wParam,lParam);
}
//-------------------------------------------------------------------
//Description:
//OnmessageWM_PAINT
//
//------------------------------------------------------------------
voidOnPaint(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
//
//------------------------------------------------------------------
voidOnRegCallback(HWNDhWnd,UINTwMsg,WPARAMwParam,LPARAMlParam)
{
g_pIMCallback=(IIMCallback*)wParam;
}
//-------------------------------------------------------------------
//Description:
//OnmessageWM_LBUTTONUP
//
//------------------------------------------------------------------
voidOnLButtonUp(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
#defineIMPUTMETHOD_H
#include"stdafx.h"
#include"sip.h"
#include"IMWnd.h"
//-----------------------------------------------------------------
classCInputMethod:publicIInputMethod
{
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
longm_lRef;
#ifdefIMWND_FROM_CODE
CIMWnd*m_pIMWnd;//Theinputmethodwindowpointer
#defineGETINSTANCE()(m_pIMWnd=CIMWnd::GetInstance())
#defineGETWINDOW()(m_pIMWnd->GetWindow())
#defineSHOWUSEROPTIONSDLG(x,y)(m_pIMWnd->ShowUserOptionsDlg(x,y))
#defineSHOWWINDOW(x)(m_pIMWnd->ShowWindow(x))
#defineDESTROYWINDOW()(m_pIMWnd->DestroyWindow())
#defineINITIALIZE(x,y)(m_pIMWnd->Initialize(x,y))
#endif//#ifdefIMWND_FROM_CODE
#ifdefIMWND_FROM_DLL
BOOLm_bLoadLib;
//Idon'tneedgetinstancefromthedll.
#defineGETINSTANCE()
typedefHWND(WINAPI*DLL_GETWINDOW)(void);
typedefvoid(WINAPI*DLL_SHOWUSEROPTIONSDLG)(HWND,HINSTANCE=NULL);
typedefvoid(WINAPI*DLL_SHOWWINDOW)(BOOL);
typedefvoid(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
#defineSIP_WND_WIDTH200
#defineSIP_WND_HEIGHT180
#defineIMWND_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)
{
returnE_FAIL;
}
SHOWWINDOW(TRUE);
returnS_OK;
}
//-------------------------------------------------------------------------------------------
//Description:
//Thismethodisimplementedtoselecttheinputmethod(IM)outofthesoftware-based
//inputpanelwindowandtodestroytheIMwindows.
//----------------------------------------------------------------------------------------------
HRESULTSTDMETHODCALLTYPECInputMethod::Deselect()
{
DESTROYWINDOW();
returnS_OK;
}
//-------------------------------------------------------------------------------------------
//Description:
//Thismethodisimplementedtoperformanyinitializationbeforethesoftware-based
//inputpanelwindowisdisplayed
//----------------------------------------------------------------------------------------------
HRESULTSTDMETHODCALLTYPECInputMethod::Showing()
{
SHOWWINDOW(TRUE);
returnS_OK;
}
//-------------------------------------------------------------------------------------------
//Description:
//Thismethodisimplementedtoperformanysavingroutinesbeforethesoftware-based
//inputpanelishidden.
//----------------------------------------------------------------------------------------------
HRESULTSTDMETHODCALLTYPECInputMethod::Hiding()
{
SHOWWINDOW(FALSE);
returnS_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;
returnS_OK;
}
//-------------------------------------------------------------------------------------------
//Description:
//ThismethodisimplementedfortheIMtoreceiveinformationaboutthesize,
//placement,anddockedstatusofthesoftware-basedinputpanel.
//----------------------------------------------------------------------------------------------
HRESULTSTDMETHODCALLTYPECInputMethod::ReceiveSipInfo(SIPINFO*psi)
{
returnS_OK;
}
//-------------------------------------------------------------------------------------------
//Description:
//ThismethodisimplementedtoreceiveapointertoanIIMCallbackinterface.
//Aninputmethod(IM)usestheIIMCallbackinterfacetosendkeystrokestoapplications
//andtochangetheiconsontheInputPanelbutton.
//----------------------------------------------------------------------------------------------
HRESULTSTDMETHODCALLTYPECInputMethod::RegisterCallback(IIMCallback*pIMCallback)
{
//TelltheIMwindowtoregisterthecallback
HWNDhWnd=GETWINDOW();
SendMessage(hWnd,MYMSG_REGCALLBACK,(WPARAM)pIMCallback,0);
returnS_OK;
}
//-------------------------------------------------------------------------------------------
//Description:
//Thismethodisimplementedtosenddatafromthecurrent
//inputmethod(IM)tothecurrentapplication.
//----------------------------------------------------------------------------------------------
HRESULTSTDMETHODCALLTYPECInputMethod::GetImData(DWORDdwSize,void*pvImData)
{
returnS_OK;
}
//-------------------------------------------------------------------------------------------
//Description:
//Thismethodisimplementedtorespondtoanapplication'srequestto
//setinputmethod(IM)-specificdatawithintheIM.
//----------------------------------------------------------------------------------------------
HRESULTSTDMETHODCALLTYPECInputMethod::SetImData(DWORDdwSize,void*pvImData)
{
returnS_OK;
}
//---------------------------------------------------------------------
//Description:
//Incrementobjectrefcount
//----------------------------------------------------------------------
STDMETHODIMPCInputMethod::QueryInterface(REFIIDriid,LPVOID*ppv)
{
#ifdefIMWND_FROM_DLL
if(m_bLoadLib==FALSE)
{
returnE_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.
returnNOERROR;
}
*ppv=NULL;
return(E_NOINTERFACE);
}
//---------------------------------------------------------------------
//Description:
//Incrementobjectrefcount
//----------------------------------------------------------------------
STDMETHODIMP_(ULONG)CInputMethod::AddRef()
{
ULONGcnt;
cnt=(ULONG)InterlockedIncrement(&m_lRef);
returncnt;
}
//---------------------------------------------------------------------
//Description:
//Incrementobjectrefcount
//----------------------------------------------------------------------
STDMETHODIMP_(ULONG)CInputMethod::Release()
{
ULONGcnt;
cnt=(ULONG)InterlockedDecrement(&m_lRef);
if(cnt==0)
{
deletethis;
return0;
}
returncnt;
}
//---------------------------------------------------------------------
//Description:
//TheSIPControlPanelappletisaskingforaconfigurationdialogboxtobedisplayed.
//----------------------------------------------------------------------
HRESULTSTDMETHODCALLTYPECInputMethod::UserOptionsDlg(HWNDhwndParent)
{
SHOWUSEROPTIONSDLG(hwndParent,m_hInst);
returnS_OK;
}
OK,编译完毕,大功告成!
本文介绍了一种使用 DLL 替代 CIMWnd 类实现在 Windows CE 中输入法的方法,通过这种方式,可以更灵活地更新输入法组件。文章详细介绍了 DLL 的编写过程及如何与 CInputMethod 类接口配合使用。
328

被折叠的 条评论
为什么被折叠?



