Com库中包含一个创建组件的名为CoCreateInstance的函数。声明是:
HRESULT _stdcall CoCreateInstance(
Const CLSID& clsid,
IUnknown* pIUnknownOuter,
DWORD dwClsContext,
Const IID& iid,
Void **ppv
);
第一个参数是待创建组件的CLSID,第二个参数是用于聚合组件的,第八章介绍。第三个参数是限定所创建的组件的执行上下文的,第四个参数为组件上待使用的接口的IID,最后一个参数返回此接口的指针。
第三个参数指定的上下文可以是下列值的组合:
1. CLSCTX_INPROC_SERVER:客户希望创建在同一进程中运行的组件。
2. CLSCTX_INPROC_HANDLER:
3. CLSCTX_LOCAL_SERVER:本地EXE服务组件
4. CLSCTX_REMOTE_SERVER:远程EXE服务组件
CoCreateInstance实际上并没有直接创建COM组件,而是创建了一个称为类厂的组件。类厂组件的唯一功能是创建其它组件。一个类厂组件可以对应多种普通COM组件,但每个类厂组件的实例只能创建一种COM组件。
COM库中CoGetClassObject可以获得类厂接口的指针。声明如下:
HRESULT _stdcall CoGetClassObject(
Const CLSID& clsid,
DWORD dwClsContext,
COSERVERINFO* pServerInfo,
Const IID& iid,
Void **ppv);
ppv作为输出参数存放返回的类厂接口指针,类厂一般实现了IclassFactory指针。该接口继承自IUnknown,但多个两个方法:CreateInstance用来创建实际的COM对象,LockServer用来防止组件所在的dll被卸载。
IclassFactory::CreateInstance的声明是:
CreateInstance(IUnknown *PunknownOuter, const IID& iid, void **ppv);它接收一个接口GUID,返回该接口的指针。它并不接受组件的CLSID,所以一个类厂实例只能够创建一种COM组件,即传给CoGetClassObject的CLSID对应的组件。
在书上P109给出了CoCreateInstance是如何使用CoGetClassObject和IclassFactory::CreateInstance配合完成的。
1. 客户首先调用COM库的CoCreateInstance函数来创建COM组件。
2. CoCreateInstance首先调用COM库的CoGetClassObject获取类厂。
3. 该函数具体是通过调用了组件DLL输出的DllGetClassObject来创建类厂。
4. DllGetClassObject通过new函数产生一个Cfactory的对象,并通过QueryInterface获取其接口指针(一般是IclassFactory指针)。
5. 返回到COM库的CoCreateInstance调用刚才获得的接口指针(IclassFactory,类厂)的CreateInstance函数。
6. 该函数new指定的组件类,通过QueryInterface获得指定的接口
7. CoCrateInstanse释放掉IclassFactory指针(通过Release),然后向客户程序返回获得的指针。
8. 可以在客户中使用获得的接口了。
可以参考书的P111和p120的图。
在第6步中,根据不同的CLSID创建不同的组件,可以实现一个类厂供该DLL中多个组件共用。但只是类共用,不是实例共用。一旦在创建类厂时通过CoGetClassObject指定了CLSID,则只能创建该COM组件的实例。