WTL應用程序處理ActiveX事件更好的方法

WTL應用程序處理ActiveX事件更好的方法
之前寫的“WTL應用程序接收處理ActiveX控件事件的實現”文章已經描述瞭如何處理ActiveX的事件,但那個方法實施起來比較繁鎖,也不易讀解。這裏介紹更簡便的方法,甚少不需要一個一個的將UUID拷到WTL工程來用,而是直到使用IDL文件編譯出來的結果,這樣的好處是當這些UUID更改後重新編譯就可以了,不需要修改源碼。


首先我們寫的ActiveX控件可以將IDL公開給使用者(僅項目內或公司內),如果直接把IDL文件給使用者,後者使用#include方法把該IDL包含到其IDL中,編譯時可能會有問題,畢竟ActiveX控件的library對使用者是沒有意義的反而會導致錯誤。


解決辦法是:(假設工程名是Test,接口是TestCtrl)
1. 在完成接口和事件定義後將library TestLib部分移出到TestLib.idl文件中,原來的idl文件刪除該library項只保留interface ITestCtrl和dispinterface _ITestCtrlEvents,在TestLib.idl中使用#include "Test.idl"包含接口。
2. 然後將TestLib.idl添加到工程並刪除原來的IDL文件,將Test.idl移到公用目錄下(別人可以直接使用),並將該公用目錄添加到MIDL的Addional Inlcude Directories中。
3. 將interface和dispinterface中的所有id值定義成宏,文件名格式可以是工程名+DISPIDs.h(與Test.idl放在同一目錄下),比如TestDISPIDs.h,在該宏定義文件加上事件的擴展聲明,以後用到__uuidof(_ITestCtrlEvents)的地方全用DIID_ITestCtrlEvents代替:
#ifdef __cplusplus
extern "C" const IID DIID__ITestCtrlEvents;
#else
extern const IID DIID__ITestCtrlEvents;
#endif
4. 生成連接點後在_ITestCtrlEvents_CP.h包含TestDISPIDs.h文件。添加實現代碼,編譯生成DLL並註冊,下一步使用。


在WTL工程中,使用IDispEventSimpleImpl代替IDispEventImpl,前者不再需要Lib的UUID,處理方法是:
1. 在MainDlg.h中包含TestDISPIDs.h,定義一個控件ID比如“#define CONTROL_ID 1001”,修改CMainDlg類從IDispEventSimpleImpl中重載:
public IDispEventSimpleImpl<CONTROL_ID, CMainDlg, &DIID__ITestCtrlEvents>
2. 在CMainDlg中添加SINK_MAP:
 BEGIN_SINK_MAP(CMainDlg)
  SINK_ENTRY_INFO(CONTROL_ID, DIID__ITestCtrlEvents, DISPID_CLICK, OnItemClick, &s_infoOnItemClick)
  SINK_ENTRY_INFO(CONTROL_ID, DIID__ITestCtrlEvents, DISPID_DBLCLK, OnItemDblClk, &s_infoOnItemDblClk)
  SINK_ENTRY_INFO(CONTROL_ID, DIID__ITestCtrlEvents, DISPID_CHANGED, OnItemChanged, &s_infoOnItemChanged)
 END_SINK_MAP()
3. 添加事件處理函數:
 STDMETHOD(OnItemClick)(IBaseNode* pItem);
 STDMETHOD(OnItemDblClk)(IBaseNode* pItem);
 STDMETHOD(OnItemChanged)(IBaseNode* pNewItem, IBaseNode* pOldItem);
4. 定義Entry Info爲static:
 static _ATL_FUNC_INFO s_infoOnItemClick;
 static _ATL_FUNC_INFO s_infoOnItemDblClk;
 static _ATL_FUNC_INFO s_infoOnItemChanged;
5. 在cpp文件中定義Entry Info實體:
_ATL_FUNC_INFO CMainDlg::s_infoOnItemClick =
{
 CC_STDCALL,   // Calling convention.
  VT_I4,    // Return type.
  1,        // Number of arguments.
 {VT_DISPATCH} // Argument types.
};
_ATL_FUNC_INFO CMainDlg::s_infoOnItemDblClk =
{
 CC_STDCALL,   // Calling convention.
  VT_I4,    // Return type.
  1,        // Number of arguments.
 {VT_DISPATCH} // Argument types.
};
_ATL_FUNC_INFO CMainDlg::s_infoOnItemChanged =
{
 CC_STDCALL,   // Calling convention.
  VT_I4,    // Return type.
  2,        // Number of arguments.
 {VT_DISPATCH, VT_DISPATCH} // Argument types.
};
6. 定義事件函數實體:
STDMETHODIMP CMainDlg::OnItemClick(IBaseNode* pItem){…}
STDMETHODIMP CMainDlg::OnItemDblClk(IBaseNode* pItem){…}
STDMETHODIMP CMainDlg::OnItemChanged(IBaseNode* pNewItem, IBaseNode* pOldItem){…}
7. 將Test.idl包含到WTL工程的IDL文件中(沒有則創建一個與工程同名的IDL),編譯IDL後將xxx_i.c添加到工程中,編譯整個WTL工程,測試。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章