Chinaunix首页 | 论坛 | 博客
  • 博客访问: 194795
  • 博文数量: 90
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 0
  • 用 户 组: 普通用户
  • 注册时间: 2017-08-23 16:48
文章分类

全部博文(90)

文章存档

2015年(1)

2011年(21)

2010年(59)

2009年(9)

我的朋友

分类: C/C++

2010-07-14 10:30:12

CoCreateInstance中调用CoGetClassObject获得IClassFactory(IClassFactory2),IClassFactory2又调用自己的CreateInstance或CreateInstanceLic建立控件实例。这里面类厂(IClassFactory)起到了非常重要的作用,特别是在MFC中,所有的控件都派生自COleControl(COleControl又派生自CCmdTarget),而COleControl本身却没有实现任何的接口,包括IUnknown。所有的接口都在COleControl的包裹类中实现。因此这里的类厂还需要调用正确的函数来返回正确的IUnknown指针(这里一般会调用CCmdTarget的InternalQueryInterface而不是通常的QueryInterface,因为新建的COleControl实例指针本身并不是一个接口指针,不提供QueryInterface方法)。
在MFC中,IClassFactory由COleObjectFactory(或者COleObjectFactoryEx,其实是一样的)实现。其实COleObjectFactory本身也派生自CCmdTarget,也没有直接实现IClassFactory,而是由其包裹类XOleObjectFactory来实现的。
CoGetClassObject在注册表中找到正确的Dll后,就调用该Dll的DllGetClassObject来获得相应的类厂,在这里,MFC实现了DllGetClassObject,它搜索存在当前Dll模块中的COleObjectFactory列表,找到与所要求的类ID(CLSID)相对应的COleObjectFactory后,就调用COleObjectFactory(CCmdTarget)的InternalQueryInterface返回相应的IClassFactory2接口指针。
理论上讲应该可以完全撇开MFC的类厂机制,自己从头建一个类厂,自己实现DllGetClassObject。不过好象是没有什么必要的,我们完全可以从COleObjectFactory派生自己的类厂。只要在自己的这个类厂类(真别扭)中实现IClassFactory就可以了。
1.新建控件of
2.新建派生自COleObjectFactory的类CMyObjectFactory,并加入定义IClassFactory接口的宏,实现IClassFactory接口的代码和接口映射表,如下:
//MyObjectFactory.h
class CMyObjectFactory : public COleObjectFactoryEx 
{
public:
    void CreateErrorInfo();
    CMyObjectFactory(REFCLSID clsid, CRuntimeClass* pRuntimeClass,
        BOOL bMultiInstance, LPCTSTR lpszProgID) :
    COleObjectFactory(clsid, pRuntimeClass,    bMultiInstance, lpszProgID)
    {
    }
    virtual ~CMyObjectFactory();
    BEGIN_INTERFACE_PART(MyClassFactory, IClassFactory2)
        INIT_INTERFACE_PART(CMyObjectFactory, ClassFactory)
        STDMETHOD(CreateInstance)(LPUNKNOWN, REFIID, LPVOID*);
        STDMETHOD(LockServer)(BOOL);
        STDMETHOD(GetLicInfo)(LPLICINFO);
        STDMETHOD(RequestLicKey)(DWORD, BSTR*);
        STDMETHOD(CreateInstanceLic)(LPUNKNOWN, LPUNKNOWN, REFIID, BSTR,
            LPVOID*);
    END_INTERFACE_PART(MyClassFactory)
   DECLARE_INTERFACE_MAP()
};
//MyObjectFactory.cpp
BEGIN_INTERFACE_MAP(CMyObjectFactory, COleObjectFactoryEx)
    INTERFACE_PART(CMyObjectFactory, IID_IClassFactory, MyClassFactory)
    INTERFACE_PART(CMyObjectFactory, IID_IClassFactory2, MyClassFactory)
END_INTERFACE_MAP()
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CMyObjectFactory::~CMyObjectFactory()
{
}
STDMETHODIMP_(ULONG) CMyObjectFactory::XMyClassFactory::AddRef()
{
    METHOD_PROLOGUE_EX_(CMyObjectFactory, MyClassFactory)
    return pThis->InternalAddRef();
}
STDMETHODIMP_(ULONG) CMyObjectFactory::XMyClassFactory::Release()
{
    METHOD_PROLOGUE_EX_(CMyObjectFactory, MyClassFactory)
    return pThis->InternalRelease();
}
STDMETHODIMP CMyObjectFactory::XMyClassFactory::QueryInterface(
    REFIID iid, LPVOID* ppvObj)
{
    METHOD_PROLOGUE_EX_(CMyObjectFactory, MyClassFactory)
    return pThis->InternalQueryInterface(&iid, ppvObj);
}
STDMETHODIMP CMyObjectFactory::XMyClassFactory::CreateInstance(
    IUnknown* pUnkOuter, REFIID riid, LPVOID* ppvObject)
{
    return CreateInstanceLic(pUnkOuter, NULL, riid, NULL, ppvObject);
}
STDMETHODIMP CMyObjectFactory::XMyClassFactory::LockServer(BOOL fLock)
{
    METHOD_PROLOGUE_EX(CMyObjectFactory, MyClassFactory)
    ASSERT_VALID(pThis);
    SCODE sc = E_UNEXPECTED;
    TRY
    {
        if (fLock)
            AfxOleLockApp();
        else
            AfxOleUnlockApp();
        sc = S_OK;
    }
    END_TRY
    return sc;
}
STDMETHODIMP CMyObjectFactory::XMyClassFactory::GetLicInfo(
    LPLICINFO pLicInfo)
{
    METHOD_PROLOGUE_EX(CMyObjectFactory, MyClassFactory)
    ASSERT_VALID(pThis);
    BSTR bstr = NULL;
    pLicInfo->fLicVerified = pThis->IsLicenseValid();
    pLicInfo->fRuntimeKeyAvail = pThis->GetLicenseKey(0, &bstr);
    if (bstr != NULL)
        SysFreeString(bstr);
    return S_OK;
}
STDMETHODIMP CMyObjectFactory::XMyClassFactory::RequestLicKey(
    DWORD dwReserved, BSTR* pbstrKey)
{
    METHOD_PROLOGUE_EX(CMyObjectFactory, MyClassFactory)
    ASSERT_VALID(pThis);
    ASSERT(pbstrKey != NULL);
    *pbstrKey = NULL;
    if (pThis->IsLicenseValid())
    {
        if (pThis->GetLicenseKey(dwReserved, pbstrKey))
            return S_OK;
        else
            return E_FAIL;
    }
    else
        return CLASS_E_NOTLICENSED;
}
STDMETHODIMP CMyObjectFactory::XMyClassFactory::CreateInstanceLic(
    LPUNKNOWN pUnkOuter, LPUNKNOWN /* pUnkReserved */, REFIID riid,
    BSTR bstrKey, LPVOID* ppvObject)
{
    METHOD_PROLOGUE_EX(CMyObjectFactory, MyClassFactory)
    ASSERT_VALID(pThis);
    if (ppvObject == NULL)
        return E_POINTER;
    *ppvObject = NULL;
    if (((bstrKey != NULL) && !pThis->VerifyLicenseKey(bstrKey)) ||
        ((bstrKey == NULL) && !pThis->IsLicenseValid()))
        return CLASS_E_NOTLICENSED;
    // outer objects must ask for IUnknown only
    ASSERT(pUnkOuter == NULL || riid == IID_IUnknown);
    //这里加入消息框,以表示这是我的类厂
    MessageBox(NULL, "hello", NULL, MB_OK);
    // attempt to create the object
    CCmdTarget* pTarget = NULL;
    SCODE sc = E_OUTOFMEMORY;
    TRY
    {
        // attempt to create the object
        pTarget = pThis->OnCreateObject();
        if (pTarget != NULL)
        {
            // check for aggregation on object not supporting it
            sc = CLASS_E_NOAGGREGATION;
            if (pUnkOuter == NULL || pTarget->m_xInnerUnknown != 0)
            {
                // create aggregates used by the object
                pTarget->m_pOuterUnknown = pUnkOuter;
                sc = E_OUTOFMEMORY;
                if (pTarget->OnCreateAggregates())
                    sc = S_OK;
            }
        }
    }
    END_TRY
    // finish creation
    if (sc == S_OK)
    {
        DWORD dwRef = 1;
        if (pUnkOuter != NULL)
        {
            // return inner unknown instead of IUnknown
            *ppvObject = &pTarget->m_xInnerUnknown;
        }
        else
        {
            // query for requested interface
            sc = pTarget->InternalQueryInterface(&riid, ppvObject);
            if (sc == S_OK)
            {
                dwRef = pTarget->InternalRelease();
                ASSERT(dwRef != 0);
            }
        }
        if (dwRef != 1)
            TRACE1("Warning: object created with reference of %ld\n", dwRef);
    }
    // cleanup in case of errors
    if (sc != S_OK)
        delete pTarget;
    return sc;
}
这里的实现代码基本上都是从MFC的COleObjectFactory中拷过来的。只是在CreateInstanceLic方法中加了一个MessageBox。
3.现在要用我们的CMyObjectFactory来代替缺省的COleObjectFactory了。
a.我们先要定义几个宏,当然不用宏也可以,这里只是贪图方便罢了
#define BEGIN_MYOLEFACTORY(class_name) \
protected: \
    class class_name##Factory : public CMyObjectFactory \
    { \
    public: \
        class_name##Factory(REFCLSID clsid, CRuntimeClass* pRuntimeClass, \
            BOOL bMultiInstance, LPCTSTR lpszProgID) : \
                CMyObjectFactory(clsid, pRuntimeClass, bMultiInstance, \
                lpszProgID) {} \
        virtual BOOL UpdateRegistry(BOOL);
#define END_MYOLEFACTORY(class_name) \
    }; \
    friend class class_name##Factory; \
    static AFX_DATA class_name##Factory factory; \
public: \
    static AFX_DATA const GUID guid; \
    virtual HRESULT GetClassID(LPCLSID pclsid);
#define DECLARE_MYOLECREATE_EX(class_name) \
    BEGIN_MYOLEFACTORY(class_name) \
    END_MYOLEFACTORY(class_name)

在MFC中对应的是BEGIN_OLEFACTORY(class_name)和END_OLEFACTORY(class_name),因为MFC中的这些宏已经定死了控件的类厂必须派生自COleObjectFactory(前面我们提到在模块上存放的列表就是COleObjectFactory指针列表,所以必须派生自COleObjectFactory是很显然的),而COleObjectFactory实现IClassFactory是在它的包裹类中,我们并不能直接继承COleObjectFactory就可以轻松的自己实现IClassFactory了,如果在由BEGIN_OLEFACTORYT和END_OLEFACTORY宏对中间定义我们自己的IClassFactory实现,那就变成包裹类的包裹类了,整个别扭的很啊,只好改它的宏了,幸好这几个宏并不复杂。
b.注释掉DECLARE_OLECREATE_EX(COfCtrl),改成
    DECLARE_MYOLECREATE_EX(COfCtrl)
至于IMPLEMENT_OLECREATE_EX就不用改了,该怎样还怎样吧。
4.编译,测试吧。
将DECLARE_MYOLECREATE_EX改回DECLARE_OLECREATE_EX,再编译的话,就又用回缺省的COleObjectFactory,够省事的了。
 
阅读(2602) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~