COM programming with MFC in VC 6.0
2000-03-21 · Yang Ning · vchelp
First, it should be clear that the MFC is to implement the COM interface through the nested category rather than multiple inheritance, and the interface and implementation of the interface are associated with the nested classes that implement the interface; the MFC is provided with a simple macro to achieve nested Class definition. Second, the MFC implements an IUNKNOWN interface through the ccmdtarget class. This article first describes the steps and core code for creating a COM server. Then explain the customer critical code. This COM server implements a TimeLogServer component, which is only the same, this component is only An interface ITIMELOG, through ITIMELOG's method OutputLog can output log text to log files. Create a MFC DLL project, choose support Automation (Of course this program is not necessarily an automation server, this is here to do a few necessary Output functions such as DllgetClassObject, DllRegisterServer, etc., otherwise write) the first COM server. Declaration Components and interfaces 1. Write a guids.h, declare the components and interfaces in Guids.h Guid // Declaration Components Guid {a433E701 -E45E-11D3-97B5-52544CBA7F28}
// define_guid (CLSID_TIMELOGSERVER,
// 0xA433E701, 0XA45E, 0X11D3, 0x97, 0xB5, 0x52, 0x54, 0x4c, 0xBa, 0x7f, 0x28);
Static const Iid CLSID_TIMELOGSERVER =
{0xA433E701, 0xE45E, 0x11D3, {0x97, 0xB5, 0x52, 0x54, 0x4c, 0xba, 0x7f, 0x28}};
// Declaration interface guid {a433e702-E45E-11D3-97B5-52544CBA7F28}
// define_guid (IID_ITIMELOG,
// 0xA433E702, 0xA433E702, 0xE45E, 0X11D3, 0x97, 0xB5, 0x52, 0x54, 0x4c, 0xba, 0x7f, 0x28);
Static const same IID_ITIMELOG =
{0xA433E702, 0xE45E, 0x11D3, {0x97, 0xB5, 0x52, 0x54, 0x4c, 0xba, 0x7f, 0x28}};
2. Write a ITIMELOGSERVER.H, declared components and interfaces in ITIMELOGSERVER.H files //itimelogserver.h
#include "guids.h"
// Interface ITIMELOG declaration
Declare_Interface_ (ITIMELOG, IUNKNOWN)
{
STDMETHOD (OUTPUTLOG) PURE;
}
Description: 1. Macro Define_GUID associates the PROGID of the components and interfaces. You can use the Guidgen.exe tool. 2. Macro Declare_interface_ declared the interface; the first parameter is the interface name, the second parameter is the interface Base class. Declaring no base class interface with declare_interface macro. 3. Macro stdmethod declares how the method in the interface. The return value of this method is HRESULT.PURE is interpreted as "= 0", that is, this method is a pure virtual function. The return value of the method is not HRESULT, with macro STDMETHOD_ (return type, function name) pure; two. Declarative component class CTIMELOGSERVER and the nested class of the interface add new class CTimelogServer, the base class is selected as ccmdtarget Modify its header file TimelogServer1.h, plus #include "itimelogserver.h"; simultaneously add // declared the nested class of the ITIMELOG interface in the class declaration
Begin_Interface_part (TimeLog, ITIMELOG) // Automatically declares the three methods of the iUnknown interface stdmethod (outputlog) (BSTR * VARLOGTEXT);
END_INTERFACE_PART (TIMELO)
// Declaration Interface Map
Declare_interface_map ()
// Disclaimer
Declare_olecreate (CTimelogServer)
III. Implementation of class and interface mapping in CTimelogServer implementation files: // Implementation
Implement_olecreate (CTimelogServer, "TimelogServer",
0xA433E701, 0XE45E, 0x11D3, 0x97, 0xB5, 0x52, 0x54, 0x4c, 0xba, 0x7f, 0x28);
// Mapping the interface to the corresponding nested class
Begin_Interface_map (ctimelogserver, ccmdtarget)
Interface_part (CTimelogServer, IID_ITIMELOG, TIMELOG)
END_INTERFACE_MAP ()
Four. Counting the overall object count in the constructor and destructive function
CTimelogServer :: ctimelogserver ()
{
:: AfxoLockApp ();
}
CTimelogServer :: ~ ctimelogserver ()
{
:: AfxoleunlockApp ();
} V. IUNKNOWN interface / / for nested classes to implement iUnknown interface
STDMETHODIMP_ (ULONG)
CTimelogServer :: Xtimelog :: AddRef ()
{
Method_Prologue (CTimelogServer, Timelog)
Return PTHIS-> EXTERNALADDREF ();
}
STDMETHODIMP_ (ULONG)
CTimelogServer :: Xtimelog :: release ()
{
Method_Prologue (CTimelogServer, Timelog)
Return PTHIS-> EXTERNALRELEASE ();
}
StdMethodimp
CTimelogServer :: Xtimelog :: queryinterface (refiid riid, void ** ppvobj)
{
Method_Prologue (CTimelogServer, Timelog)
Return PTHIS-> ExternalQueryInterface (& RiID, PPVObj);
Note: Although the CCMDTARGET class has implemented an IUNKNOWN interface, it is also necessary to map the nested class's iUnknown to the iUnknown interface supported by the ccmdTarget. The two parameters of the Method_ProLogueh macro are the class and implementation of the interface. Nested classes. Six. Method for implementing the ITIMELOG interface Outputlog Note The function of this component is to enter the log file. 1. Add a file pointer to the component class: // attributes
PUBLIC:
protected:
FILE * M_LOGFILE;
2. Initializing and exiting first in the constructor of CTimelogServer: CTimelogServer :: CTimelogServer ()
{
:: AfxoLockApp ();
CTIME TIMESTAMP = CTime :: getcurrenttime ();
CSTRING FILENAME;
Filename.Format (_T ("% s.log"), timestamp.format ("% y% m% D"));
m_logfile = fopen (filename, _t ("a"));
IF (m_logfile) {
FPRINTF (M_Logfile, _T ("# # # # # # # # # # # / n"));
FPRINTF (M_Logfile, _T ("Start:% S"), (LPCTSTR) TimeStamp.Format ("% y year% M month% D days% H:% M% s"));
FPRINTF (m_logfile, _t ("/ n"));
}
}
/ / Then close the file in the destructor
CTimelogServer :: ~ ctimelogserver ()
{
:: AfxoleunlockApp ();
IF (m_logfile)
{
CTIME TIMESTAMP = CTime :: getcurrenttime ();
FPRINTF (m_logfile, _t ("/ n"));
FPRINTF (M_Logfile, _T ("end:% s"), (lpctstr) timestamp.format ("% y year% M month% D day% h:% m% s"));
FPRINTF (m_logfile, _t ("/ n"));
FPRINTF (M_Logfile, _T ("# # # # # # # # # # # / n"));
Fclose (m_logfile);
}
} 3. Implement interface ITIMELOG method // implement interface ITIMELOG method
StdMethodimp
CtimelogServer :: Xtimelog :: OutputLog (BSTR * VARLOGTEXT)
{
Method_Prologue (CTimelogServer, Timelog)
IF (PTHIS-> M_LOGFILE)
{
CTIME TIMESTAMP = CTime :: getcurrenttime ();
CString nowTime = timestamp.format ("% y year% M month% D day% h:% m:% s");
CString logtext (lpcwstr) * varLogtext);
FPrintf (pTHIS-> M_LogFile, "/ N% S / N% S / N%", NOWTIME, LOGTEXT
Return noerror;
}
Else
{
AfxMessageBox ("No log file!");
Return S_FALSE;
}
} Seven. Improve component server in the implementation file of the application object CTIMELOGSERVERAPP, process instance () and exitInstance () Bool CTimelogSerVerapp :: initInstance ()
{
:: AfxoLockApp ();
// Register All Ole Server (Factories) As Running. This Enables the
// Ole Libraries to create Objects from Other Applications.
ColeObjectFactory :: registerall ();
Return True;
}
Int ctimelogserVerapp :: exitInstance ()
{
// Todo: Add Your Specialized Code Here and / or Call The Base Class
:: AfxoleunlockApp ();
Return CWINAPP :: EXITINSTANCE ();
} The key steps for the client program for the second section of the customer using the COM component server are: initialize the COM library, create component objects, and get the iUnknown interface pointer, query the interface and use, release the component. #Include "itimelogserver.h"
// Initialize the COM library, instantiate the components
HRESULT HRESULT;
IUNKNOWN * PIUNKNOWN;
HRESULT = :: Coinitialize (NULL);
Failed (HRESULT))
{
:: AfxMessageBox ("You can't initialize the COM library!");
Return False;
}
// Create a component instance
Piunknown = null;
HRESULT = :: COCREATEINSTANCE (CLSID_TIMELOGSERVER, NULL,
CLSCTX_INPROC_SERVER, IID_IUNKNOWN, (VOID **) & PIUNKNOWN;
Failed (HRESULT))
{
Piunknown = null;
:: AfxMessageBox ("You can't create Timelog Objects!");
Return False;
}
/ / Query the interface and use
IF (PiunkNown! = NULL)
{
ITIMELOG * PITIMELOG;
HRESULT = Piunknown-> queryinterface (iid_itimelog, (void **) & pitimelog);
Failed (HRESULT))
{
:: AfxMessageBox ("You cannot get interface itimelog!");
Piunknown-> Release ();
Return;
}
BSTR BSTRLOGTEXT;
Bstrlogtext = m_logtext.allocsystring ();
CString text ((lpcwstr) BSTRLogText);
:: AfxMessageBox (Text);
IF (Failed (PitiMelog-> Outputlog (& Bstrlogtext))))
{
:: AfxMessageBox ("Log Output Error!");
PitiMelog-> Release ();
Return;
}
PitiMelog-> Release ();
:: AfxMessageBox ("Log already writes!");
}
// Release component
Piunknown-> Release ();
Piunknown = null; :: couninitialize ();