您的位置:首页 > 其它

在MFC中实现自己的类厂

2011-09-02 10:36 309 查看
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,够省事的了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: