ATL实战开发指南-----2.5

当一个COM组件通过某一种语言设计并实现之后,他必须在一个操作系统的进程环境下运行。基于COM 的组件要么被包容在exe文件里面,要么被包容在一个Windows的动态链接库(DLL)。这两种包容方式是有区别的,组件开发者必须视情况来实现不同的函数,这里到底是哪些不同的函数,以后再讲。

下面我们将几个概念:

1 local server(本地服务器): COM组件被包容在exe文件中。也就是说该exe文件要支持COM组件,当然它也可以有其他的功能。

2.in-process server(进程内服务器): COM组件包含着DLL文件中。

3.remote server(远程服务器):它是在远程计算机上载入和执行的组件宿主文件。它通常是在一个可执行文件内部实现的。 

使用COM的一个好处是它为客户进程提供了位置透明性。上面我们讲了基于COM提供的服务可以在三种不同的配置中实现: 在本地机上通过FLL文件的进程内方式(in-process erver),在同一计算机(local server)上的跨线程方式, 在远程机上透过DLL文件和可执行文件的方式。然而客户并不需要了解组件实现或组件所处的位置。客户创建完组件的实例之后,COM将负责定位宿主文件和启动宿主文件的工作。

在决定如何实现你的组件,应考虑两个主要因素: 1 性能 2 客户程序的鲁棒性(robustness). 对于性能: 由于在进程内方式下组件是在客户进程的地址空间内执行,不要在方法参数之间进行进程间传递(marshaling),所以相较其他两种,它的性能是good。 对于鲁棒性: 若使用进程内方式实现组件包容,那么你有可能使用户自己的进程崩溃。而对进程外执行的组件(组件在exe中), 即使发生重大的错误,也不会使客户应用程序奔溃,因为它不在客户应用程序的地址空间中。

因为COM对象 可以位于进程空间之外, 并且必须要能被不同的语言访问,所以必须要提供一种与语言无关的方法来实例化一个组件。所以COM提供了一个标准化接口IClassFactory, 该接口是一个 必须实现 的构造器组件,使用它才能让外部客户可以创建自己的组件的实例。

class IClassFactory : public IUnknown
{
    virtual HRESULT CreateInstance( LPUNKNOWN pUnk, REFIID riid, void** ppv) = 0;
    virtual HRESULT LockServer(bool fLock) = 0;
};

 

基于COM的复用技术

两种方式复用组件的类对象: 包容(containment)和集合(aggregation).它们和C++中的复用技术非常相似,但是COM提供了二进制方式的复用,而不是C++所提供的编译时的要用。

那么什么是包容呢? 因为和C++相似的,那么它相当于(在C++)一个类作为另一个类的成员变量。被包容的组件的接口只能以间接的方式展示给外部用户。内部对象的生命周期完全受外部组件的控制。

集合: 与包容比较近似,但是集合里,内部的COM对象的接口可以直接由客户使用,就好象是它自己的接口一样。外部集合对象的IUnknow接口提供了对所有内部对象接口的访问。这一细节问题使集合的实现在有些时候变的复杂。对于外部对象和内部对象的生存期的管理必须通过IUnkown的实现来进行协调。具体细节以后再讲。

下面列出了一些COM api 函数:

// 初始化COM库以供进程使用, CoInitialize  仅支持apartment线程管理模型。而CoInitializeEx还可以支持另外3种类型:

//其中常用的COINT_MULTITHREADED   ---OLE 可以在任何线程调用对象

CoInitialize, CoInitializeEx  

CoUninitialize(client and server) // 当COM库提供的服务不再需要的时候使用。在进程内服务器上不能使用该函数。

 // 为一个指定的COM对象获取一个类工厂实例。若组件被包容在DLL中,COM系统会调用dll导出的DllGetClassObject函数来得到类工厂的接口,从而通过类工厂,得到一个 组件的实例。下面是通过CoGetClassObject 来实现的,若组件是包容在dll中,在其内部会调用DllGetClassObject., 在exe中,应该会调用CoRegisterClassObject.

	IMath* pMath = NULL;
	IClassFactory* pCF = NULL;
	//get the instance of MathClassFactory
	HRESULT hr = CoGetClassObject(CLSID_Math, CLSCTX_INPROC, NULL, IID_IClassFactory, &pCF);
	//get the instance of Math
	pCF->CreateInstance(NULL, IID_IMath, &pMath);

//若被包容在一个没有在运行的EXE文件中,COM将会载入该可执行文件,并等待服务器(组件自己)使用CoRegisterClassObject 注册它的类工厂。然后把接口

//返回给客户使用。CoRegisterClassObject 的原型基本上和DllGetClassObjec一样的。

在大多数情况下,客户应该使用CoCreateInstance 来创建组件实例。这里有3种例外情况:

//1. 应用程序需要多个组件对象的实例, 这样代码只需要一个类工厂就可以了。效率更高

	IMath* pMath1 = NULL;
	IMath* pMath2 = NULL;
	IMath* pMath3 = NULL;
	IClassFactory* pCF = NULL;
	//get the instance of MathClassFactory
	HRESULT hr = CoGetClassObject(CLSID_Math, CLSCTX_INPROC, NULL, IID_IClassFactory, &pCF);
	//get the instance of Math
	pCF->CreateInstance(NULL, IID_IMath, &pMath1);
	pCF->CreateInstance(NULL, IID_IMath, &pMath2);
	pCF->CreateInstance(NULL, IID_IMath, &pMath3);

// 2. 客户应用程序要求访问IClassFactory::LockServer方法,在内存中来锁定组件的宿主。这时也是出于性能考虑。

// 3.客户应用程序使用的创建技术里没有包含标准的IClassFactory接口。

CoGetClassObject (client) 

 

CoCreateInstance (client)  // 创建一个特定的COM对象实例,它可以位于远程计算机上

// 上面这个函数相当于以下代码:

IMath* pMath = NULL;
	IClassFactory* pCF = NULL;
	//get the instance of MathClassFactory
	HRESULT hr = CoGetClassObject(CLSID_Math, CLSCTX_INPROC, NULL, IID_IClassFactory, &pCF);
	//get the instance of Math
	pCF->CreateInstance(NULL, IID_IMath, &pMath);
    pCF->Release();

CoCreateInstanceEx (client) 

 

  // 为一个特定的COM对象的类工厂进行注册, 表明它的存在

CoRegisterClass (server)  

DllCanUnloadNow (in-process server)   // COM将定时调用它,用以决定DLL是否可以被下载。该函数由进程内服务器实现

DllGetClassObject (server)  // 入口点有进程内服务器实现,从而客户进程可以获得他的类工厂接口


所有的COM函数和标准接口方法都需要使用Unicode字符串,它用两个字节来存储一个字符。

ATL里面有两个ANSI和Unicode互相转换的宏: A2W ,W2A. 

char pa[10] = {'\0'};
wchar_t* pw = L"ni hao";
pa = W2A(pw);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值