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.
// declare assembly GUID {A433E701-E45E-11d3-97B5-52544CBA7F28} // DEFINE_GUID (CLSID_TimeLogServer, // 0xa433e701, 0xe45e, 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}}; // declare an interface GUID {A433E702-E45E-11d3-97B5-52544CBA7F28} // DEFINE_GUID (IID_ITimeLog, // 0xa433e702, 0xe45e, 0x11d3, 0x97, 0xb5, 0x52, 0x54, 0x4c, 0xba, 0x7f, 0x28); static const IID 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 (outputlogtext) pure;};
Description:
1. Macro DEFINE_GUID associates the PROGID of the component and interface. 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"; = 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 to ClassWizard, the base class is selected as ccmdtarget. Modify its header file TimelogServer1.h, plus #include "; itimelogserver.h" ;; At the same time, in the class declaration
// declare nested class interface implemented ITimelog BEGIN_INTERFACE_PART (TimeLog, ITimeLog) // automatically declared method STDMETHOD three IUnknown interface (OutputLog) (BSTR * varLogText); END_INTERFACE_PART (TimeLog) // declare DECLARE_INTERFACE_MAP interface map () // Declaration Factory Declare_Olecreate (CTimelogServer)
Third. Implementation of class and interface mappings
Write in the implementation file of CTimelogServer:
// Implement the type of import_oleracte (ctimelogserver, "; timeelogserver"; 0xA433E701, 0xE45E, 0X11D3, 0x97, 0x4c, 0x52, 0x54, 0x4c, 0x/A, 0x7F, 0x28); // map interface to the corresponding nested begin_interface_map CTIMELOGSERVER, CCMDTARGET) Interface_part (CTIMELOGSERVER, IID_ID_ITIMELOG, TIMELOG) End_Interface_map ()
Four. Counting the overall object count in the constructor and destructive function
CTimelogServer :: ctimelogserver () {:: afxolelockapp ();
CtimelogServer :: ~ ctimelogserver () {:: AfxoleunlockApp ();
5. Realize the IUNKNOWN interface for nested classes
// nested class IUnknown interface implemented STDMETHODIMP_ (ULONG) CTimeLogServer :: XTimeLog :: AddRef () {METHOD_PROLOGUE (CTimeLogServer, TimeLog) return pThis ->; ExternalAddRef ();} STDMETHODIMP_ (ULONG) CTimeLogServer :: XTimeLog :: RELEASE () {Method_ProLogue (CTimelogServer, Timelog) Return PTHIS ->; ExternalRelease ();
STDMETHODIMPCTimeLogServer :: 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:
CTimeiLogServer (); ctime timestamp = ctime :: getCurrentTime (); cstract 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 at:% s ";), (lpctstr) timestamp.format (";% y year% M month% D days% H:%) M% s ";); fprintf (m_logfile, _t ("; n ";));}} // then close files CTIMELOGSERVER :: ~ ctimelogserver () {:: AfXoleunlockApp (); if ( m_logfile) {ctime timestamp = ctime :: getCurrentTime (); fprintf (m_logfile, _t ("; n";); fprintf (m_logfile, _t ("; end in:% 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
// implementation of the interface method ITimeLog STDMETHODIMPCTimeLogServer :: 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% SN% SN% "; 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 () {:: AfxOleLockApp (); // 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 HRESULT HRESULT; IUNKNOWN * PIUNKNOWN; HRESULT = :: Coinitialize (NULL) {:: AfxMessageBox ("; initialize the COM library ";!); return FALSE;} // create a component instance pIUnknown = NULL; hResult = :: CoCreateInstance (CLSID_TimeLogServer, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void **) &; pIUnknown); if (FAILED (hResult )) {Piunknown = null; :: afxMessagebox ("; can not create Timelog Object!";); Return False;} // Query the interface and use IF (PiunkNown! = Null) {itimelog * pitimelog; hResult = piunknown->; Queryinterface (IID_ITIMELOG, (Void **) &; pitimelog); if (Failed (HRESULT)) {:: afxMessageBox ("; can not get interface ITIMELOG!";); PiunkNown ->; Release (); return;} BSTR BSTRLogText BSTRLOGTEXT = m_logtext.allocsystring (); cstring text ((lpcwstr) bstrlogtext); :: afxMessageBox (text);