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万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章