COM--类厂
来源:互联网 发布:python实现支付宝登录 编辑:程序博客网 时间:2024/05/17 07:59
什么是类厂
类厂就是COM类的工厂,确切的说是对象厂,是对象的生产基地,com库通过类厂创建com对象。每一个com类有个专门用于该com类的对象创建操作。它支持一个特殊的接口IClassFactory:
class IClassFactory:public IUnknown{ virtual HRESULT _stdcall CreateInstance(IUnknown * pUnknownOuter,const IID& idd,void**ppv)=0; virtual HRESULT _stdcall LockServer(BOOL bLock)=0;};其中CreateInstance 用于创建对应的COM对象。LockServer用于控制组件的生命周期。
每一个com对象有一个相应的类厂对象,如果一个组件程序实现了多个com对象,则相应有多个类厂。如图:
因为类厂本身也是一个对象,它被用于其他com对象的创建过程。类厂对象由DllGetClassObject引出函数创建。DllGetClassObject不是com库函数,而是由组件程序实现的引出函数,函数原型如下:
HRESULT DllGetClassObject(const CLSID& clsid,const IID& iid,(void**)ppv);其中clsid是待创建对象的CLSID。iid和ppv分别用于指定接口IID和存放类厂接口指针。
COM库在接到对象创建的指令后,它要调用进程内组件的DllGetClassObject函数,由该函数创建类厂对象,并返回类厂对象的接口指针,com库或者客户一旦有了类厂对象的接口指针,他们就可以通过类厂接口IClassFactory的成员函数CreateInstance创建相应的COM对象。
COM库与类厂的交互
在COM库中有3个API用于对象的创建。CoGetClassObject CoCreateInstance CoCreateInstanceEx。通常情况下,客户程序调用其中之一完成对象的创建。并返回对象的初始接口指针。COM库与类厂也是通过这3个函数进行交互。
HRESULT CoGetClassObject(const CLSID& clsid,DWORD dwClsContext,COSERVERINFO*pServerInfo,const IID&iid,(void**)ppv);CoGetClassObject 函数首先找到由clsid指定的COM类的类厂,然后连接到类厂对象,如果需要的,CoGetClassObject函数装入组件代码。
如果,COM对象是进程内组件对象的话,则CoGetClassObject调用Dll模块中的DllGetClassObject引出函数,把参数clsid、iid、ppv传给DllGetClassObject,由DllGetClassObject创建类厂,并返回类厂对象接口指针。
HRESULT CoCreateInstance(const CLSID& clsid,IUnknown * pUnknownOuter,DWORD dwClsContext,const IID&iid,(void**)ppv);CoCreateInstance 是一个被包装过的辅助函数,在他的内部实际上也调用了CoGetClassObject ,其参数clsid,dwClsContext、idd、和ppv的含义与CoGetClassObject的函数一致,参数pUnknownOuter与类厂接口的CreateInstance对对应参数一致,用于对象聚合。CoCreateInstance 函数把通过类厂对象创建对象的过程封装起来,客户程序只需要指定对象类的CLSID和待输出的接口指针及接口ID,函数返回后,客户就可以得到对象的接口指针,客户程序可以不与类厂打交道,下面是CoGetClassObject的一种实现
HRESULT CoCreateInstance(const CLSID& clsid,IUnknown *pUnknownOuter,DWORD dwClsContext,const IID& iid,void **ppv){ IClassFactory *pCF; HRESULT hr; hr=CoGetClassObject(clsid,dwClsContext,NULL,IID_IClassFactory,(void*)pCF); if(FAILUE(hr)) return hr; hr=pCF->CreateInstance(pUnknownOuter,iid,(void*)ppv); pCF->Release(); return hr;}CoCreateInstance函数首先利用CoGetClassObject函数创建类厂对象,然后用得到类厂对象的接口指针创建真正的com对象。最后把类厂对象释放掉并返回。
在COM对象创建过程中,客户程序、COM库和进程内的组件程序三者之间的顺序关系如下:
- CoCreateInstance调用CoGetClassObject函数;
- COM库找到DLL程序并进入进程;
- 调用DllGetClassObject函数;
- DllGetClassObject函数创建类厂;
- DllGetClassObject函数把类厂接口指针返回给CoGetClassObject函数;
- CoGetClassObject函数把类厂接口指针返回给CoCreateInstance;
- CoCreateInstance函数得到类厂后,调用类厂的对象创建函数;
- 类厂创建COM对象;
- 类厂把COM对象返回给CoCreateInstance函数,CoCreateInstance函数返回;
- 客户直接调用COM对象。
类厂的实现
由于类厂是一个支持IClassFactory接口的com对象,所以类厂的C++定义(以字典程序为例):class CDictionaryFactory:public IClassFactory{protected:ULONG m_Ref;public:CDictionaryFactory(void);~CDictionaryFactory(void);//IUnknown membersHRESULT QureyInterface(const IID& idd,void **ppv);ULONG AddRef();ULONG Release();//IClassFactory memberHRESULT CreateInstance(IUnknown*,const IID& iid,void **ppv);HRESULT LockServer(BOOL);};CDictionaryFactory的实现代码如下:
#include"stdafx.h"#include"factory.h"#include"dictcomp.h"extern ULONG g_LockNumber;extern ULONG g_DictionaryNumber;CDictionaryFactory:CDictionaryFactory(){m_Ref=0;}CDictionaryFactory::~CDictionaryFactory(){}HRESULT CDictionaryFactory::QueryInterface(const IID& iid,void ** ppv){if(iid==IID_IUnknown){*ppv=(IUnknown*)this;static_cast<IUnknow*>(*ppv)->AddRef();}else if (iid==IID_IClassFactory){*ppv=(IClassFactory*)this;static<IClassFactory*>(*ppv)->AddRef();}else{*ppv=NULL;return E_NOINSTANCE;}return S_OK;}ULONG CDictionaryFactory::AddRef(){m_Ref++;return (ULONG)m_Ref;}ULONG CDictionaryFactory::Release(){m_Ref--;if(m_Ref==0){delete this;return 0;}return (ULONG)m_Ref;}HRESULT CDictionaryFactory::CreateInstance(IUnknown* pUnknownOuter,const IID& iid,void ** ppv){CDictionary *pObj;HRESULT hr;*ppv=NULL;hr=E_OUTOFMEMORY;if(pUnknownOuter!=NULL){return CLASS_E_NOAGGREGATION; }//Create the object passing function to notify no destruction.pObj=new CDictionary();if(pObj==NULL){return hr;}hr=pObj->QueryInterface(iid,ppv);if(hr!=S_OK){g_Dictionary--;delete pObj;}return hr;}HRESULT CDictionaryFactory::LockServer(BOOL bLock){if(bLock)g_LockNumber++;elseg_LockNumber--;return NOERROR;}引出函数DllGetClassObject的实现方法:
extern "C" HRESULT _stdcall DllGetClassObject(const CLSID& clsid,const IID& iid,void** ppv){if(clsid==CLSID_Dcitionary{CDictionaryFactory *pFactory=new CDictionaryFactory;if(pFactory==NULL){return E_OUTOFMEMORY;}HRESULT result=pFactory->QueryInterface(iid,ppv);return result;}else{return CLASS_E_CLASSNOTAVAILABLE;}}函数首先判断CLSID是否为字典组件的clsid,如果是,则创建类厂对象并通过类厂对象的QureyInterface成员函数找到对应的接口,一般是IClassFactory接口,然后返回。
类厂对组件生存周期的控制
虽然类厂也是一个com对象,但我们通常只把它当做创建其他组件对象的手段。一般,客户程序或这com库只是在创建组件对象的时候才使用类厂对象的接口指针,创建完成后就把类厂对象丢弃掉,以后如果还要创建组件对象,可以再次获取类厂对象,所以,类厂对象并不被长久保存,只是在创建过程中被用到。
如果希望保留类厂的接口,在以后创建对象时继续使用,则需要一种机制锁定组件程序,即通过IClassFactory::LockServer来实现锁定或解锁。
0 0
- COM--类厂
- COM---类厂
- COM笔记-类厂
- Inside COM读书笔记-----类厂
- COM笔记-类厂
- COM技术内幕--类厂
- COM
- com
- COM+
- COM+
- com
- COM
- com
- COM
- COM
- COM
- COM
- COM
- 剑指offer(四)
- Java基础——集合Collection
- POJ 2752 Seek the Name, Seek the Fame(KMP)
- eclipse导入java和android sdk源码,帮助文档
- uboot移植之配置分析
- COM--类厂
- Unity3D通过对象池模式 管理场景中的元素
- Swift(十二、方法&下标脚本)
- 【分享】魔王的地下要塞1+2(デモニオン)【日文硬盘版】(带全CG存档+打开存档+1.03升级+SSG补丁)
- 快速开发平台为树型部件添加图标
- GFS、HDFS等分布式文件系统对比介绍
- Android Studio插件-Android Butterknife Zelezny
- Mapreduce不设置reduce,只执行map的输出结果
- 文件下载 Servlet实现