zoukankan      html  css  js  c++  java
  • COM笔记-类厂

    CoCreateInstance实际上并没有直接创建COM组件 ,而是创建了一个被称作是类厂的组件。而所需的组件正是由些类厂创建的。类厂组件的唯一功能就创建其他的组件。创建组件的标准接口是IClassFactory,用CoCreateInstnce创建的组件实际上是通过IClassFactory创建的。

    类厂只是创建其它组件的一个简单组件。

    为了创建同某个CLSID相应的类厂,需要一个与CoCreateInstance等价的,也可以接收一个CLSID作为参数并把回相应类厂中某个接口指针的函数。这个函数就是COM库中的CoGetClassObject。

    CoGetClassObject声明:

    STDAPI CoGetClassObject(REFCLSID rclsid,

                  DWORD dwClsContext,

                  COSERVERINFO * pServerInfo,

                  REFIID riid,

                  LPVOID * ppv);

    区别1:CoGetClassObject同CoCreatInstance是非常相似的。只一个参数不同,CoCreatInstance将接收一个Iunknown指针,而CoGetClassObject则将接收一个COSERVERINFO指针。

    区别2:CoGetClassObject返回的是指向类厂中某个接口的指针(客户可以用这个指针来创建所需的组件),而CoCreateInstance返回的则是指向组件中某个接口的指针。

    IClassFactory:

    类厂所支持的用于创建组件的标准接口是IClassFactory。大多数组件均可使用IClassFactory接口来创建。

    interface IClassFactory : IUnknown

    {

        HRESULT _stdcall CreateInstance(IUnknown* pUnknownOuter,

                            const IID& iid,

                            void** ppv);

        HRESULT _stdcall LockServer(BOOL, bLock);

    };

    CreateInstance

    第一个参数为指向某个Iunknown接口的指针。在聚合再介绍。

    其它两个参数同传给QueryInterface的参数是相同的。

    CreateInstance并没有接收一个CLSID参数。这意味着些函数只能创建同某个CLSID(即传给CoGetClassObject的CLSID)相应的组件。

    IClassFactory2

    除了IClassFactory之外,Microsoft还定义了另外一个创建接口IClassFactory2,此接口在IClassFactory的基础上增加了许可或权限功能。此时,为使类厂能够创建所需的组件,客户必须通过IClassFactory2给类厂提供正确的关键字或许可。通过使用IClassFactory2,类厂可以保证客户只能获得它能合法访问的组件,并具有对此组件的访问授权。

    CoCreateInstance与CoGetClassObject 的比较

    在每次创建组件时,先创建相应的组件的类厂,然后用所获取的IClassFactory指针来创建所需的接口需要完成的工作显然比直接调用 CoCreateInstance来创建所需的组件要复杂一些。所以很多时候用CoCreateInstance来创建组件。但CoCreateInstance是能过CoGetClassObject实现的。

    HRESULT CoCreateInstance(const CLSID& clsid,

                  IUnknown* punkonwnDuter,

                  DWORD dwClsContext,

                  const IID& iid,

                  void** ppv)

    {

        // Set the out paameter to NULL

        *ppv = NULL;

        // Create the class factory

    // and get an IClassFactroy interface pointer.

        IClassFactory* pIFactory = NULL;

        HRESULT hr = CoGetClassObject(clsid,

                         dwClsContext,

                         NULL,

                         IID_IClassFactory,

                         (void**)&pIFactory);

        if (SUCCEEDED(hr))

        {

           // create the component.

           hr = pIFactory->CreateInstance(punkonwnDuter, iid, ppv);

           pIFactory->Release()();

        }

        return hr;

    }

    多数情况用CoCreateInstance,何时使用CoGetClassObject

    第一种情况:若想用不同于IClassFactory的某个创建接口创建组件,则必须使用CoGetClassObject。因此如果想使用IClassFactory2来创建组件,就应使用CoGetClassObject。

    第二种情况:若需要创建同一个组件的多个实例,那么使用CoGetClassObject将可以获得更高的效率。因为这样只需要创建相应的类厂一次,而CoCreateInstance使得客户可以对组件的创建过程进行更多控件。

    类厂的若干特性

    类厂的一个实例将只能创建同某个CLSID相应的组件。

    类厂和它所创建的组件是由同一个开发人员实现的。

    类厂就是需要知道如何创建相应的组件并将这一点封装起来,以便客户能够尽可能地同组件所具有的特殊需要分开。

    类厂的实现

    DllGetClassObject的使用

    CoGetClassObject需要DLL中一个特定函数来创建组件类厂。此函数的名称的为DllGetClassObject。

    STDAPI DllGetClassObject(const CLSID & rclsid, 

                  const IID & riid,     

                  void ** ppv);

    组件的创建过程

    (vs2008)代码下载

    本文地址:http://www.cnblogs.com/fangyukuan/archive/2010/06/12/1757417.htm

    回一楼:(因为写的东西比较多,就写在这里了)


    先看看CoCreateInstance(参数相关说明请看:COM笔记-CoCreateInstance和CoGetClassObject的参数。其中clsid和dwClsContext是由CoCreateInstance函数直接传给CoGetClassObject的。

    接着看CoGetClassObject:(参数请参考MSDN 

    HRESULT hr = CoGetClassObject(clsid,
    dwClsContext,
    NULL,
    IID_IClassFactory,
    (void**)&pIFactory);

    因为CoGetClassObject源代码没有公开,所以现在只能是看msdn和从它前后的代码以及用法来推测,它在里面做了什么事情。

    CoGetClassObject之前 

    (可以参考我们是怎么使用com组件的。)

     
    HRESULThr = CoInitialize(NULL);    //初始化COM
    if(SUCCEEDED(hr))
    {
    hr =CoCreateInstance(CLSID_kuan,
    NULL,
    CLSCTX_INPROC_SERVER,
    IID_Ikuan,
    (void **)&IkuanATL);
    if(SUCCEEDED(hr))
    {
          // 使用 接口IkuanATL
       }
    }
    CoUninitialize();//释放COM
     

    可以看到。CoInitialize初始化COM库后,就调用了CoCreateInstance,后面就是直接使用接口了。

    推断:所以有一件很重要的事CoCreateInstance要做。就是把实现com的DLL加载起来。

    CoGetClassObject之后

        if (SUCCEEDED(hr))
    {
    // create the component.
    hr = pIFactory->CreateInstance(punkonwnDuter, iid, ppv);
    pIFactory->Release()();
    }

    可见它已经得到组件的类厂接口。所以可以推断

    CoGetClassObject调用了DLL的导出函数DllGetClassObject。(参考图)

    STDAPI DllGetClassObject(const CLSID& clsid,
    const IID& iid,
    void** ppv);

     

    总结

      CoGetClassObject要加载DLL,但是我们并没有给他传递DLL的路径(DLL相关请参考DLL-使用DLL)。所以它要用参数clsid(即组件id,它是从CoCreateInstance传递过来的)去注册表找到这个组件DLL路径(请见:COM笔记-Widows注册表),然后把DLL加载起来。

           加载起来之后我们就可以调用DLL的导出函数DllGetClassObject。并把clsid(组件ID),IID_IclassFactory(接口ID)传递它。(可以看一下DllGetClassObject的实现,看看COM笔记-类厂源代码)。

      DllGetClassObject执行成功则返回类工厂接口pIFactory(见图)。

    接着就是 类工厂接口pIFactory 调用 它的方法CreateInstance,去创建我们需要的组件,并返回我们需要的接口了。(同样可以看看COM笔记-类厂源代码

      关于参数punkonwnDuter这个没用传递CoGetClassObject,而是传递给了类厂的一个方法CreateInstance,主要是聚合方面的东西。(见:COM笔记-包容与聚合

       参数dwClsContext限定所创建的组件的执行上下文。(见:COM笔记-CoCreateInstance

    com这东西就是绕来绕去。不知道我说清楚了没了。

  • 相关阅读:
    awk学习
    Redis快速入门
    Redis源码研究—基础知识
    稳定模式在RESTful架构中的应用
    解析Google集群资源管理系统Omega
    在Ubuntu 14.04 64bit上安装百度云Linux客户端BCloud
    在Ubuntu 14.04 64bit上安装Markdown和绘图软件Haroopad
    在Ubuntu 14.04 64bit上安装网易云音乐Linux版本(最新官方版)
    各数据库连接maven配置
    maven POM.xml 标签详解
  • 原文地址:https://www.cnblogs.com/bruce1992/p/14873410.html
Copyright © 2011-2022 走看看