Com的相关概念学习,网上有很多资料,我也是一篇一篇的资料学习而来的,这里相关概念就不做赘述了。Com的学习,光看资料是不行的,虽然可能概念方面你都掌握了,但是给你个任务编写个Com组件,都不知道怎么去下手。博主也是看了几天的资料仍是一头雾水,最后查找相关的代码详解,才一步步知道怎么编程。但是网上相关的实例比较少,总结的详细的也就更少了。写这篇博客的目的是想把我学习的过程总结下,同时也把自己过程中遇到的问题和解决方法写下来方便以后查看。
ATL(ActiveX Template Library,活动模板库)是一套C++的模板库,利用它可以很方便地建立小型的、基于COM的组件,对COM组件的开发提供了最大限度的代码自动生成以及可视化的支持。模板是ATL的核心技术。
一、创建Com:
点击ok选择dll,Support options选择Support MFC 点击finish创建
系统会自动生成两个项目,其中结尾带PS的不做操作,具体什么作用没有具体研究
其中
为项目的生成文件,可以做具体的调用文件。源文件中有一个.idl文件为项目的信息文件,可以查看项目的注册键值。
右键项目添加一个ATL Simple Object类
进入类的创建界面,只需输入short name也就是类的名称,其他项自动添加
在生成的MyMath.h文件中如下代码
class ATL_NO_VTABLE CMyMath :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CMyMath, &CLSID_MyMath>,
public IDispatchImpl<IMyMath, &IID_IMyMath, &LIBID_ComTestLib, /*wMajor =*/ 1, /*wMinor =*/ 0>
为用ATL建立Com的派生类,CComObjectRootEx提供IUnknown实现方法和组件线程模型,包括管理引用计数,CComCoClass提供缺省积累行为和定义类工厂;IDispatchImpl是个类模版,提供IDispatch接口实现。
DECLARE_PROTECT_FINAL_CONSTRUCT()
HRESULT FinalConstruct()
{
return S_OK;
}
void FinalRelease()
{
}
public:
//方法和变量的声明位置
};
OBJECT_ENTRY_AUTO(__uuidof(MyMath), CMyMath)
public下是具体的方法和变量的声明,这是头文件中的。ATL提供了很好的创建方法机制,所以最好不要自己写,容易出错。
下面添加一个加法方法:
点击到Class View在当前项目中有个定义类的接口(I+方法名),我的为IMyMath,右键它有个添加方法,方法的返回值都是HRESULT。其中下方是定义方法的参数,in为输入参数,out为返回参数,返回参数都是为指针。
DECLARE_PROTECT_FINAL_CONSTRUCT()
HRESULT FinalConstruct()
{
return S_OK;
}
void FinalRelease()
{
}
public:
STDMETHOD(Add)(LONG num1, LONG num2, LONG* result);
STDMETHOD(Sub)(LONG num1, LONG num2, LONG* result);
STDMETHOD(mul)(LONG num1, LONG num2, LONG* result);
STDMETHOD(Div)(LONG num1, LONG num2, LONG* result);
};
public中声明了4个方法,切记不要随便改动函数构造,如果改了,不仅源文件和头文件里的需要改,在.idl文件中的也需要相应的修改。
在源文件中就可以做具体操作了:
STDMETHODIMP CCxMath::Add(LONG num1, LONG num2, LONG* result)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// TODO: Add your implementation code here
LONG lResult = num1 + num2;
*result = lResult;
return S_OK;
}
其中返回值,最好加一个中间参数,否则有的情况下多个调用时,某一处被释放了,其他就调用不到相应的值了。
好了,一个简单的Com就可以拉,生成就可以调用了。
二、com的调用
com的调用方法有很多种,下面是我用的其中一种
需要引用com生成的两个文件
#include “ComTest.h"
#include “ComTest_i.c“
CoInitialize(NULL);
IMyMath* pMath;
HRESULT hr;
hr = ::CoCreateInstance(CLSID_MyMath, NULL, CLSCTX_ALL, IID_IMyMath, (void**)&pMath);
if (SUCCEEDED(hr)&&pMath != NULL)
{
LONG l;
CString strNum1,strNum2;
GetDlgItem(IDC_EDIT1)->GetWindowText(strNum1);
GetDlgItem(IDC_EDIT2)->GetWindowText(strNum2);
//long s = _ttoi(strNum1);
//long ss = _ttoi(strNum2);
pMath->Add(_ttoi(strNum1),_ttoi(strNum2),&l);
CString strResult;
strResult.Format(L"%d",l);
GetDlgItem(IDC_EDIT3)->SetWindowText(strResult);
}
其他调用方法:
#include "ComTest.h"
#include "ComTest_i.c"
::CoInitialize( NULL );
IUnknown * pUnk = NULL;
IMyMath * pMath = NULL;
HRESULT hr;
hr = ::CoCreateInstance(CLSID_MyMath,NULL,
CLSCTX_INPROC_SERVER,IID_IUnknown,
(LPVOID *) &pUnk);
if( FAILED( hr ) )throw( _T(“组件没注册!") );
hr = pUnk->QueryInterface(IID_IMyMath,(LPVOID *)&pMath );
if( FAILED( hr ) )throw( _T("没有接口?") );
hr = pMath->Add( 1, 2, &nSum ); //调用组件函数
#include "ComTest.h"
#include "ComTest_i.c“
::CoInitialize( NULL );
CComPtr < IUnknown > spUnk;
CComPtr < IFun > spFun;
HRESULT hr;
hr = spUnk.CoCreateInstance( CLSID_Fun );
if( FAILED( hr ) ) throw( _T("没注册组件") );
hr = spUnk.QueryInterface( &spFun );
if( FAILED( hr ) ) throw( _T("没有接口") );
hr = spFun->Add( 1, 2, &nSum );
我就列举几种,其他的方法网上很多
在调用过程中,.h和.c文件必须同时调用,不然会出现很多未知的问题。
总结的有点乱,先写到这,以后有时间再更新新内容。