First, it should be clear that in MFC, the COM interface is implemented through nested classes instead of multiple inheritance, and the interface and the nested class implementing this interface are associated through the interface ing mechanism; MFC provides a set of concise macros to implement the definition of Nested classes. secondly, MFC implements the iunknown interface through the csf-target class.
This article first describes the steps and core code for creating a COM server, and then describes the key code of the customer program.
This COM server implements a timelogserver component. For the sake of conciseness, this component has only one interface, itimelog. The outputlog method of itimelog can output the log text to the log file.
Create an mfc dll project and select to support automation (of course, this program is not necessarily an Automation server. Here, we do this by automatically implementing several necessary output functions, such as dllgetclassobject and dllregisterserver, otherwise, write it by yourself)
Section 1 COM Server
I. Declare components and interfaces
1. Write a guids. h file and declare the guid of the component and interface in guids. h.
// Declare component 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 an itimelogserver. h and declare the components and interfaces in the itimelogserver. h file.
// Itimelogserver. h # Include "; guids. H "; // Interface itimelog Declaration Declare_interface _ (itimelog, iunknown) { Stdmethod (outputlog) (BSTR * varlogtext) pure; }; |
Note:
1.macro define_guidcan be associated with progidof the group and interface. It can be generated using the guidgen.exe tool.
2. Macro declare_interface _ declares the interface. The first parameter of the macro is the interface name, and the second parameter is the base class of the interface. The declare_interface macro is used to declare interfaces without the base class.
3. the macro stdmethod declares the methods 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. when the return value of a method is not hresult, use the macro stdmethod _ (return type, function name) (parameter) pure;
Ii. Declare component class ctimelogserver and implement interface nesting class
Add the ctimelogserver class to classwizard, and set the base class to csf-target. Modify the header file timelogserver1.h, and add # include "; itimelogserver. H";. Add the class declaration
// Declare the nested class that implements the itimelog Interface Begin_interface_part (timelog, itimelog) // automatically declare three methods of the iunknown Interface Stdmethod (outputlog) (BSTR * varlogtext ); End_interface_part (timelog) // Declare interface ing Declare_interface_map () // Declaration Factory Declare_olecreate (ctimelogserver) |
3. Implement class factory and interface ing
Write in the ctimelogserver implementation file:
// Implementation Factory Implement_olecreate (ctimelogserver, "; timelogserver ";, 0xa433e701, 0xe45e, 0x11d3, 0x97, 0xb5, 0x52, 0x54, 0x4c, 0xba, 0x7f, 0x28 ); // Map the interface to the corresponding nested class Begin_interface_map (ctimelogserver, c1_target) Interface_part (ctimelogserver, iid_itimelog, timelog) End_interface_map () |
4. Global Object count in Component Construction and destructor
Ctimelogserver: ctimelogserver () { : Afxolelockapp (); } Ctimelogserver ::~ Ctimelogserver () { : Afxoleunlockapp (); } |
5. Implement the iunknown interface for nested classes
// Implement the 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 ); } |
Note: although the cshorttarget class has implemented the iunknown interface, the iunknown interface of the nested class must be mapped to the iunknown interface supported by cshorttarget. the two parameters of the method_prologueh macro are the classes that implement component objects and the nested classes that implement interfaces.
6. Methods for implementing the itimelog interface outputlog
Note that the function of this component is to input logs into the log file.
1. Add a file pointer to the component class:
// Attributes Public: Protected: File * m_logfile; |
2. initialize and exit
First, perform some initialization in the melogserver constructor:
Ctimelogserver: ctimelogserver () { : Afxolelockapp (); Ctime timestamp = ctime: getcurrenttime (); Cstring filename; Filename. Format (_ T ("; % S. log";), timestamp. Format ("; % Y % m % d ";)); M_logfile = fopen (filename, _ T ("; ";)); If (m_logfile) { Fprintf (m_logfile, _ T (";##################/N ";)); Fprintf (m_logfile, _ T ("; started at: % s";), (lpctstr) timestamp. format ("; % Y % m month % d % H: % m % s ";)); Fprintf (m_logfile, _ T (";/N ";)); } } // 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 ("; ended at: % s";), (lpctstr) timestamp. format ("; % Y % m month % d % H: % m % s ";)); Fprintf (m_logfile, _ T (";/N ";)); Fprintf (m_logfile, _ T (";##################/N ";)); Fclose (m_logfile ); } } |
3. Implement the interface itimelog Method
// Implement the 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 % m month % d % H: % m: % s ";); Cstring logtext (lpcwstr) * varlogtext ); Fprintf (pthis->; m_logfile, ";/n % s/n %";, nowtime, logtext ); Return noerror; } Else { Afxmessagebox ("; no log file! ";); Return s_false; } } |
7. Complete component servers
Process instance () and exitinstance () in the Implementation file of ctimelogserverapp ()
Bool ctimelogserverapp: initinstance () { : Afxolelockapp (); // Register all OLE server (factories) as running. This enables // 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 customer Program
Key steps for using the COM component Server Client program are: Initialize the com library, create a component object, obtain the iunknown interface pointer, query the interface, use it, and release the component.
# Include "; itimelogserver. H "; // Initialize the com library and instantiate the component Hresult; Iunknown * piunknown; Hresult =: coinitialize (null ); If (failed (hresult )) { : Afxmessagebox ("; com library cannot be initialized! ";); 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 ("; timelog object cannot be created! ";); Return false; } // Query the interface and use If (piunknown! = NULL) { Itimelog * pitimelog; Hresult = piunknown->; QueryInterface (iid_itimelog, (void **) &; pitimelog ); If (failed (hresult )) { : Afxmessagebox ("; the interface itimelog cannot be obtained! ";); Piunknown->; release (); Return; } BSTR bstrlogtext; Bstrlogtext = m_logtext.allocsysstring (); Cstring text (lpcwstr) bstrlogtext ); : Afxmessagebox (text ); If (failed (pitimelog->; outputlog (&; bstrlogtext ))) { : Afxmessagebox ("; log output error! ";); Pitimelog->; release (); Return; } Pitimelog->; release (); : Afxmessagebox ("; the log has been written! ";); } // Release the component Piunknown->; release (); Piunknown = NULL; : Couninitialize (); |