VS2012创建ATL工程及使用MFC测试COM组件
2015-03-12 00:38
316 查看
/article/9757256.html
一、创建ATL工程
1、创建ATL项目,取名为MyATL
![](http://img.my.csdn.net/uploads/201501/22/1421912390_4534.png)
2、在ATL项目向导中,勾选【支持MFC】(利用MFC测试用)、【支持 COM+ 1.0】和【支持部件注册器】,其余的选项默认,点击完成。
![](http://img.my.csdn.net/uploads/201501/22/1421912390_8466.png)
3、右键工程名称,选择添加类,接下来选择【ATL简单对象】。
4、在【ATL简单对象向导】对话框中填入下面内容(可更改为自己喜欢的类名称),然后直接点击完成。
![](http://img.my.csdn.net/uploads/201501/22/1421912391_6970.png)
5、切换到类视图,为刚刚添加的接口IMyATLClass添加方法。
![](http://img.my.csdn.net/uploads/201501/22/1421912391_4783.png)
6、现在来添加2个方法,分别用来计算两个数之和和弹出MFC对话框。
![](http://img.my.csdn.net/uploads/201501/22/1421912417_1886.png)
![](http://img.my.csdn.net/uploads/201501/22/1421912417_8805.png)
7、切换到【解决方案资源管理器】,可以看到Sum和PopupDialog的定义。
[cpp] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
interface IMyATLClass : IDispatch{
[id(1)] HRESULT Sum([in] LONG para1, [in] LONG para2, [in] LONG* sum);
[id(2)] HRESULT PopupDialog([in] CHAR* text);
};
将参数[in] LONG* sum修改为[out] LONG* sum,表示这是一个需要输出的值。
8、打开MyATLClass.cpp,实现添加的两个方法。
[cpp] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
STDMETHODIMP CMyATLClass::Sum(LONG para1, LONG para2, LONG* sum)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// TODO: 在此添加实现代码
*sum = para1 + para2;
return S_OK;
}
STDMETHODIMP CMyATLClass::PopupDialog(CHAR* text)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// TODO: 在此添加实现代码
AfxMessageBox((LPCTSTR)text);
return S_OK;
}
9、生成该工程,得到MyATL.dll并在注册表中注册。
二、测试ATL组件
1、在上面的工程中添加测试项目。
![](http://img.my.csdn.net/uploads/201501/22/1421912418_7203.png)
2、添加用于测试的MFC工程TestATL。
3、运行MFC应用程序向导,为简单起见,选择对话框工程,其余默认,点击完成。
4、将生成的对话框中【确定】、【取消】按钮修改如下。
![](http://img.my.csdn.net/uploads/201501/22/1421912440_9844.png)
5、双击上面的按钮,在系统生成的函数里删除掉代码CDialogEx::OnOK();如下。
[cpp] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
void CTestATLDlg::OnBnClickedOk()
{
// TODO: 在此添加控件通知处理程序代码
}
void CTestATLDlg::OnBnClickedCancel()
{
// TODO: 在此添加控件通知处理程序代码
}
6、在TestATL工程中引入由MyATL工程中生成的“MyATL_i.h”、“MyATL_i.c”(这个文件主要用来查看CLSID_MyATLClass和IID_IMyATLClass的值),并在TestATLDlg.cpp中添加MyATL_i.h的引用。
[cpp] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
#include "..\MyATL\MyATL_i.h"
7、生成TestATL工程,会出现如下错误。
[cpp] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
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
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
void CTestATLDlg::OnBnClickedOk()
{
// TODO: 在此添加控件通知处理程序代码
HRESULT hr = S_OK;
hr = CoInitialize(NULL);
ITypeLib* pTypeLib = NULL;
hr = ::LoadTypeLib(L"..\\Debug\\MyATL.dll", &pTypeLib); //加载并注册类型库
if (FAILED(hr))
{
return;
}
int nTypeInfoCount = pTypeLib->GetTypeInfoCount();
if (nTypeInfoCount <= 0) //返回类型库中的类型说明的数量
{
return;
}
ITypeInfo* pTypeInfo = NULL;
TYPEATTR* pTypeAttr = NULL;
//!!!此处一定要注意导出类在.idl文件中的顺序!!!
hr = pTypeLib->GetTypeInfo(2, &pTypeInfo);
hr = pTypeInfo->GetTypeAttr(&pTypeAttr);
CLSID clsid = pTypeAttr->guid;
hr = pTypeLib->GetTypeInfo(3, &pTypeInfo);
hr = pTypeInfo->GetTypeAttr(&pTypeAttr);
IID iid = pTypeAttr->guid;
IMyATLClass* pMyATLClass = NULL;
hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, iid, (void **)&pMyATLClass);
hr = CoCreateInstance(CLSID_MyATLClass, NULL, CLSCTX_INPROC_SERVER, IID_IMyATLClass, (void **)&pMyATLClass);
int sum = 0;
pMyATLClass->Sum(2, 3, (LONG*)&sum);
pTypeInfo->ReleaseTypeAttr(pTypeAttr);
pTypeInfo->Release();
CoUninitialize();
}
9、将TestATL设置为启动项,在CoCreateInstance设置断点跟踪调试。启动应用后,点击Sum按钮,进入断点,在监视窗口看到clsid、iid是和CLSID_MyATLClass、IID_IMyATLClass一一对应的,这就说明在调用pTypeLib->GetTypeInfo的时候,其参数值index是正确的。
![](http://img.my.csdn.net/uploads/201501/22/1421912463_6011.png)
10、注释掉含有CLSID_MyATLClass那一行对CoCreateInstance的调用,添加对Sum的测试代码,调试运行在监视窗口可以看到运算结果。
![](http://img.my.csdn.net/uploads/201501/22/1421912463_4585.png)
11、添加对Popup Dialog的测试,过程略,结果如下。
[cpp] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
pMyATLClass->PopupDialog("test ATL");
![](http://img.my.csdn.net/uploads/201501/22/1421912463_2973.png)
考虑到编码问题,将MyATLClass.cpp中对PopupDialog的实现修改为:
[cpp] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
STDMETHODIMP CMyATLClass::PopupDialog(CHAR* text)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// TODO: 在此添加实现代码
CString str(text);
AfxMessageBox((LPCTSTR)str);
return S_OK;
}
重新生成MyATL,并启动TestATL测试如下。
![](http://img.my.csdn.net/uploads/201501/22/1421912492_9906.png)
12、再看pTypeLib->GetTypeInfo的调用。
程序中的调用是:
[cpp] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
hr = pTypeLib->GetTypeInfo(2, &pTypeInfo);
hr = pTypeInfo->GetTypeAttr(&pTypeAttr);
CLSID clsid = pTypeAttr->guid;
hr = pTypeLib->GetTypeInfo(3, &pTypeInfo);
hr = pTypeInfo->GetTypeAttr(&pTypeAttr);
IID iid = pTypeAttr->guid;
注意到其中index的值分别是2、3,表示第3、4个值。另外,
[cpp] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
int nTypeInfoCount = pTypeLib->GetTypeInfoCount();
中nTypeInfoCount的值为4,这下就可以知道pTypeLib中前2个TypeInfo并不是所期望的,而第3、4个才是我们需要的,为什么会这样?
再次找到MyATL工程中的MyATL.idl文件,找到library MyATLLib的定义,
[cpp] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
library MyATLLib
{
importlib("stdole2.tlb");
[
uuid(59E6B9BA-489E-417A-BCE9-2AFFE61F57D1)
]
coclass CompReg
{
[default] interface IComponentRegistrar;
};
[
uuid(03677350-0273-42BA-8F16-C7701493C1DC)
]
coclass MyATLClass
{
[default] interface IMyATLClass;
};
};
可以看到首先定义的是CompReg这个类,它使得生成的dll完成了在注册表中的注册,并且它的两部分也正是pTypeLib->GetTypeInfo的前两部分,因此GetTypeInfo的index就变成了2和3。
下面修改CompReg和MyATLClass类定义的顺序,
[cpp] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
library MyATLLib
{
importlib("stdole2.tlb");
[
uuid(03677350-0273-42BA-8F16-C7701493C1DC)
]
coclass MyATLClass
{
[default] interface IMyATLClass;
};
[
uuid(59E6B9BA-489E-417A-BCE9-2AFFE61F57D1)
]
coclass CompReg
{
[default] interface IComponentRegistrar;
};
};
在调用pTypeLib->GetTypeInfo的时候,将参数设置为0、1,这时候也会成功运行。
最后,我们知道了在library MyATLLib中类定义的顺序决定了GetTypeInfo中index参数的值,注意不到这个问题,如果在接口自动化中随意写index参数的值,就会一直找不到方向,白白浪费时间。
一、创建ATL工程
1、创建ATL项目,取名为MyATL
![](http://img.my.csdn.net/uploads/201501/22/1421912390_4534.png)
2、在ATL项目向导中,勾选【支持MFC】(利用MFC测试用)、【支持 COM+ 1.0】和【支持部件注册器】,其余的选项默认,点击完成。
![](http://img.my.csdn.net/uploads/201501/22/1421912390_8466.png)
3、右键工程名称,选择添加类,接下来选择【ATL简单对象】。
4、在【ATL简单对象向导】对话框中填入下面内容(可更改为自己喜欢的类名称),然后直接点击完成。
![](http://img.my.csdn.net/uploads/201501/22/1421912391_6970.png)
5、切换到类视图,为刚刚添加的接口IMyATLClass添加方法。
![](http://img.my.csdn.net/uploads/201501/22/1421912391_4783.png)
6、现在来添加2个方法,分别用来计算两个数之和和弹出MFC对话框。
![](http://img.my.csdn.net/uploads/201501/22/1421912417_1886.png)
![](http://img.my.csdn.net/uploads/201501/22/1421912417_8805.png)
7、切换到【解决方案资源管理器】,可以看到Sum和PopupDialog的定义。
[cpp] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
interface IMyATLClass : IDispatch{
[id(1)] HRESULT Sum([in] LONG para1, [in] LONG para2, [in] LONG* sum);
[id(2)] HRESULT PopupDialog([in] CHAR* text);
};
将参数[in] LONG* sum修改为[out] LONG* sum,表示这是一个需要输出的值。
8、打开MyATLClass.cpp,实现添加的两个方法。
[cpp] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
STDMETHODIMP CMyATLClass::Sum(LONG para1, LONG para2, LONG* sum)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// TODO: 在此添加实现代码
*sum = para1 + para2;
return S_OK;
}
STDMETHODIMP CMyATLClass::PopupDialog(CHAR* text)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// TODO: 在此添加实现代码
AfxMessageBox((LPCTSTR)text);
return S_OK;
}
9、生成该工程,得到MyATL.dll并在注册表中注册。
二、测试ATL组件
1、在上面的工程中添加测试项目。
![](http://img.my.csdn.net/uploads/201501/22/1421912418_7203.png)
2、添加用于测试的MFC工程TestATL。
3、运行MFC应用程序向导,为简单起见,选择对话框工程,其余默认,点击完成。
4、将生成的对话框中【确定】、【取消】按钮修改如下。
![](http://img.my.csdn.net/uploads/201501/22/1421912440_9844.png)
5、双击上面的按钮,在系统生成的函数里删除掉代码CDialogEx::OnOK();如下。
[cpp] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
void CTestATLDlg::OnBnClickedOk()
{
// TODO: 在此添加控件通知处理程序代码
}
void CTestATLDlg::OnBnClickedCancel()
{
// TODO: 在此添加控件通知处理程序代码
}
6、在TestATL工程中引入由MyATL工程中生成的“MyATL_i.h”、“MyATL_i.c”(这个文件主要用来查看CLSID_MyATLClass和IID_IMyATLClass的值),并在TestATLDlg.cpp中添加MyATL_i.h的引用。
[cpp] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
#include "..\MyATL\MyATL_i.h"
7、生成TestATL工程,会出现如下错误。
[cpp] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
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
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
void CTestATLDlg::OnBnClickedOk()
{
// TODO: 在此添加控件通知处理程序代码
HRESULT hr = S_OK;
hr = CoInitialize(NULL);
ITypeLib* pTypeLib = NULL;
hr = ::LoadTypeLib(L"..\\Debug\\MyATL.dll", &pTypeLib); //加载并注册类型库
if (FAILED(hr))
{
return;
}
int nTypeInfoCount = pTypeLib->GetTypeInfoCount();
if (nTypeInfoCount <= 0) //返回类型库中的类型说明的数量
{
return;
}
ITypeInfo* pTypeInfo = NULL;
TYPEATTR* pTypeAttr = NULL;
//!!!此处一定要注意导出类在.idl文件中的顺序!!!
hr = pTypeLib->GetTypeInfo(2, &pTypeInfo);
hr = pTypeInfo->GetTypeAttr(&pTypeAttr);
CLSID clsid = pTypeAttr->guid;
hr = pTypeLib->GetTypeInfo(3, &pTypeInfo);
hr = pTypeInfo->GetTypeAttr(&pTypeAttr);
IID iid = pTypeAttr->guid;
IMyATLClass* pMyATLClass = NULL;
hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, iid, (void **)&pMyATLClass);
hr = CoCreateInstance(CLSID_MyATLClass, NULL, CLSCTX_INPROC_SERVER, IID_IMyATLClass, (void **)&pMyATLClass);
int sum = 0;
pMyATLClass->Sum(2, 3, (LONG*)&sum);
pTypeInfo->ReleaseTypeAttr(pTypeAttr);
pTypeInfo->Release();
CoUninitialize();
}
9、将TestATL设置为启动项,在CoCreateInstance设置断点跟踪调试。启动应用后,点击Sum按钮,进入断点,在监视窗口看到clsid、iid是和CLSID_MyATLClass、IID_IMyATLClass一一对应的,这就说明在调用pTypeLib->GetTypeInfo的时候,其参数值index是正确的。
![](http://img.my.csdn.net/uploads/201501/22/1421912463_6011.png)
10、注释掉含有CLSID_MyATLClass那一行对CoCreateInstance的调用,添加对Sum的测试代码,调试运行在监视窗口可以看到运算结果。
![](http://img.my.csdn.net/uploads/201501/22/1421912463_4585.png)
11、添加对Popup Dialog的测试,过程略,结果如下。
[cpp] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
pMyATLClass->PopupDialog("test ATL");
![](http://img.my.csdn.net/uploads/201501/22/1421912463_2973.png)
考虑到编码问题,将MyATLClass.cpp中对PopupDialog的实现修改为:
[cpp] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
STDMETHODIMP CMyATLClass::PopupDialog(CHAR* text)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// TODO: 在此添加实现代码
CString str(text);
AfxMessageBox((LPCTSTR)str);
return S_OK;
}
重新生成MyATL,并启动TestATL测试如下。
![](http://img.my.csdn.net/uploads/201501/22/1421912492_9906.png)
12、再看pTypeLib->GetTypeInfo的调用。
程序中的调用是:
[cpp] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
hr = pTypeLib->GetTypeInfo(2, &pTypeInfo);
hr = pTypeInfo->GetTypeAttr(&pTypeAttr);
CLSID clsid = pTypeAttr->guid;
hr = pTypeLib->GetTypeInfo(3, &pTypeInfo);
hr = pTypeInfo->GetTypeAttr(&pTypeAttr);
IID iid = pTypeAttr->guid;
注意到其中index的值分别是2、3,表示第3、4个值。另外,
[cpp] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
int nTypeInfoCount = pTypeLib->GetTypeInfoCount();
中nTypeInfoCount的值为4,这下就可以知道pTypeLib中前2个TypeInfo并不是所期望的,而第3、4个才是我们需要的,为什么会这样?
再次找到MyATL工程中的MyATL.idl文件,找到library MyATLLib的定义,
[cpp] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
library MyATLLib
{
importlib("stdole2.tlb");
[
uuid(59E6B9BA-489E-417A-BCE9-2AFFE61F57D1)
]
coclass CompReg
{
[default] interface IComponentRegistrar;
};
[
uuid(03677350-0273-42BA-8F16-C7701493C1DC)
]
coclass MyATLClass
{
[default] interface IMyATLClass;
};
};
可以看到首先定义的是CompReg这个类,它使得生成的dll完成了在注册表中的注册,并且它的两部分也正是pTypeLib->GetTypeInfo的前两部分,因此GetTypeInfo的index就变成了2和3。
下面修改CompReg和MyATLClass类定义的顺序,
[cpp] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
library MyATLLib
{
importlib("stdole2.tlb");
[
uuid(03677350-0273-42BA-8F16-C7701493C1DC)
]
coclass MyATLClass
{
[default] interface IMyATLClass;
};
[
uuid(59E6B9BA-489E-417A-BCE9-2AFFE61F57D1)
]
coclass CompReg
{
[default] interface IComponentRegistrar;
};
};
在调用pTypeLib->GetTypeInfo的时候,将参数设置为0、1,这时候也会成功运行。
最后,我们知道了在library MyATLLib中类定义的顺序决定了GetTypeInfo中index参数的值,注意不到这个问题,如果在接口自动化中随意写index参数的值,就会一直找不到方向,白白浪费时间。
相关文章推荐
- VS2012创建ATL工程及使用MFC测试COM组件
- VS2012创建ATL工程及使用MFC测试COM组件
- 创建ATL工程及使用MFC测试COM组件
- VS2012创建ATL工程及使用MFC测试COM组件
- VS2010创建ATL工程及使用C++测试COM组件
- 创建ATL工程及使用C++测试COM组件
- VS2010创建ATL工程及使用C++测试COM组件
- 使用VS2010创建MFC工程,并添加VTK引用
- 用ATL和MFC来创建ActiveX控件应该使用哪个框架?
- vs2010 之后安装vs2012,原VS2010里的测试工程不能使用的解决方法
- 应该使用哪个框架?用ATL和MFC来创建ActiveX控件1
- 利用ATL创建com组件和如何在程序中使用组件的接口函数和设置接口的属性
- 使用android创建安卓项目工程或者创建安卓测试项目工程命令详解
- 关于VC60中创建MFC工程时, 使用了UNICODE选项后编译报错的解决方法
- ATL--创建简单的ATL之dll工程,添加类和类的接口并在MFC中调用
- 如何使用C++创建COM组件(ATL项目)
- 在 MFC 和 ATL 工程中使用动画GIF
- C++ VS 2008中ATL的创建,使用。并在C++项目以及C#项目中进行调用测试
- vs2010中创建DLL文件,并在另外一个工程中使用测试或使用它
- 用VS2012做MFC ActiveX控件并使用html、c#、c++测试容器