In CoCreateInstance, call CoGetClassObject to obtain IClassFactory (IClassFactory2), and IClassFactory2 call its own CreateInstance or CreateInstanceLic to create a control instance. Here, IClassFactory plays a very important role. Especially in MFC, all controls are derived from COleControl (COleControl and csf-target ), COleControl itself does not implement any interfaces, including IUnknown. All interfaces are implemented in the COleControl package class. Therefore, the class factory also needs to call the correct function to return the correct IUnknown pointer (here, the InternalQueryInterface of csf-target is generally called instead of the normal QueryInterface, because the newly created COleControl instance pointer is not an interface pointer, the QueryInterface method is not provided ).
In MFC, IClassFactory is implemented by COleObjectFactory (or COleObjectFactoryEx. In fact, COleObjectFactory itself is also derived from CCmdTarget, and does not directly implement IClassFactory, but is implemented by its package class XOleObjectFactory.
After CoGetClassObject finds the correct Dll in the registry, it calls the DllGetClassObject of the Dll to obtain the corresponding class factory. Here, MFC implements DllGetClassObject, it searches for the COleObjectFactory list in the current Dll module, finds the COleObjectFactory corresponding to the required class ID (CLSID), and then calls COleObjectFactory (c1_target) internalQueryInterface of returns the corresponding IClassFactory2 interface pointer.
In theory, we should be able to completely put aside the class factory mechanism of MFC, build a class factory from the ground up, and implement the DllGetClassObject. But it seems that there is no need. We can derive our own class factory from the COleObjectFactory. You only need to implement IClassFactory in your own factory class.
1. Create a control
2. Create a New CMyObjectFactory class derived from COleObjectFactory and add a macro defining the IClassFactory interface to implement the Code and interface ing table of the IClassFactory interface, as shown below:
// 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 );
// Add a message box to indicate that this is my factory
MessageBox (NULL, "hello", NULL, MB_ OK );
// Attempt to create the object
Csf-target * 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;
}
The implementation code here is basically copied from the COleObjectFactory of MFC. Only a MessageBox is added to the CreateInstanceLic method.
3. Now we need to use our CMyObjectFactory to replace the default COleObjectFactory.
A. We need to define several macros first. Of course we can use them without macros. This is just a convenient place to look.
# 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)
In MFC, BEGIN_OLEFACTORY (class_name) and END_OLEFACTORY (class_name) are matched ), because these macros in MFC have fixed the control's class factory, they must be derived from the COleObjectFactory (the list we mentioned earlier on the module is the COleObjectFactory pointer list, therefore, it is obvious that the COleObjectFactory must be derived from the COleObjectFactory. The COleObjectFactory implementation IClassFactory is in its package class. We cannot directly inherit the COleObjectFactory to implement IClassFactory on our own, if we define our own IClassFactory implementation in the middle of the in_olefactoryt and END_OLEFACTORY macros, it will become the package class. The whole awkwardly, so we have to change its macro, fortunately, these macros are not complex.
B. Comment out DECLARE_OLECREATE_EX (COfCtrl) and change it
DECLARE_MYOLECREATE_EX (COfCtrl)
As for IMPLEMENT_OLECREATE_EX, you don't need to change it. How can this problem be solved.
4. Compile and test it.
Change DECLARE_MYOLECREATE_EX back to DECLARE_OLECREATE_EX. After compilation, the default COleObjectFactory is used again, which is easy enough.