日本搞逼视频_黄色一级片免费在线观看_色99久久_性明星video另类hd_欧美77_综合在线视频

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

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

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

最近想自己寫個按鍵精靈的插件,因而接觸到這個問題: 怎樣在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個,有需要的可以自行在代碼里調劑。


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



生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 一区二区三区四区在线播放 | 久草免费在线 | 久久综合九色综合久久久精品综合 | 亚洲成人在线视频播放 | 欧美日韩免费 | 国产美女av | 在线地址一地址二免费看 | 91在线播放视频 | 亚洲一级毛片 | 久久久久无码国产精品一区 | av在线成人 | 久久久久久黄色 | 久久久国产精品免费 | 高清视频一区 | 国内精品久久久久久久 | 在线无码| 国产网站视频 | 性久久久久久 | 看全色黄大色黄大片男爽一次 | 亚洲网站在线观看 | 久久久久国产一区二区三区 | 欧美日韩无 | 国产黄色大片网站 | 精品视频久久久 | 国内精品一区二区三区 | 亚洲欧美日韩天堂 | 久久亚洲免费 | 伊人久久在线 | 日韩精品影片 | 久久久久久亚洲精品 | 三区视频 | 国内精品一区二区 | 成人妖精视频yjsp地址 | 婷婷毛片 | 新久草 | 久久中文字幕一区 | 成人国产精品免费观看 | 亚洲精品在线视频网站 | 手机看片福利永久 | 伦乱视频| 成人午夜激情 |