打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
ATL开发COM实现类厂和组件的创建框架调用过程
userphoto

2011.11.17

关注

类工厂的实现,组件的创建过程
1. 在*_Server.cpp 中有
BEGIN_OBJECT_MAP(ObjectMap)
    OBJECT_ENTRY(CLSID_Math, CMath)
END_OBJECT_MAP()

展开后是这样:

struct _ATL_OBJMAP_ENTRY30
{
    const CLSID* pclsid;
    HRESULT (WINAPI *pfnUpdateRegistry)(BOOL bRegister);
    _ATL_CREATORFUNC* pfnGetClassObject;
    _ATL_CREATORFUNC* pfnCreateInstance;
    IUnknown* pCF;
    DWORD dwRegister;
    _ATL_DESCRIPTIONFUNC* pfnGetObjectDescription;
    _ATL_CATMAPFUNC* pfnGetCategoryMap;
    void (WINAPI *pfnObjectMain)(bool bStarting);
};
static ATL::_ATL_OBJMAP_ENTRY ObjectMap[] =
{
    {
        &CLSID_Math,
        CMath::UpdateRegistry,
        CMath::_ClassFactoryCreatorClass::CreateInstance,
        CMath::_CreatorClass::CreateInstance,
        NULL,
        0,
        CMath::GetObjectDescription,
        CMath::GetCategoryMap,
        CMath::ObjectMain
    },
    {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}
};

定义了一个_ATL_OBJMAP_ENTRY 类型的全局数组变量 ObjectMap
然后在 Dll 被载入时用这个数组初始化全局的 _Module 变量
CComModule _Module;
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
{//......
    if (dwReason == DLL_PROCESS_ATTACH)
    {
        _Module.Init(ObjectMap, hInstance);
    }
}
inline HRESULT CComModule::Init(_ATL_OBJMAP_ENTRY* p, HINSTANCE /*h*/, const GUID* plibid) throw()
{//......
    m_pObjMap = p;
    _ATL_OBJMAP_ENTRY* pEntry = m_pObjMap;
    while (pEntry->pclsid != NULL)
    {
        pEntry->pfnObjectMain(true); //这里就是 CMath::ObjectMain //initialize class resources
        pEntry++;
    }
}
 


当用户代码中调用 CoCreateInstance 时
HRESULT hr = CoCreateInstance( CLSID_Math,
                                  NULL,
                                  CLSCTX_INPROC,
                                  IID_IMath,
                                  (void**) &pMath );

Dll 中的 DllGetClassObject 会被调用,最终调用 CMath::_ClassFactoryCreatorClass::CreateInstance 创建CMath组件
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
{
    return _Module.GetClassObject(rclsid, riid, ppv);
}
inline HRESULT CComModule::GetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) throw()
{
    _ATL_OBJMAP_ENTRY* pEntry = m_pObjMap;
    while (pEntry->pclsid != NULL)
    {
        if ((pEntry->pfnGetClassObject != NULL) && InlineIsEqualGUID(rclsid, *pEntry->pclsid))
        {
            //pEntry->pfnGetClassObject == CMath::_ClassFactoryCreatorClass::CreateInstance
            //pEntry->pfnCreateInstance == CMath::_CreatorClass::CreateInstance
            pEntry->pfnGetClassObject(pEntry->pfnCreateInstance, __uuidof(IUnknown), (LPVOID*)&pEntry->pCF);
            pEntry->pCF->QueryInterface(riid, ppv);
            break;
        }
        pEntry++;
    }
}


接下来看 CComCoClass 又是如何帮助实现 CMath::_ClassFactoryCreatorClass::CreateInstance 创建类厂的
class ATL_NO_VTABLE CMath :
   public CComObjectRootEx<CComSingleThreadModel>,
   public CComCoClass<CMath, &CLSID_Math>,
   //......
{
}
template <class T, const CLSID* pclsid = &CLSID_NULL> //T = CMath, pclsid = CLSID_Math
class CComCoClass
{
public:
    //DECLARE_CLASSFACTORY()
    //DECLARE_AGGREGATABLE(T)
    typedef ATL::CComCreator< ATL::CComObjectCached< ATL::CComClassFactory > > _ClassFactoryCreatorClass;
    typedef ATL::CComCreator2< ATL::CComCreator< ATL::CComObject< x > >, ATL::CComCreator< ATL::CComAggObject< x > > > _CreatorClass;
    typedef T _CoClass;
    template <class Q>
    static HRESULT CreateInstance(IUnknown* punkOuter, Q** pp)
    {
        return T::_CreatorClass::CreateInstance(punkOuter, __uuidof(Q), (void**) pp);
    }
};

可见在 CComCoClass 中有两个typedef的定义, 
_ClassFactoryCreatorClass 用于创建类厂
而 _CreatorClass用于创建组件实例
DllGetClassObject 最终调用了其中的 _ClassFactoryCreatorClass 的 CreateInstance函数创建类厂

将 _ClassFactoryCreatorClass 展开

//typedef ATL::CComCreator< ATL::CComObjectCached< ATL::CComClassFactory > > _ClassFactoryCreatorClass;
template <class T1> //T1 = ATL::CComObjectCached< ATL::CComClassFactory > 类厂
                    //T1 = ATL::CComCreator< ATL::CComObject< CMath > >, ATL::CComCreator< ATL::CComAggObject< CMath > > 组件
class CComCreator
{
public:
    static HRESULT WINAPI CreateInstance(void* pv, REFIID riid, LPVOID* ppv)
    {
        *ppv = NULL;
        HRESULT hRes = E_OUTOFMEMORY;
        T1* p =  new T1(pv)); //这里创建了组件或类厂
        if (p != NULL)
        {
            p->SetVoid(pv); //pv = CMath::_CreatorClass::CreateInstance
            p->InternalFinalConstructAddRef();
            hRes = p->_AtlInitialConstruct();
            if (SUCCEEDED(hRes))
                hRes = p->FinalConstruct();
            if (SUCCEEDED(hRes))
                hRes = p->_AtlFinalConstruct();
            p->InternalFinalConstructRelease();
            if (hRes == S_OK)
                hRes = p->QueryInterface(riid, ppv); //获取组件接口指针
            if (hRes != S_OK)
                delete p;
        }
        return hRes;
    }
};

DllGetClassObject 调用 
//pEntry->pfnGetClassObject(pEntry->pfnCreateInstance, __uuidof(IUnknown), (LPVOID*)&pEntry->pCF);
CMath::_ClassFactoryCreatorClass::CreateInstance (CMath::_CreatorClass::CreateInstance, __uuidof(IUnknown), (LPVOID*)NULL);

然后在这里面创建了类厂 :ATL::CComObjectCached< ATL::CComClassFactory >* p = new ATL::CComObjectCached< ATL::CComClassFactory >(pv));
最终获得类厂的接口 :p->QueryInterface(riid, ppv);

类厂类是ATL::CComClassFactory 它的定义
typedef HRESULT (WINAPI _ATL_CREATORFUNC)(void* pv, REFIID riid, LPVOID* ppv);
class CComClassFactory :
    public IClassFactory,
    public CComObjectRootEx<CComGlobalsThreadModel>
{
public:
    BEGIN_COM_MAP(CComClassFactory)
        COM_INTERFACE_ENTRY(IClassFactory)
    END_COM_MAP()
   
    STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void** ppvObj)
    {
        HRESULT hRes = E_POINTER;
        *ppvObj = NULL;
        if ((pUnkOuter != NULL) && !InlineIsEqualUnknown(riid)) //检查参数
        {
            ATLTRACE(atlTraceCOM, 0, _T("CComClassFactory: asked for non IUnknown interface while creating an aggregated object"));
            hRes = CLASS_E_NOAGGREGATION;
        }
        else
            hRes = m_pfnCreateInstance(pUnkOuter, riid, ppvObj);
        return hRes;
    }
    void SetVoid(void* pv) //pv = CMath::_CreatorClass::CreateInstance
    {
        m_pfnCreateInstance = (_ATL_CREATORFUNC*)pv;
    }
    _ATL_CREATORFUNC* m_pfnCreateInstance;
};


这里面有趣的是 SetVoid(void* pv) 它将 CMath::_CreatorClass::CreateInstance 传给了类厂指针成员变量 _ATL_CREATORFUNC* m_pfnCreateInstance

然后,在调用类厂 CreateInstance 创建对象实例时, 它会在检查参数后,调用 CMath::_CreatorClass::CreateInstance
那再看看 CMath::_CreatorClass::CreateInstance 会是如何实现创建组件实例
typedef ATL::CComCreator2< ATL::CComCreator< ATL::CComObject< x > >, ATL::CComCreator< ATL::CComAggObject< x > > > _CreatorClass;
template <class T1, class T2> //T1 = ATL::CComCreator< ATL::CComObject< CMath > >, T2 = ATL::CComCreator< ATL::CComAggObject< CMath > >
class CComCreator2
{
public:
    static HRESULT WINAPI CreateInstance(void* pv, REFIID riid, LPVOID* ppv)
    {
        ATLASSERT(ppv != NULL);
        return (pv == NULL) ?
            ATL::CComCreator< ATL::CComObject< CMath > >::CreateInstance(NULL, riid, ppv) :
            ATL::CComCreator< ATL::CComAggObject< CMath > >::CreateInstance(pv, riid, ppv);
    }
};

它会通过pv参数判断组件是否组合,然后选择相应的创建模板类

-------------------------------------------------------------------------------------------------------------
总结一下类厂和组件的创建过程

类厂创建过程:
1. 在*_Server.cpp 中定义CComModule _Module 全局变量和一个数组,里面填入组件创建的相关函数信息
CComModule _Module;
BEGIN_OBJECT_MAP(ObjectMap)
    OBJECT_ENTRY(CLSID_Math, CMath)
END_OBJECT_MAP()

2. Dll 加载时完成_Module的初始化
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID )
{
    if (dwReason == DLL_PROCESS_ATTACH)
    {
        _Module.Init(ObjectMap, hInstance);
    }
}
inline HRESULT CComModule::Init(_ATL_OBJMAP_ENTRY* p, HINSTANCE , const GUID* plibid) throw()
{
    m_pObjMap = p;
    //......
}

3. 用户调用 CoCreateInstance (末尾给出)时,dll导出函数 DllGetClassObject 会被调用
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
{
    return _Module.GetClassObject(rclsid, riid, ppv);
}
//rclsid = CLSID_Math
inline HRESULT CComModule::GetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) throw()
{//......
    _ATL_OBJMAP_ENTRY* pEntry = m_pObjMap;
    while (pEntry->pclsid != NULL)
    {
        if ((pEntry->pfnGetClassObject != NULL) && InlineIsEqualGUID(rclsid, *pEntry->pclsid))
        {
            //pEntry->pfnGetClassObject == CMath::_ClassFactoryCreatorClass::CreateInstance
            //pEntry->pfnCreateInstance == CMath::_CreatorClass::CreateInstance
            hr = pEntry->pfnGetClassObject(pEntry->pfnCreateInstance, __uuidof(IUnknown), (LPVOID*)&pEntry->pCF);
            break;
        }
        pEntry++;
    }
}
 


4. DllGetClassObject 会导致 CMath::_ClassFactoryCreatorClass::CreateInstance 的调用
CMath::_ClassFactoryCreatorClass 类型是 CComCreator, 也就是 CComCreator::CreateInstance 被调用,创建了类厂
//typedef ATL::CComCreator< ATL::CComObjectCached< ATL::CComClassFactory > > _ClassFactoryCreatorClass;
template <class T1> //T1 = ATL::CComObjectCached< ATL::CComClassFactory > 类厂
class CComCreator
{//......
    static HRESULT WINAPI CreateInstance(void* pv, REFIID riid, LPVOID* ppv)
    {
        *ppv = NULL;
        HRESULT hRes = E_OUTOFMEMORY;
        T1* p =  new T1(pv)); //这里创建了类厂
        if (p != NULL)
        {
            p->SetVoid(pv); //pv = CMath::_CreatorClass::CreateInstance
            p->QueryInterface(riid, ppv); //获取组件接口指针
            //......
        }
    }
};

*********************************************************************************

组件的创建过程:
1. CComCreator::CreateInstance 创建类厂后,会调用 SetVoid(pv) 将组件创建的函数指针创给了类工厂
class CComClassFactory : //.....
{//.....
    void SetVoid(void* pv) //pv = CMath::_CreatorClass::CreateInstance
    {
        m_pfnCreateInstance = (_ATL_CREATORFUNC*)pv;
    }
    _ATL_CREATORFUNC* m_pfnCreateInstance;
};

2. 用户调用的 CoCreateInstance(末尾给出), 在成功创建类厂后,会调用类厂的 CreateInstance接口
class CComClassFactory : //.....
{//.....
    STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void** ppvObj)
    {
        HRESULT hRes = E_POINTER;
        *ppvObj = NULL;
        if ((pUnkOuter != NULL) && !InlineIsEqualUnknown(riid)) //检查参数
        {
            ATLTRACE(atlTraceCOM, 0, _T("CComClassFactory: asked for non IUnknown interface while creating an aggregated object"));
            hRes = CLASS_E_NOAGGREGATION;
        }
        else
            hRes = m_pfnCreateInstance(pUnkOuter, riid, ppvObj); //调用组件创建函数
        return hRes;
    }
    _ATL_CREATORFUNC* m_pfnCreateInstance; //m_pfnCreateInstance = CMath::_CreatorClass::CreateInstance
};

3. 类厂的 CreateInstance 会调用通过 SetVoid 获取的组件创建的函数指针, 也就是CMath::_CreatorClass::CreateInstance
//typedef ATL::CComCreator2< ATL::CComCreator< ATL::CComObject< CMath > >, ATL::CComCreator< ATL::CComAggObject< CMath > > > _CreatorClass;
template <class T1, class T2> //T1 = ATL::CComCreator< ATL::CComObject< CMath > >, T2 = ATL::CComCreator< ATL::CComAggObject< CMath > >
class CComCreator2
{
public:
    static HRESULT WINAPI CreateInstance(void* pv, REFIID riid, LPVOID* ppv)
    {
        ATLASSERT(ppv != NULL);
        return (pv == NULL) ?
            ATL::CComCreator< ATL::CComObject< CMath > >::CreateInstance(NULL, riid, ppv) :
            ATL::CComCreator< ATL::CComAggObject< CMath > >::CreateInstance(pv, riid, ppv);
    }
};

4. CComCreator2 会通过检查pv参数,确定是创建组合对象还是非组合对象,最终还是通过 CComCreator 创建组件
//ATL::CComCreator< ATL::CComObject< CMath > >::CreateInstance(NULL, riid, ppv);
template <class T1> //T1 = ATL::CComCreator< ATL::CComObject< CMath > > 或 ATL::CComCreator< ATL::CComAggObject< CMath > > 创建组件                   
class CComCreator
{//.....
    static HRESULT WINAPI CreateInstance(void* pv, REFIID riid, LPVOID* ppv)
    {
        *ppv = NULL;
        HRESULT hRes = E_OUTOFMEMORY;
        //ATL::CComObject< CMath > *p = new ATL::CComObject< CMath > (pv);
        T1* p =  new T1(pv)); //这里创建了组件或类厂
        //.....
        hRes = p->QueryInterface(riid, ppv); //获取组件接口指针
        return hRes;
    }
};

到此,组件创建完成。


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;
}
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
COM聚合
COM调用过程
COM技术初探
理解Filter创建的过程
如何删除Internet临时文件
URLDownloadToCacheFile的疑问
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服