一、类厂:
作用:
COM库通过类厂来创建对象,每个COM类对应着有一个COM类厂来创建此COM类的对象。
并不是用户直接通过c++的new来实例化
优点:
使用类厂来创建对象,可以将所有客户创建的对象的接口统一(统一的方法创建不同类型的COM对象),实现位置透明
说明:
类厂本身也是一个COM对象,当然,类厂不需要其他的类厂创建了;
类厂有一个特殊的接口IClassFactory,该接口派生自IUnknown接口。
二、数学组件的类厂实现:
//IClassFactory接口必须继承自IUnknown接口
class IClassFactory: public IUnknown
{
public:
virtual HRESULT _stdcall CreateInstance(IUnknown *pUnkouter,REFIID riid,void **ppv) = 0;
//pUnkouter用于对象被聚合的情形,一般设置为NULL
//riid 指的COM创建完成后,客户应该得到的初始接口IID,IID_ISimpleMath等
//ppv来保存接口的指针
vitual HRESULT _stdcall LockServer(BOOL fLock) = 0;
//用来控制DLL组件的卸载
};
//IClassFactory属于抽象类,要实现什么类型的对象就需要派生什么类型的工厂类
//这里具体实现一个用来生成CMath类型对象的工厂
class CMathFactory:public IClassFactory //具体类继承自抽象类,多态性
{
public:
CMathFactory(); ~CMathFactory(); //构造和析构函数
//IUnknown接口成员函数 查询接口,他对IClassFactory 和IUnknown接口提供支持并返回接口指针
HRESULT _stdcall QueryInterface(const IID&iid , void **ppv);
//用来管理创建出对象的引用计数
ULONG _stdcall AddRef(); ULONG _stdcall Release();
HRESULT _stdcall CreateInstance(IUnknown *,const IID&iid,void **ppv);
//该函数是这里的重点,
HRESULT _stdcall LockServer(BOOL fLock);
//组件生存周期的控制
private:
ULONG m_Ref;
};
HRESULT CMathFactory::CreateInstance(IUnknown *pUnkouter,const IID&iid,void **ppv)
{
CMath *obj; //定义对象类的指针
HRESULT hr;
*ppv = NULL;
if(pUnkouter != NULL) return CLASS_E_NOAGGREGATION;
obj = new CMath(); //创建CMath类型对象
if(obj == NULL ) return hr;
hr = obj ->QueryInterface(iid,ppv); //得到COM对象的初始接口
if(hr != S_OK) delete obj;
return hr;
}
1.我们客户如何去获取一个工厂类对象呢?
一般普通的COM对象我们可以这样获取:
1.调用CoCreateInstance() 2.或者调用IClassFactory::CreateInstance()
COM规范规定对于工厂对象的总是调用CoGetClassObject创建
优点:
客户代码不需要关系它要创建的是哪种对象,进程内、外的差别由类对象管理
2.CoGetClassObject的工作流程:
1.客户调用CoGetClassObject函数
2.CoGetClassObject从系统的注册表中找到目标组件的路径和名称,然后把组件加载到内存
3.再调用组件程序的引出函数DllGetClassObject,该函数创建类厂接口对象并返回指针
3.通过类厂创建对象:
1.客户通过调用CoGetClassObject获得类厂对象的接口指针
2.用该指针调用类厂中的CreateInstance,创建COM对象并返回对象的接口指针。
三、客户通过COM库与组件程序的交互过程:
1.客户调用CoCreateInstance创建对象;
2.CoCreateInstance调用CoGetClassObject函数,
该函数通过注册表找到目标组件的路径和名称,加载到内存;
3.CoGetClassObject去调用DllGetClassObject函数创建类厂,并把类厂接口指针返回给CoGetClassObject
4.CoGetClassObject又将接口指针返回给CoCreateInstance
5.CoCreateInstance拿到接口指针去调用类厂的CreateInStance方法,创建COM对象
6.然后类厂将对象的接口指针返回给CoCreateInstance,CoCreateInstance最终将接口指针交付给客户
7.客户最终拿着接口指针来使用操作COM对象。
四、组件程序的装载和卸载:
前面说过,由于同一个对象可能被多次引用,为了保证对象能被使用后正确的释放,给每个对象加上引用计数的属性,保证对象的正确的声明周期。
那么组件程序的在内存中的生命周期是什么样的呢?
为什么要说这个问题,因为组件程序我们使用前是要将其加载到内存,使用完成后卸载出内存。
为了管理组件程序的生命周期:引入两个计数器
1.锁计数器
2.组件对象个数计数器
当以上两个计数器都 == 0时,组件将被卸载出内存。