多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > php開源 > php教程 > ATL實現一個組件多個dual接口,multidisp

ATL實現一個組件多個dual接口,multidisp

來源:程序員人生   發布時間:2014-12-14 08:56:29 閱讀次數:2689次

最近想自己寫個按鍵精靈的插件,因而接觸到這個問題: 怎樣在1個組件里實現兩個自動化接口。

主要針對的ATL,MFC貌似沒這個問題,具體MFC是怎樣實現的自己沒有深究。


按鍵精靈的插件會在1個組件里實現兩個dispinterface,具體請看oleview工具截圖:



剛開始對這個問題不理解,以為不是問題,自己用ATL嘗試了幾次,才發現不是那末回事,因而google之。


MSDN上是這么說的,看這里

ATL不提供任作甚將多個兩重接口支持。IDispatch的單個實現。 但是,有幾個已知的方法來手動合并接口,如創建包括創建1個新的對象,履行 QueryInterface 函數或使用嵌套的對象1個基于typeinfo的實現的單獨 IDispatch 接口來創建 IDispatch 接口的模板選件類。

這些方法都有潛伏的命名空間沖突問題,和代碼復雜性和可保護性。 建議不要創建多個雙綁定接口。

雖然ATL不支持,但是上面也說了,還是有方法的,因而再google之,終究找到1篇相干問題的文章,里面說的很細,還提供了幾種不同的方案:

網址:https://www.sellsbrothers.com/posts/details/12657


自己比較喜歡第2和第3種方案,對照來講,第3種方案比較容易理解和實現。


固然我是用的第3種方案的簡單實現,沒有從typeinfo接口再繼承,還是自己實現了1個類,代理其實接口的IDispatch調用,空話不說了,上代碼:

#ifndef _XMULTIDISPIMPL_H_ #define _XMULTIDISPIMPL_H_ #include <atlcom.h> #define INTERFACE_MASK 0xFFFF0000UL #define DISPID_MASK 0x0000FFFFUL template<class tihclass = CComTypeInfoHolder> struct _TIH_ENTRY { tihclass *ptih; // 類型庫指針,實現IDispatch調用 DWORD dispEncode; // 函數調用id編碼,在GetIdsOfNames函數中對返回的dispid進行編碼,嘗試解決dispid重復的問題 DWORD offset; // 接口虛函數表偏移,IDispatchImpl<...> }; template <class T, class tihclass = CComTypeInfoHolder> class ATL_NO_VTABLE XMultiDispImpl: public IDispatch { public: typedef _TIH_ENTRY<tihclass> TIH_ENTRY; public: STDMETHOD(GetTypeInfoCount)(UINT* pctinfo) { //TODO: 斟酌是不是按多個類型庫處理 *pctinfo = 1; return S_OK; } STDMETHOD(GetTypeInfo)(UINT itinfo, LCID lcid, ITypeInfo** pptinfo) { //TODO: 斟酌是不是按多個類型庫處理 T* pT = static_cast<T*> (this); TIH_ENTRY* pEntry = pT->GetTypeInfoHolder(); if (pEntry->ptih) { // 默許返回第1個接口的類型庫 return pEntry->ptih->GetTypeInfo(itinfo, lcid, pptinfo); } return E_FAIL; } STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid) { // NOTE: 函數名字不能沖突, // 名字相同時按順序查找接口映照表中的接口, // 返回第1個匹配的接口函數對應的dispid T* pT = static_cast<T*> (this); TIH_ENTRY* pEntry = pT->GetTypeInfoHolder(); HRESULT hr = DISP_E_UNKNOWNNAME; while (pEntry->ptih != NULL) { hr = pEntry->ptih->GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid); if (SUCCEEDED(hr)) { for (UINT i = 0; i < cNames; i++) { rgdispid[i] |= pEntry->dispEncode; } return hr; } else if (hr != DISP_E_UNKNOWNNAME) { return hr; } pEntry++; } return DISP_E_UNKNOWNNAME; } STDMETHOD(Invoke)(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr) { T* pT = static_cast<T*> (this); TIH_ENTRY* pEntry = pT->GetTypeInfoHolder(); HRESULT hr = DISP_E_MEMBERNOTFOUND; if (dispidMember & INTERFACE_MASK) { // 函數id是編碼過的,查找對應的接口進行調用,1般是腳本1類的動態調用 while (pEntry->ptih != NULL) { if (pEntry->dispEncode == (dispidMember & INTERFACE_MASK)) { // 找到接口,調用并退出 hr = pEntry->ptih->Invoke((IDispatch*)(((DWORD)pT)+pEntry->offset), (dispidMember & DISPID_MASK), riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr); return hr; } pEntry++; } } else { // 函數id未編碼,逐一接口進行嘗試,1般是VC生成的接口類進行的靜態調用 // NOTE: 不同的接口,如果存在dispid相同的函數, // 請保證其函數參數個數或參數類型或返回值類型不要相同, // 否則可能會調用到毛病的接口函數 while (pEntry->ptih != NULL) { hr = pEntry->ptih->Invoke((IDispatch*)(((DWORD)pT)+pEntry->offset), dispidMember, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr); if (SUCCEEDED(hr)) { // 調用成功退出 return hr; } pEntry++; } } return DISP_E_MEMBERNOTFOUND; } }; // 映照表宏定義,需要在組件的頭文件中援用 #define BEGIN_MULTI_DISPATCH_MAP(CLS) typedef CLS theDerived; static theDerived::TIH_ENTRY* GetTypeInfoHolder() { const DWORD _dwCnt = __COUNTER__; static theDerived::TIH_ENTRY pDispEntries[] = { // 函數id編碼,占用id的高16位bit #define MULTI_DISPATCH_ENCODE() (((DWORD)(__COUNTER__) - _dwCnt) << 16) #define MULTI_DISPATCH_ENTRY(theBase) { &theBase::_tih, MULTI_DISPATCH_ENCODE(), offsetofclass(theBase, theDerived) }, #define END_MULTI_DISPATCH_MAP() { NULL, 0UL, 0UL } }; return(pDispEntries); } #endif // sentry

使用方法,在組件類的頭文件中,讓我們的組件繼承我們的類:

class ATL_NO_VTABLE CQMPlugin : public CComObjectRootEx<CComSingleThreadModel>, public CComCoClass<CQMPlugin, &CLSID_QMPlugin>, public ISupportErrorInfo, <span style="color:#3366ff;">public XMultiDispImpl<CQMPlugin>,</span> public IDispatchImpl<IQMPlugin, &IID_IQMPlugin, &LIBID_zdLib, /*wMajor =*/ 1, /*wMinor =*/ 0>, public IDispatchImpl<IQMPluginStandard, &IID_IQMPluginStandard, &LIBID_zdLib, /*wMajor =*/ 1, /*wMinor =*/ 0>

藍色是要手動添加的代碼

在BEGIN_COM_MAP和END_COM_MAP中添加以下代碼:

BEGIN_COM_MAP(CQMPlugin) <span style="color:#3366ff;">COM_INTERFACE_ENTRY2(IDispatch, XMultiDispImpl<CQMPlugin>)</span> COM_INTERFACE_ENTRY(IQMPlugin) COM_INTERFACE_ENTRY(IQMPluginStandard) COM_INTERFACE_ENTRY(ISupportErrorInfo) END_COM_MAP()
意思是說當外部程序查詢IDispatch接口,返回我們實現的類的虛函數表


下面就是要添加接口映照表了,目前感覺這里還是看著不是很爽,暫時沒有解決辦法:

<span style="color:#3366ff;">typedef IDispatchImpl<IQMPlugin, &IID_IQMPlugin, &LIBID_zdLib, /*wMajor =*/ 1, /*wMinor =*/ 0> TQMPlugin; typedef IDispatchImpl<IQMPluginStandard, &IID_IQMPluginStandard, &LIBID_zdLib, /*wMajor =*/ 1, /*wMinor =*/ 0> TQMPluginStandard; BEGIN_MULTI_DISPATCH_MAP(CQMPlugin) MULTI_DISPATCH_ENTRY(TQMPlugin) MULTI_DISPATCH_ENTRY(TQMPluginStandard) END_MULTI_DISPATCH_MAP()</span>

記住要先typedef 再用MULTI_DISPATCH_ENTRY,不然會編譯失敗,這也是讓人不爽的地方。

其他的可以按正常的ATLCOM接口開發步驟進行開發了。


下面就是注意事項了:

1. 如果要在1個組件里實現多個disp接口,對每一個接口的方法或屬性,不要出現重名的情況,代碼中有說明;

2. 函數的dispid可以相同,但是如果dispid相同,請1定讓兩個函數的參數個數,參數類型或返加值類型不要全部相同,不然可能調用到毛病的接口函數;

3. 理論上這個類實現的多接口是支持靜態調用和動態調用的

4. 對dispid相同的情況,代碼是通過在dispid的高16bit設置標志還區分的,對VBS1類的動態腳本調用是沒有問題的,在腳本里可以把組件當做只實現了1個接口

5. 由于使用的dispid的高16bit,所以這個類最多支持65536個接口,同時每一個接口的方法和屬性不能超過65536個,有需要的可以自行在代碼里調劑。


最后希望代碼能幫助到大家,沒有甚么比自己的代碼被他人認可更讓人。。。,找不到形容詞了,歡迎大定留言哈。



生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 欧美xxxx在线| 亚洲欧美在线观看视频 | 自拍偷拍小说 | 日韩欧美在线视频 | 午夜私人福利影院 | 国产成人福利美女观看视频 | 91亚洲精品久久 | 龙口护士门91午夜国产在线 | 亚洲国产精品一区二区三区 | 欧美在线天堂 | 欧美在线视频 一区二区 | 亚洲乱码一二三四区麻豆 | 精品日韩欧美国产一区二区 | 黑人双渗透 | 国产免费久久精品久久久 | 日韩高清片 | 亚洲欧美久久 | 校园春色偷拍自拍 | 久久视频精品36线视频在线观看 | 亚洲最黄网站 | 最近免费中文字幕高清大全 | 日本高清另类videohd | 欧美在线一二三区 | 亚洲精品视频在线观看视频 | 久久精品www | 暴力欧美娇小 videos | 精品视频亚洲 | 国产成人精品一区二区免费 | 久久精品隔壁老王影院 | 亚洲国产高清人在线 | 久久久久久久久国产 | 亚洲欧美日韩一区二区 | 欧美在线不卡视频 | 欧美性生交xxxxx久久久 | 日韩欧| 国产乱码亚洲精品一区二区 | 久久精品一级 | 国产嫩草影院精品免费网址 | 日韩日韩日韩 | 国美女福利视频午夜精品 | 可以免费观看的黄色网址 |