在MFC中实现自己的类厂

来源:互联网 发布:买苹果电脑装windows 编辑:程序博客网 时间:2024/04/28 05:57
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,够省事的了。
原创粉丝点击