首先控件必须注册。
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。
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);
//=====================================================================
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);
//=====================================================================