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 the iUnknown interface through the CCMDTARGET class.
This article first describes the steps and core code for creating a COM server. Then explain the critical code of the client program.
This COM server implements a TimelogServer component. For your concise, this component has only one interface ITIMELOG, and the log text can be output to the log file with the method OutputLog through ItimeLog.
Create an MFC DLL project, select Support Automation (Of course this program is not necessarily an automation server, this is here to automatically implement several necessary output functions such as DllgetClassObject, DllRegisterServer, etc., otherwise write yourself)
Section 1 COM server
I. Disclaimer Components and Interfaces
1. Write a guids.h, declare the components and interfaces in Guids.h.
// 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, declare components and interfaces in the ITIMELOGSERVER.H file
//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_ declare the interface; the macro first parameter is the interface name, the second parameter is the base class for the interface. Declare the interface without the base class with the DECLARE_INTERFACE macro.
3. Macro STDMethod declare the method in the interface. The return value of this method is explained as "= 0", that is, this method is a pure virtual function. When the return value of the method is not HRESULT, macro stdmethod_ (return type , Function name) (parameter) PURE;
II. Declaration Components CTIMELOGSERVER and nested classes to implement interface
Add a new class CTimelogServer in ClassWizard, the base class is selected as ccmdtarget. Modify its header file TimelogServer1.h, plus #include "itimelogserver.h"; while plus in class declaration
// Declare the nested class to realize the ITIMELOG interface
Begin_Interface_part (Timelog, Itimelog) // three methods for automatically declaring the iUnknown interface
STDMETHOD (OUTPUTLOG); End_Interface_part (Timelog)
// Declaration Interface Map
Declare_interface_map ()
// Disclaimer
Declare_olecreate (CTimelogServer)
Third. Implementation of class and interface mappings
Write in the implementation file of CTimelogServer:
/ / 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 ();
}
5. Realize the IUNKNOWN interface for nested classes
/ / Realize IUNKNOWN interface for nested classes
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);
}
Description: Although the CCMDTARGET class has implemented the 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 classes of the component object and implement the interface. Set.
6. Method for realizing itiMelog interface Outputlog
Note The functionality of this component is to enter the log file into the log file.
1. Add a file pointer to the component class:
// attributes
PUBLIC:
protected:
FILE * M_LOGFILE;
2. Initialization and exit
First, some initialization is performed 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 ("# # # # # # # # # # # # # # # # # # # # # # # # #tf (m_logfile, _t (" Start:% s "), (LPCTSTR) TimeStamp. Format ("% y year% M month% D day% 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 the interface ITIMELOG method
/ / Implement the 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
Process instance () and exitInstance () in the implementation file of the application object CTIMELOGSERVERAPP
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 ();
}
Section 2 client program
The key steps of 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 ();