8.ATL实现简单的COM

使用MFC开发COM依赖MFC庞大的类库,开发的基于COM技术的ActiveX控件不利于在Web传输,因此微软推出了新的解决方案——ATL(Active Template Library),和基于简单封装和继承原理的MFC不同,ATL充分利用了C++泛型编程,开发的程序十分短小精悍。

本文主要讲在ATL中如何通过IDL编写COM,主要是为了讲在ATL中COM编写框架,了解整个结构,可以先参考实现,具体涉及的IDL、多线程、代理/存根等概念之后都会讲解


1.建立工程

建立一个ATL工程,所有都是默认设置

可以看到,ATL框架已经帮我们做的事情有

1.实现如下四个标准的COM加载和导出函数

DllCanUnloadNow    
DllGetClassObject   
DllRegisterServer   
DllUnregisterServer 

2.包含一个.idl命名的类型库文件,MIDL编译该idl文件生成的文件含义如下

AtlBaseCom_i.h 接口定义

AtlBaseCom_i.c 各种GUID定义

AtlBaseCom_p.h 代理实现

3.包含两个工程,工程名带PS后缀的为存根/代理代码。


2.新建组件对象

在工程名上左键选择添加类->ATL->简单ATL对象,填写组件对象名CoClass和接口名,其他的会自动生成。


下一步,如下,选择单线程自定义接口实现,不需要实现聚合



3.COM实现

同样是实现如下COM对象

此时我们切换到类视图上,在ICat接口上右键添加对应的方法,然后我们直接编辑idl来自动生成文件,打开idl发现当前idl如下:

import "oaidl.idl";
import "ocidl.idl";

[
	object,
	uuid(7D796BB3-E479-42C9-99F9-FC2189CF8E78),
	helpstring("ICat 接口"),
	pointer_default(unique)
]
interface ICat : IUnknown{
	[helpstring("方法SayHello")] HRESULT SayHello1([in] WCHAR* szWord);
};

[
	uuid(63CD81C0-FD49-4153-A6CF-56BC8BA97935),
	version(1.0),
	helpstring("CAnimalObject Type Library")
]
library AtlBaseComLib
{
	importlib("stdole2.tlb");

	[
		uuid(A0A0C1F6-B5F4-42D1-80A2-C4D47B99DC2D),
		helpstring("AnimalObject 组件对象")
	]
	coclass CAnimalObject
	{
		[default] interface ICat;
	};
};
可以看到,这里定义了ICat接口,AtlBaseComLib类型库,CAnimalObject组件对象。

此时编译工程,可以查看到生成的文件

AtlBaseCom_i.h 接口定义

AtlBaseCom_i.c 各种GUID定义

所有的事情都帮我们做好了,我们只需要实现对应接口即可。


常用的IDL命令参考MSDN这里


我们手动添加上IDog接口,整个IDL如下:

import "oaidl.idl";
import "ocidl.idl";

[
	object,
	uuid(7D796BB3-E479-42C9-99F9-FC2189CF8E78),
	helpstring("ICat 接口"),
	pointer_default(unique)
]
interface ICat : IUnknown{
	[helpstring("方法SayHello")] HRESULT SayHello1([in] WCHAR* szWord);
};

[
	uuid(4BF862D3-6677-46AB-AA0A-59012ACBAC10),
	version(1.0),
	helpstring("IDog 接口")
]
interface IDog : IUnknown{
	[helpstring("方法SayHello")] HRESULT SayHello2([in] WCHAR* szWord);
};

[
	uuid(63CD81C0-FD49-4153-A6CF-56BC8BA97935),
	version(1.0),
	helpstring("CAnimalObject Type Library")
]
library AtlBaseComLib
{
	importlib("stdole2.tlb");

	[
		uuid(A0A0C1F6-B5F4-42D1-80A2-C4D47B99DC2D),
		helpstring("AnimalObject 组件对象")
	]
	coclass CAnimalObject
	{
		[default] interface ICat;
		interface IDog;
	};
};
编译后,我们实现对应的接口如下即可,就是这么简单!

HRESULT STDMETHODCALLTYPE CCAnimalObject::SayHello1(WCHAR *szWord)
{
	wcout << L"喵~ 猫大王发话: " << szWord << endl;
	return S_OK;
}

HRESULT STDMETHODCALLTYPE CCAnimalObject::SayHello2(WCHAR *szWord)
{
	wcout << L"汪~ 狗大王发话: " << szWord << endl;
	return S_OK;
}

在需要使用组件对象时,拷贝生成的.h和.c文件以获得对应的接口定义。


4.ATL实现原理简介

下面大概说下ATL的实现原理,查看生成的代码,组件对象定义如下:

class ATL_NO_VTABLE CCAnimalObject :
	public CComObjectRootEx<CComSingleThreadModel>,
	public CComCoClass<CCAnimalObject, &CLSID_CAnimalObject>,
	public ICat,
	public IDog
{
public:
	CCAnimalObject()
	{
	}

DECLARE_REGISTRY_RESOURCEID(IDR_CANIMALOBJECT)

DECLARE_NOT_AGGREGATABLE(CCAnimalObject)

BEGIN_COM_MAP(CCAnimalObject)
	COM_INTERFACE_ENTRY(ICat)
	COM_INTERFACE_ENTRY(IDog)
END_COM_MAP()



	DECLARE_PROTECT_FINAL_CONSTRUCT()

	HRESULT FinalConstruct()
	{
		return S_OK;
	}

	void FinalRelease()
	{
	}

public:
	STDMETHOD(SayHello1)( WCHAR* szWord);
	STDMETHOD(SayHello2)( WCHAR* szWord);
};

OBJECT_ENTRY_AUTO(__uuidof(CAnimalObject), CCAnimalObject)
可以看到,这里继承了CComObjectRootEx和CComCoClass。

CComObjectRootEx继承自CComObjectRootBase,CComObjectRootBase实现基本的AddRef/Release/QueryInterface,CComObjectRootEx指定对应的线程模型。


CComCoClass包含具体的工厂类实现。

OBJECT_ENTRY_AUTO指定具体的工厂类对象。


DECLARE_REGISTRY_RESOURCEID指明了组件对象的注册信息,对应在.rgs文件中的描述。


DECLARE_NOT_AGGREGATABLE定义了CComCreator2,CComCreator2支持指定聚合和非聚合时的创建者CComCreator。工厂类调用CComCreator2创建组件对象

CComCreator包装CComObject<CAnimalObject>,实现安全的创建。

DECLARE_PROTECT_FINAL_CONSTRUCTFinalConstruct是为了支持多步构造,可在FinalConstruct中做自己的创建工作,并据此返回创建是否成功。FinalConstruct在CComCreator中调用。

CComObject完成了实际的AddRef/Release/QueryInterface调用。这里实现QueryInterface时查询BEGIN_COM_MAP和END_COM_MAP中指定的接口表。


组件对象析构时会调用FinalRelease.

详细的过程分析可参考《深入解析ATL》


本文完整演示代码下载链接

原创,转载请注明来自http://blog.csdn.net/wenzhou1219


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值