com控件的幾種調用方法(C++)

首先控件必須註冊。


1、調用控件生成時的*.c和*.h文件,定義一個接口變量,創建實例
IMyDll  myInterFace = NULL;
myInterFace.CreateInstance( CLSID ); 
myInterFace.fun();
2、沒有控件生成時的*.c和*.h文件時,在代碼中添加#import "*.dll",通過#import "*.dll" 後,編譯時會自動生成com接口的包裝類,即生成了文件“*.tlh”和“*.tli”(一個聲明文件,一個實現文件)。可以調用生成文件裏面的接口 定義自己的接口變量,然後調用接口方法。
聲明接口變量時,可以用生成文件中已經定義的智能指針聲明,獲取GUIID時可以通過“__uuidof( COMLib::AppCom )”之類的方式,通過接口名稱或者類名稱就可以獲得IID或者CLSID了。


#import "AppCom.dll"
AppCOMLib::IAppComPtr  COMINS = NULL;
COMINS .CreateInstance( __uuidof( AppCOMLib::AppCom ) );

if (COMINS  == NULL){
return 0;
}
BSTR val= COMINS ->fun(); 


3、如果控件的註冊目錄不確定時,不能用#import "*.dll"時,只要控件已經註冊了,就自己寫封裝函數或者封裝內,不需要包含調用頭文件了。
通過IDispatch提供的“GetIDsOfNames”和“Invoke”方法,先以接口方法名稱爲參數調用通過GetIDsOfNames獲得ID,然後通過以ID爲參數調用Invoke方法即可實現接口方法的調用。


const CLSID CLSID_Ctrl = {0xa5a73ef8, 0xa623, 0x4ded, {0x89, 0x74, 0x71,0x7d, 0xbb, 0x9f, 0x19, 0x5c}};
const IID   IID_ICtrl = {0xa5c73ef8, 0xa733, 0x4ded, {0xs9, 0x74, 0x71,0x7d, 0xee, 0x6f, 0x19, 0x5c}};
IDispatch * pInter;
hr = CoCreateInstance(CLSID_Ctrl, NULL, CLSCTX_INPROC, IID,(void **)&pInter);       
if(SUCCEEDED(hr))
{
   hr = pInter->GetIDsOfNames(IID_NULL,szMember,2, LOCALE_SYSTEM_DEFAULT,dispid);/
   hr = pInter->Invoke(dispid[0],IID_NULL,LOCALE_SYSTEM_DEFAULT,DISPATCH_METHOD,&dispparams,NULL,NULL,NULL);
}
或者將:
 hr = pInter->GetIDsOfNames(IID_NULL,szMember,2, LOCALE_SYSTEM_DEFAULT,dispid);
 hr = pInter->Invoke(dispid[0],IID_NULL,LOCALE_SYSTEM_DEFAULT,DISPATCH_METHOD,&dispparams,NULL,NULL,NULL);
用“_com_dispatch_method”代替,如下:
BSTR _result = 0;
_com_dispatch_method(pInter, 0x10, DISPATCH_METHOD, VT_BSTR, (void*)&_result, NULL);  //0x10是接口方法ID
_bstr_t strRes = _bstr_t(_result, false);


4、如果遇到的是ocx控件,上面的方法創建實例都是成功的,但是調用接口方法時就失敗了,爲什麼了? 從ocx控件本身說起,這個控件是依賴於窗口的,
它的存在必須有一個窗口容器作爲它的載體,直接調用是不行的,那麼就得先創建窗體,然後在調用了。過程如下:

const IID IID_Ctrl =  {0xa5a73ef8, 0xa623, 0x4ded, {0x89, 0x74, 0x71,0x7d, 0xbb, 0x9f, 0x19, 0x5c}};
//AtlAxWin
HWND hWnd = CreateWindow(AtlAxWin, _T(CtrlCLSID), WS_SYSMENU, 100, 50, 800, 600, 0, 0, 0, 0);
AsertWnd(hWnd);
CAxWindow wndTest;
wndTest.Attach(hWnd);
AsertWnd(wndTest);
IDispatch*  ptr = NULL;
HRESULT hr = wndTest.QueryControl (IID_BjcaKeyCtrl, (void **)&ptr );
if ((hr!=S_OK) || ptr==NULL){
wndTest.DestroyWindow();
return FALSE ;  
}  

try
{
BSTR _result = 0;
_com_dispatch_method(ptr, 0x10, DISPATCH_METHOD, VT_BSTR, (void*)&_result, NULL);
_bstr_t strRes = _bstr_t(_result, false);
}
catch(_com_error &er)
{
wndTest.DestroyWindow();
return FALSE;  //函數調用失敗
}
wndTest.DestroyWindow();

上面的“AtlAxWin”是我定義的一個宏,表示窗口類型,不同的編譯版本下是不同的,我是跟到ATL底層創建窗口時纔看到,仿照ATL底層創建窗口的方法寫了上面的創建代碼。
可以仿照下面的定義自己擴充(_MSC_VER==1600,_MSC_VER==1500,_MSC_VER==1400,_MSC_VER==1310,_MSC_VER==1300),看自己的VS版本定義:
#if (_MSC_VER==1600)
#define AtlAxWin _T("AtlAxWin100")
#endif
#if (_MSC_VER==1500)
#define AtlAxWin _T("AtlAxWin90")
#endif
“CtrlCLSID”是控件的CLSID。

說明:ocx控件的界面拖放生成包裝類的方法沒有寫,這個方法很大衆,你懂的


=====================================================================

//附錄: _com_dispatch_method的幾種常用方法,數據格式可以自己參考com數據類型的宏定義。


//沒有返回值,帶一個BSTR的參數,L"\x0008"表示VT_BSTR。
inline HRESULT _MyCtrl::SetRecverData ( _bstr_t sCert ) {
    return _com_dispatch_method(this, 0xc, DISPATCH_METHOD, VT_EMPTY, NULL, 
        L"\x0008", (BSTR)sCert);
}

//返回值爲BSTR,不帶參數的實現
inline _bstr_t _MyCtrl::GetPass ( ) {
    BSTR _result = 0;
    _com_dispatch_method(this, 0xd, DISPATCH_METHOD, VT_BSTR, (void*)&_result, NULL);
    return _bstr_t(_result, false);
}


//返回值爲short,不帶參數的實現,如果是long型,用VT_I4
inline short _MyCtrl::GetValueLen ( ) {
    short _result = 0;
    _com_dispatch_method(this, 0xe, DISPATCH_METHOD, VT_I2, (void*)&_result, NULL);
    return _result;
}

//帶兩個參數的格式L"\x0008\x0002"表示傳入兩個參數,一個BSTR和一個short
_com_dispatch_method(pInter, SOF_GetCertInfo_ID, DISPATCH_METHOD, VT_BSTR, (void*)&_resultSN, L"\x0008\x0002", _resultCert, 2);  


//=====================================================================















































發佈了20 篇原創文章 · 獲贊 4 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章