VS2012创建ATL工程及使用MFC测试COM组件

http://blog.csdn.net/pigautumn/article/details/43021085

一、创建ATL工程

1、创建ATL项目,取名为MyATL


2、在ATL项目向导中,勾选【支持MFC】(利用MFC测试用)、【支持 COM+ 1.0】和【支持部件注册器】,其余的选项默认,点击完成。


3、右键工程名称,选择添加类,接下来选择【ATL简单对象】。

4、在【ATL简单对象向导】对话框中填入下面内容(可更改为自己喜欢的类名称),然后直接点击完成。


5、切换到类视图,为刚刚添加的接口IMyATLClass添加方法。


6、现在来添加2个方法,分别用来计算两个数之和和弹出MFC对话框。



7、切换到【解决方案资源管理器】,可以看到SumPopupDialog的定义。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. interface IMyATLClass : IDispatch{  
  2.     [id(1)] HRESULT Sum([in] LONG para1, [in] LONG para2, [in] LONG* sum);  
  3.     [id(2)] HRESULT PopupDialog([in] CHAR* text);  
  4. };  

将参数[in] LONG* sum修改为[out] LONG* sum,表示这是一个需要输出的值。

8、打开MyATLClass.cpp,实现添加的两个方法。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. STDMETHODIMP CMyATLClass::Sum(LONG para1, LONG para2, LONG* sum)  
  2. {  
  3.     AFX_MANAGE_STATE(AfxGetStaticModuleState());  
  4.   
  5.     // TODO: 在此添加实现代码  
  6.     *sum = para1 + para2;  
  7.   
  8.     return S_OK;  
  9. }  
  10.   
  11. STDMETHODIMP CMyATLClass::PopupDialog(CHAR* text)  
  12. {  
  13.     AFX_MANAGE_STATE(AfxGetStaticModuleState());  
  14.   
  15.     // TODO: 在此添加实现代码  
  16.     AfxMessageBox((LPCTSTR)text);  
  17.   
  18.     return S_OK;  
  19. }  

9、生成该工程,得到MyATL.dll并在注册表中注册。

二、测试ATL组件

1、在上面的工程中添加测试项目。


2、添加用于测试的MFC工程TestATL

3、运行MFC应用程序向导,为简单起见,选择对话框工程,其余默认,点击完成。

4、将生成的对话框中【确定】、【取消】按钮修改如下。


5、双击上面的按钮,在系统生成的函数里删除掉代码CDialogEx::OnOK();如下。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void CTestATLDlg::OnBnClickedOk()  
  2. {  
  3.     // TODO: 在此添加控件通知处理程序代码  
  4.   
  5. }  
  6.   
  7. void CTestATLDlg::OnBnClickedCancel()  
  8. {  
  9.     // TODO: 在此添加控件通知处理程序代码  
  10.   
  11. }  

6、在TestATL工程中引入由MyATL工程中生成的“MyATL_i.h”、“MyATL_i.c”(这个文件主要用来查看CLSID_MyATLClassIID_IMyATLClass的值),并在TestATLDlg.cpp中添加MyATL_i.h的引用。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. #include "..\MyATL\MyATL_i.h"  

7、生成TestATL工程,会出现如下错误。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. 1>d:\projects\test\myatl\myatl\myatl_i.c : fatal error C1853: “Debug\TestATL.pch”预编译头文件来自编译器的早期版本,或者预编译头为 C++ 而在 C 中使用它(或相反)  

解决方法是右键“MyATL_i.c->属性->C/C++->预编译头,将“使用(/Yu)”修改为“不使用预编译头”。

再次生成TestATL就不会报错了。

8、实现Sum按钮的响应方法。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void CTestATLDlg::OnBnClickedOk()  
  2. {  
  3.     // TODO: 在此添加控件通知处理程序代码  
  4.     HRESULT hr = S_OK;  
  5.     hr = CoInitialize(NULL);  
  6.   
  7.     ITypeLib* pTypeLib = NULL;  
  8.     hr = ::LoadTypeLib(L"..\\Debug\\MyATL.dll", &pTypeLib); //加载并注册类型库  
  9.     if (FAILED(hr))  
  10.     {  
  11.         return;  
  12.     }  
  13.   
  14.     int nTypeInfoCount = pTypeLib->GetTypeInfoCount();  
  15.     if (nTypeInfoCount <= 0) //返回类型库中的类型说明的数量  
  16.     {  
  17.         return;  
  18.     }  
  19.   
  20.     ITypeInfo* pTypeInfo = NULL;  
  21.     TYPEATTR* pTypeAttr = NULL;  
  22.   
  23.     //!!!此处一定要注意导出类在.idl文件中的顺序!!!  
  24.     hr = pTypeLib->GetTypeInfo(2, &pTypeInfo);  
  25.     hr = pTypeInfo->GetTypeAttr(&pTypeAttr);  
  26.     CLSID clsid = pTypeAttr->guid;  
  27.   
  28.     hr = pTypeLib->GetTypeInfo(3, &pTypeInfo);  
  29.     hr = pTypeInfo->GetTypeAttr(&pTypeAttr);  
  30.     IID iid = pTypeAttr->guid;  
  31.   
  32.     IMyATLClass* pMyATLClass = NULL;  
  33.     hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, iid, (void **)&pMyATLClass);  
  34.     hr = CoCreateInstance(CLSID_MyATLClass, NULL, CLSCTX_INPROC_SERVER, IID_IMyATLClass, (void **)&pMyATLClass);  
  35.   
  36.     int sum = 0;  
  37.     pMyATLClass->Sum(2, 3, (LONG*)&sum);  
  38.   
  39.     pTypeInfo->ReleaseTypeAttr(pTypeAttr);  
  40.     pTypeInfo->Release();  
  41.     CoUninitialize();  
  42. }  

9、将TestATL设置为启动项,在CoCreateInstance设置断点跟踪调试。启动应用后,点击Sum按钮,进入断点,在监视窗口看到clsid、iid是和CLSID_MyATLClass、IID_IMyATLClass一一对应的,这就说明在调用pTypeLib->GetTypeInfo的时候,其参数值index是正确的。

10、注释掉含有CLSID_MyATLClass那一行对CoCreateInstance的调用,添加对Sum的测试代码,调试运行在监视窗口可以看到运算结果。

11、添加对Popup Dialog的测试,过程略,结果如下。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. pMyATLClass->PopupDialog("test ATL");  

考虑到编码问题,将MyATLClass.cpp中对PopupDialog的实现修改为:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. STDMETHODIMP CMyATLClass::PopupDialog(CHAR* text)  
  2. {  
  3.     AFX_MANAGE_STATE(AfxGetStaticModuleState());  
  4.   
  5.     // TODO: 在此添加实现代码  
  6.     CString str(text);  
  7.     AfxMessageBox((LPCTSTR)str);  
  8.   
  9.     return S_OK;  
  10. }  

重新生成MyATL,并启动TestATL测试如下。

12、再看pTypeLib->GetTypeInfo的调用。

程序中的调用是:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. hr = pTypeLib->GetTypeInfo(2, &pTypeInfo);  
  2. hr = pTypeInfo->GetTypeAttr(&pTypeAttr);  
  3. CLSID clsid = pTypeAttr->guid;  
  4.   
  5. hr = pTypeLib->GetTypeInfo(3, &pTypeInfo);  
  6. hr = pTypeInfo->GetTypeAttr(&pTypeAttr);  
  7. IID iid = pTypeAttr->guid;  

注意到其中index的值分别是23,表示第34个值。另外,

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. int nTypeInfoCount = pTypeLib->GetTypeInfoCount();  

nTypeInfoCount的值为4,这下就可以知道pTypeLib中前2TypeInfo并不是所期望的,而第34个才是我们需要的,为什么会这样?

再次找到MyATL工程中的MyATL.idl文件,找到library MyATLLib的定义,

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. library MyATLLib  
  2. {  
  3.     importlib("stdole2.tlb");  
  4.     [  
  5.         uuid(59E6B9BA-489E-417A-BCE9-2AFFE61F57D1)        
  6.     ]  
  7.     coclass CompReg  
  8.     {  
  9.         [default] interface IComponentRegistrar;  
  10.     };  
  11.     [  
  12.         uuid(03677350-0273-42BA-8F16-C7701493C1DC)        
  13.     ]  
  14.     coclass MyATLClass  
  15.     {  
  16.         [default] interface IMyATLClass;  
  17.     };  
  18. };  

可以看到首先定义的是CompReg这个类,它使得生成的dll完成了在注册表中的注册,并且它的两部分也正是pTypeLib->GetTypeInfo的前两部分,因此GetTypeInfoindex就变成了23

下面修改CompRegMyATLClass类定义的顺序,

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. library MyATLLib  
  2. {  
  3.     importlib("stdole2.tlb");  
  4.     [  
  5.         uuid(03677350-0273-42BA-8F16-C7701493C1DC)        
  6.     ]  
  7.     coclass MyATLClass  
  8.     {  
  9.         [default] interface IMyATLClass;  
  10.     };  
  11.     [  
  12.         uuid(59E6B9BA-489E-417A-BCE9-2AFFE61F57D1)        
  13.     ]  
  14.     coclass CompReg  
  15.     {  
  16.         [default] interface IComponentRegistrar;  
  17.     };  
  18. };  

在调用pTypeLib->GetTypeInfo的时候,将参数设置为01,这时候也会成功运行。

最后,我们知道了在library MyATLLib中类定义的顺序决定了GetTypeInfoindex参数的值,注意不到这个问题,如果在接口自动化中随意写index参数的值,就会一直找不到方向,白白浪费时间。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
COMComponent Object Model)是一种面向对象的组件化技术,常用于实现跨进程、跨机器的组件通信。C++可以使用COM组件来实现这种技术。 下面是使用C++创建使用COM组件的基本步骤: 1.定义组件接口:使用IDL(Interface Definition Language)语言定义组件接口,包括组件的方法、属性和事件等。 2.实现组件使用C++编写组件的实现代码,实现组件接口定义的方法、属性和事件等。 3.注册组件使用Windows系统提供的regsvr32工具将组件注册到系统,以便其他程序可以使用它。 4.使用组件:在其他程序通过COM接口调用组件的方法、属性和事件等。 以下是一个简单的示例,演示如何使用C++创建使用COM组件: 1.定义组件接口: ``` // MyComponent.idl import "oaidl.idl"; [ object, uuid(01234567-89ab-cdef-0123-456789abcdef), dual, helpstring("IMyComponent Interface"), pointer_default(unique) ] interface IMyComponent : IDispatch{ [id(1), helpstring("Method1")] HRESULT Method1([in] BSTR arg1, [out, retval] VARIANT* retVal); }; ``` 2.实现组件: ``` // MyComponent.h class ATL_NO_VTABLE CMyComponent : public CComObjectRootEx<CComSingleThreadModel>, public CComCoClass<CMyComponent, &CLSID_MyComponent>, public IDispatchImpl<IMyComponent, &IID_IMyComponent, &LIBID_MyComponentLib, /*wMajor =*/ 1, /*wMinor =*/ 0> { public: DECLARE_REGISTRY_RESOURCEID(IDR_MYCOMPONENT) DECLARE_NOT_AGGREGATABLE(CMyComponent) BEGIN_COM_MAP(CMyComponent) COM_INTERFACE_ENTRY(IMyComponent) COM_INTERFACE_ENTRY(IDispatch) END_COM_MAP() // IMyComponent methods public: STDMETHOD(Method1)(BSTR arg1, VARIANT* retVal); }; ``` ``` // MyComponent.cpp STDMETHODIMP CMyComponent::Method1(BSTR arg1, VARIANT* retVal) { // Do something here return S_OK; } ``` 3.注册组件: ``` regsvr32 MyComponent.dll ``` 4.使用组件: ``` // Client.cpp #include "MyComponent.h" int main() { CoInitialize(NULL); IMyComponentPtr pMyComponent; HRESULT hr = pMyComponent.CreateInstance(__uuidof(MyComponent)); if (SUCCEEDED(hr)) { VARIANT ret; hr = pMyComponent->Method1(L"arg1", &ret); if (SUCCEEDED(hr)) { // Do something with the returned VARIANT } } CoUninitialize(); return 0; } ``` 以上是一个简单的示例,演示了如何使用C++创建使用COM组件。实际应用,还需要考虑其他方面的问题,例如线程安全、错误处理等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值