国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

COM---調度接口與自動化

2019-11-08 02:27:49
字體:
來源:轉載
供稿:網友

自動化服務器:實現了IDispatch接口的COM組件

自動化控制程序:通過IDispatch接口同自動化服務器進行通信的COM客戶。

IDispatch

通過COM接口提供的任何服務都可以通過IDispatch接口提供。有了IDispatch,COM可通過一個標準的接口提供它所支持的服務,而無需提供多個特定于服務的接口。

IDispatch將接受一個函數名,并執行它。

IDispatch定義 可以在編譯器的/Include目錄下找到IDispatch定義

interface IDispatch : IUnknown{ typedef [unique] IDispatch * LPDISPATCH; HRESULT GetTypeInfoCount( [out] UINT * pctinfo ); HRESULT GetTypeInfo( [in] UINT iTInfo, [in] LCID lcid, [out] ITypeInfo ** PPTInfo ); //讀取一個函數名稱并返回其調度ID,即DISPID HRESULT GetIDsOfNames( [in] REFIID riid, [in, size_is(cNames)] LPOLESTR * rgszNames, [in] UINT cNames, [in] LCID lcid, [out, size_is(cNames)] DISPID * rgDispId ); //為執行某個函數,自動化控制程序把DISPID傳給Invoke //Invoke的行為由受到的DISPID決定 [local] HRESULT Invoke( //控制程序待調用函數的DISPID [in] DISPID dispIdMember, //保留的,必須為IID_NULL [in] REFIID riid, //保存位置信息 [in] LCID lcid, //調用的函數是哪種類型 //DISPATCH_METHOD 常規函數 //DISPATCH_PROPERTYGET 獲取屬性的含 //DISPATCH_PROPERTYPUT 設置屬性的函數 //DISPATCH_PROPERTYPUTREF 通過引用設置屬性的函數 [in] Word wFlags, /* 傳給被調用函數的參數 typedef struct tagDISPPARAMS { 參數數組,只有那些能放入VARIANTARG結構中的類型才可以通過調度接口進行傳遞 VARIANTARG *rgvarg; DISPID *rgdispidNamedArgs; 命名參數的DISPID,對于C++永遠為NULL UINT cArgs; 數組中元素個數 UINT cNamedArgs; 命名參數個數,對于C++永遠為0 } DISPPARAMS; */ [in, out] DISPPARAMS * pDispParams, //用于保存Invoke所執行的函數或propget的結果 //對于沒有返回值的成員函數或propputs及propputrefs,為NULL //VARIANT是一個union結構,方便用相同的方式保存不同類型變量的值 [out] VARIANT * pVarResult, /* 若Invoke執行的函數或屬性遇到一個例外情況,此結構被填入關于例外的信息。 typedef struct FARSTRUCT tagEXCEPINFO { unsigned short wCode; // Error code. Unsigned short wReserved; // Reserved. BSTR bstrSource; // Exception source. BSTR bstrDescription; //Exception description. BSTR bstrHelpFile; // Help file path. Unsigned long dwHelpContext; // Help context ID. Void FAR* pvReserved; // Reserved. HRESULT (STDAPICALLTYPE FAR* pfnDeferredFillIn) // Pointer to a (struct tagEXCEPINFO FAR*); // function that // fills in help and // description info. SCODE scode; // Return value. } EXCEPINFO, FAR* LPEXCEPINFO; */ [out] EXCEPINFO * pExcepInfo, //若Invoke的返回值為DISP_E_PARAMNOTFOUND或DISP_E_TYPEMISMATCH //putArgErr保存與此錯誤相應的參數的索引 [out] UINT * puArgErr );

IDispatch的使用

HRESULT hr = OleInitialize(NULL);//得到應用程序的CLSIDwchar_tprogid[] = L"InsideCom.Cmpnt1";CLSID clsid;CLSIDFromProgID(progid, &clsid);//創建組件,得到IDispatch指針IDispatch *pDispach = NULL;CoCreateInstance(clsid, NULL,CLSCTX_INPROC_SERVER, IID_IDispatch,(void**)&pDispach);//得到調度函數Fx的DISPIDDISPID dispid;OLECHAR* name = L"Fx";pDispach->GetIDsOfNames( IID_NULL, //必須為IID_NULL &name, //函數名稱 1, //函數個數 GetUserDefaultLCID(), &dispid); //DISPID//函數Fx的參數DISPPARAMS dispparamsNoArgs = { NULL,NULL,0,0}pDispach->Invoke(dispid, //DISPID IID_NULL, //必須為IID_NULL GetUserDefaultLCID(), DISPATCH_METHOD, //方法 &dispparamsNoArgs, //方法參數 NULL, //結果 NULL, //例外 NULL); //錯誤索引

以上代碼可變成不用參數的任意調度函數,只需要向客戶詢問ProgID和待用函數的名稱即可。 Invoke的威力在于可以被一致地調用,任何組件只要實現了Invoke,均可以用相同的代碼使用它。

例外情形

用到Invoke的倒數第二個參數

EXCEPINFO excepinfo;HRESULT hr = pDispach->Invoke(...,&excepinfo);if(FAILED(hr)){ if(hr == DISP_E_EXCEPTION) { if(excepinfo.pfnDeferredFillIn != NULL) { (*(excepinfo.pfnDeferredFillIn))(&excepinfo); } cout<<"Exception information: "<<endl <<"Source: "<<excepinfo.bstrSource<<endl <<"Description: "<<excepinfo.bstrDescription<<ends; }}

調度接口

IDispatch::Invoke的一個實現所實現的函數集被稱作一個調度接口。 調度接口的一個圖示: 這里寫圖片描述

雙重接口

讓實現IDispatch::Invoke的COM組件繼承IDispatch而不是IUnkown。雙重接口也是一種調度接口,使得通過Invoke訪問的函數也能直接通過vtbl訪問。

這里寫圖片描述

示例

構造一個實現雙重接口的IX的組件。

//// Server.idl - IDL source for Server.dll//// This file will be processed by the MIDL compiler to// produce the type library (Server.tlb) and marshaling code.//// Interface IX[ object, uuid(32BB8326-B41B-11CF-A6BB-0080C7B2D682), helpstring("IX Interface"), pointer_default(unique), dual, oleautomation]interface IX : IDispatch{ import "oaidl.idl" ; HRESULT Fx() ; HRESULT FxStringIn([in] BSTR bstrIn) ; HRESULT FxStringOut([out, retval] BSTR* pbstrOut) ; HRESULT FxFakeError() ;} ;

客戶使用雙重接口連接到組件: 演示客戶如何調用FxStringIn

這里寫圖片描述 這里寫圖片描述

類型庫

COM中類型庫,是與語言無關的、適合于解釋性語言和宏編程語言的C++頭文件等價的,為程序的正常運行提供某種程度的保證。 類型庫將提供有關組件、接口、方法、屬性、參數及結構的類型信息。類型庫是一個二進制文件。

類型庫的創建

可用IDL、MIDL建立類型庫。 MIDL編譯server.def后,會生成server.tlb的類型庫。

關鍵語句是library,library之后的方括號中的內容都將被編譯到類型庫中。

//// Server.idl - IDL source for Server.dll//// This file will be processed by the MIDL compiler to// produce the type library (Server.tlb) and marshaling code.//// Interface IX[ object, uuid(32BB8326-B41B-11CF-A6BB-0080C7B2D682), helpstring("IX Interface"), pointer_default(unique), dual, oleautomation]interface IX : IDispatch{ import "oaidl.idl" ; HRESULT Fx() ; HRESULT FxStringIn([in] BSTR bstrIn) ; HRESULT FxStringOut([out, retval] BSTR* pbstrOut) ; HRESULT FxFakeError() ;} ;//// Component and type library descriptions//[ uuid(D3011EE1-B997-11CF-A6BB-0080C7B2D682), //GUID version(1.0), //版本號 helpstring("Inside COM, Chapter 11 1.0 Type Library") //幫助字符串]library ServerLib{ importlib("stdole32.tlb") ; // Component [ uuid(0C092C2C-882C-11CF-A6BB-0080C7B2D682), helpstring("Component Class") ] coclass Component //定義一個組件 { //具有IX接口的組件 //MIDL將編譯生成一個包含組件和IX的類型庫 //之所以包含組件,是因為coclass包含library語句 //之所以包含IX,是因為在library語句中引用了它 [default] interface IX ; } ;} ;

類型庫的分發

在生成了類型庫之后,既可以將其作為一個單獨的文件發行,也可以將其作為一個資源包含在EXE或DLL中,后者可簡化安裝過程。

類型庫的使用

首先應裝載并注冊類型庫。

//// 裝載并注冊類型庫//HRESULT CA::Init(){ HRESULT hr ; // Load TypeInfo on demand if we haven't already loaded it. if (m_pITypeInfo == NULL) { ITypeLib* pITypeLib = NULL ; // 從Windows注冊表中裝載指定的類型庫 // 返回ITypeLib接口類型的指針 hr = ::LoadRegTypeLib(LIBID_ServerLib, 1, 0, // Major/Minor version numbers 0x00, &pITypeLib) ; if (FAILED(hr)) { trace("LoadRegTypeLib Failed, now trying LoadTypeLib.", hr) ; // 如果注冊表中沒有,從硬盤上裝載 // Get the fullname of the server's executable. char szModule[512] ; DWORD dwResult = ::GetModuleFileName(CFactory::s_hModule, szModule, 512) ; // Split the fullname to get the pathname. char szDrive[_MAX_DRIVE]; char szDir[_MAX_DIR]; _splitpath(szModule, szDrive, szDir, NULL, NULL) ; // Append name of registry. char szTypeLibFullName[_MAX_PATH]; sprintf(szTypeLibFullName, "%s%s%s", szDrive, szDir, szTypeLibName) ; // convert to wide char wchar_t wszTypeLibFullName[_MAX_PATH] ; mbstowcs(wszTypeLibFullName, szTypeLibFullName, _MAX_PATH) ; // 從硬盤上裝載指定文件名稱的類型庫 // 裝載之后在注冊表中注冊 // 但若提供了一個完整的路徑名稱,不會注冊 hr = ::LoadTypeLib(wszTypeLibFullName, &pITypeLib) ; if(FAILED(hr)) { trace("LoadTypeLib Failed.", hr) ; return hr; } // 注冊類型庫 hr = RegisterTypeLib(pITypeLib, wszTypeLibFullName, NULL) ; if(FAILED(hr)) { trace("RegisterTypeLib Failed.", hr) ; return hr ; } } // 為了獲取某個組件或接口信息,將其CLSID或IID傳給 // GetTypeInfoOfGuid,會返回一個指向所需項目的ITypeInfo指針 hr = pITypeLib->GetTypeInfoOfGuid(IID_IX, &m_pITypeInfo) ; pITypeLib->Release() ; if (FAILED(hr)) { trace("GetTypeInfoOfGuid failed.", hr) ; return hr ; } } return S_OK ;}

注冊表中的類型庫

這里寫圖片描述

IDispatch接口的實現

前面通過GetTypeInfoOfGuid得到了ITypeInfo指針,此指針可用來實現IDispatch接口。

//// IDispatch implementation//HRESULT __stdcall CA::GetTypeInfoCount(UINT* pCountTypeInfo){ trace("GetTypeInfoCount call succeeded.") ; *pCountTypeInfo = 1 ; return S_OK ;}HRESULT __stdcall CA::GetTypeInfo( UINT iTypeInfo, LCID, // This object does not support localization. ITypeInfo** ppITypeInfo){ *ppITypeInfo = NULL ; if(iTypeInfo != 0) { trace("GetTypeInfo call failed -- bad iTypeInfo index.") ; return DISP_E_BADINDEX ; } trace("GetTypeInfo call succeeded.") ; // Call AddRef and return the pointer. m_pITypeInfo->AddRef() ; *ppITypeInfo = m_pITypeInfo ; return S_OK ;}HRESULT __stdcall CA::GetIDsOfNames( const IID& iid, OLECHAR** arrayNames, UINT countNames, LCID, // Localization is not supported. DISPID* arrayDispIDs){ if (iid != IID_NULL) { trace("GetIDsOfNames call failed -- bad IID.") ; return DISP_E_UNKNOWNINTERFACE ; } trace("GetIDsOfNames call succeeded.") ; HRESULT hr = m_pITypeInfo->GetIDsOfNames(arrayNames, countNames, arrayDispIDs) ; return hr ;}HRESULT __stdcall CA::Invoke( DISPID dispidMember, const IID& iid, LCID, // Localization is not supported. WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pvarResult, EXCEPINFO* pExcepInfo, UINT* pArgErr){ if (iid != IID_NULL) { trace("Invoke call failed -- bad IID.") ; return DISP_E_UNKNOWNINTERFACE ; } ::SetErrorInfo(0, NULL) ; trace("Invoke call succeeded.") ; HRESULT hr = m_pITypeInfo->Invoke( static_cast<IDispatch*>(this), dispidMember, wFlags, pDispParams, pvarResult, pExcepInfo, pArgErr) ; return hr ;}

異常的引發

1、組件中實現ISupportErrorInfo接口

class CA : public CUnknown, public IX, public ISupportErrorInfo{ ... ... // ISupportErrorInfo virtual HRESULT __stdcall InterfaceSupportsErrorInfo(const IID& riid) { return (riid == IID_IX) ? S_OK : S_FALSE ; } ... ...}

2、在IDispatch::Invoke實現中,在ITypeInfo::Invoke實現之前,調用SetErrorInfo(0, NULL)

HRESULT __stdcall CA::Invoke( DISPID dispidMember, const IID& iid, LCID, // Localization is not supported. WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pvarResult, EXCEPINFO* pExcepInfo, UINT* pArgErr){ if (iid != IID_NULL) { trace("Invoke call failed -- bad IID.") ; return DISP_E_UNKNOWNINTERFACE ; } ::SetErrorInfo(0, NULL) ; trace("Invoke call succeeded.") ; HRESULT hr = m_pITypeInfo->Invoke( static_cast<IDispatch*>(this), dispidMember, wFlags, pDispParams, pvarResult, pExcepInfo, pArgErr) ; return hr ;}

3、

HRESULT __stdcall CA::FxFakeError(){ trace("FxFakeError is faking an error.") ; // 創建異常信息對象 ICreateErrorInfo* pICreateErr ; // 當發生異常時,調用CreateErrorInfo // 獲取一個ICreateErrorInfo指針 HRESULT hr = ::CreateErrorInfo(&pICreateErr) ; if (FAILED(hr)) { return E_FAIL ; } // 使用ICreateErrorInfo指針填充關于錯誤的信息 // pICreateErr->SetHelpFile(...) ; // pICreateErr->SetHelpContext(...) ; pICreateErr->SetSource(L"InsideCOM.Chap11") ; pICreateErr->SetDescription( L"This is a fake error generated by the component.") ; IErrorInfo* pIErrorInfo = NULL ; hr = pICreateErr->QueryInterface(IID_IErrorInfo, (void**)&pIErrorInfo) ; if (SUCCEEDED(hr)) { // 將ICreateErrorInfo指針作為第2個參數傳過去 // 第1個參數是保留的,恒為0 ::SetErrorInfo(0L, pIErrorInfo) ; pIErrorInfo->Release() ; } pICreateErr->Release() ; return E_FAIL ;}
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 阜城县| 枞阳县| 克山县| 贵州省| 张北县| 文安县| 托克逊县| 福海县| 石城县| 辉南县| 襄樊市| 房产| 苏州市| 乳山市| 塘沽区| 枞阳县| 景洪市| 乡宁县| 连平县| 西盟| 贵阳市| 酉阳| 淮滨县| 正镶白旗| 桐城市| 苍南县| 上高县| 都匀市| 财经| 常德市| 茶陵县| 贵州省| 无锡市| 且末县| 锦屏县| 舒城县| 衡阳市| 舒城县| 集贤县| 柏乡县| 清镇市|