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數據類型的宏定義。
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);
//=====================================================================