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,够省事的了。