COM is better C
C :
If it is a static connection, a class library is issued, and the executable code of the class library will be an inextensible part of the customer application. When three applications use this library, each executable file contains a class library code. Once the class library vendor finds a defect, release a new class library, which needs to be compiled all applications that use this library.
Application A CMATH.OBJ
Application B CMATH.OBJ
Application C CMATH.OBJ
DLL:
Code sharing, solving the above problem is to encapsulate the class library into a dynamic link library (DLL, DYNAMIC LINK LIBRARY). All methods of class libraries will be added to the Export List, and the linker will generate an introduction library (IMPORT library). This library exposes the symbol of the method of the library. When the customer link is introduced into the library, some settles will be introduced into the executable, which notifies the loader dynamically load DLL at runtime.
Application A CMATH.LIB (Introduction Library) / Application B CMATH.LIB (Introduction Library) | CMath.dll (Shared One Code) Application C CMath.lib (Introduction Library) /
COM:
Because the C class is both an interface is also an implementation. Here you need to separate the interface from the implementation to provide binary component structure. At this point, there is a two C class, one as the other as an interface class as an implementation class.
COM foundation
return value:
COM requires all methods to return an error number of the HRESULT type. HRESULT is actually a type definition; TypeDef Long HRESULT.
See Winerror.h file for the definition of HRESULT
// Values Are 32 Bit Values Layed Out As Follows:
// 3 3 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1
// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
// ---- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ -------------------
// | s | res | facility | code |
// ---- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ -------------------
// Where
// s - is the severity code
// 0 - SUCCESS
// 1 - Error
// RES- is a reserved bit
// Facility - Is The facility code
// Code - Is The Facility ''s Status Code
IDL:
Each standard COM component requires an interface definition file, the file extension is IDL. Let us see what the IUNKNOW interface definition file is.
[
Local,
Object,
UUID (000,000-0000-0000-c000-000000000046),
Pointer_Default (unique)]
Interface IUnknown
{
TypedEf [Unique] iUnknown * lpunknown;
CPP_QUOTE ("//")
CPP_QUOTE ("// IID_IUNKNOWN AND All Other System Iids Are Provided in Uuid.lib")
CPP_QUOTE ("// Link That Library In used your proxies, clients and servers)
CPP_QUOTE ("//")
HRESULT QueryInterface
Refiid Riid,
[OUT, IID_IS (RIID)] void ** ppvObject);
Ulong addRef ();
Ulong release ();
}
[local] Attributes prohibits generating network code.
[Object] The property is indicating that the definition is a COM interface instead of the DEC style interface.
[UUID] attribute gives a GUID.
[UNIQUE] Attribute indicates that the NULL (empty) pointer is a legal parameter value.
[Pointer_Defaul] All embedded pointers specify a default pointer property
Typedef [unique] iUnknown * lpunknown; this is a type definition
CPP_QUOTE This is more interesting, this is a method of writing a note in the IDL file. These annotations will be saved to ***. H and *** _ i.c files
[in] said this parameter is income
[OUT] means this parameter is exported
[IID_IS (RIID)] Indicates that this parameter requires the previous RIID parameter.
IUNKNOWN:
COM requirements (the most basic requirements) All interfaces need to be inherited directly or indirectly from the iUnknown interface. The IUNKOWN interface defines three ways.
HRESULT QueryInterface ([in] refiid riid, [out] void ** ppv);
Ulong addRef ();
Ulong release ();
Where addReft () and release () are responsible for the object reference count, and the queryinterface () method is used to query the interface implemented. Whenever the COM component is referenced once, an AddRef () method should be called. And when the client needs to call the Release () method when the client is released an interface of the COM component. Please take care of the example below.
COM simple example
This example has four files:
file name
Description
Interface.h
Interface class definition file
Math.h and math.cpp
Implement class file
SIMPLE.CPP main function file
Here used as a client for COM
Interface.h file:
#ifndef interface_h
#define interface_h
#include
// {7C8027EA-A4ED-467C-B17E-1B51CE74AF57}
Static const guid iid_isimplemath =
{0x7C8027EA, 0xA4ED, 0x467c, {0xB1, 0x7e, 0x1b, 0x51, 0xce, 0x74, 0xAF, 0x57}}
// {CA3B37EA-E44A-49B8-9729-6E9222CAE84F}
Static const guidiid_iadvancedmath =
{0xCA3B37EA, 0xE44A, 0X49B8, {0x97, 0x29, 0x6e, 0x92, 0x22, 0xca, 0xe8, 0x4f}};
Interface isimath: Public IUNKNOWN
{
PUBLIC:
Virtual Int Add (int NOP1, INT NOP2) = 0;
Virtual int subtract (int NOP1, INT NOP2) = 0; Virtual Int Multiply (INT NOP1, INT NOP2) = 0;
Virtual Int Divide (int NOP1, INT NOP2) = 0;
}
Interface Iadvancedmath: Public IUNKNOWN
{
PUBLIC:
Virtual Int Factorial (int NOP1) = 0;
Virtual Int Fabonacci (INT NOP1) = 0;
}
#ENDIF
This file first #include
Cover the IUnknown interface definition file. Next, two interfaces are defined, and the GUID (Globally Unique Identifier Global Unique Identifier) It guarantees the only time and space. Four methods are defined in the ISMIPLEMATH interface, and two methods are defined in the IadvancedMath interface. These methods are virtual functions, and the entire IsMipleMath and IadvancedMath abstraction are used as binary interfaces. Math.h file:
#include "interface.h"
Class Cmath: Public ISIMPLEMATH, PUBLIC IADVANCEDMATH
{
Private:
Ulong m_cref;
Private:
INT CALCFACTORIAL (int NOP);
INT CALCFABONACCI (INT NOP);
PUBLIC:
// iUnknown method
STDMETHOD (QueryInterface) (Refiid Riid, Void ** PPV);
STDMETHOD_ (ULONG, ADDREF) ();
STDMETHOD_ (ULONG, RELEASE) ();
// Isimplemath Method
INT Add (int NOP1, INT NOP2);
Int subtract (int NOP1, INT NOP2);
INT MULTIPLY (int NOP1, INT NOP2);
Int Divide (int NOP1, INT NOP2);
// Iadvancedmath Method
INT FACTORIAL (INT NOP);
INT Fabonacci (int NOP);
}
Such as implementation classes, he implements two interface classes for ismiplemath and Iadvancedmath (of course, only one interface class can be implemented). Note: m_cref is used for object counts. When m_cref is 0 component objects, it should be automatically deleted. Math.cpp file:
#include "interface.h"
#include "math.h"
STDMETHODIMP CMATH :: Queryinterface (Refiid Riid, Void ** PPV)
{// Here this is the function of implementing Dynamic_cast, but because Dynamic_CAST is related to the compiler.
IF (riid == iid_isimplemath)
* ppv = static_cast (this);
Else IF (riid == iid_iadvancedmath)
* ppv = static_cast (this);
Else IF (riid == iid_iunknown)
* ppv = static_cast (this);
Else {
* ppv = 0;
Return E_NOINTERFACE;
}
ReinterPret_cast (* ppv) -> addRef (); // This is because reference count is Return S_OK for components;
}
STDMETHODIMP_ (ULONG) CMATH :: AddRef ()
{
Return m_cref;
}
STDMETHODIMP_ (ULONG) CMATH :: release ()
{
Ulong res = --m_cref; // Use temporary variables to cache the modified reference count value
If (res == 0) // Because the data will be quoted after the object has been destroyed, this object will be illegal.
DELETE THIS;
Return res;
}
INT CMATH :: Add (int NOP1, INT NOP2)
{
RETURN NOP1 NOP2;
}
INT CMATH :: Subtract (int NOP1, INT NOP2)
{
RETURN NOP1 - NOP2;
}
INT CMATH :: Multiply (int NOP1, INT NOP2)
{
Return NOP1 * NOP2;
}
INT CMATH :: Divide (int NOP1, INT NOP2)
{
RETURN NOP1 / NOP2;
}
INT CMATH :: CalcFactorial (int NOP)
{
IF (NOP <= 1)
Return 1;
Return NOP * CALCFACTORIAL (NOP - 1);
}
Int cmath :: Factorial (int NOP)
{
Return CalcFactorial (NOP);
}
Int cmath :: Calcfabonacci (int NOP)
{
IF (NOP <= 1)
Return 1;
RETURN CALCFABONACCI (NOP - 1) Calcfabonacci (NOP - 2);
}
Int cmath :: Fabonacci (int NOP)
{
Return Calcfabonacci (NOP);
}
Cmath :: cmath ()
{
m_cref = 0;
}
This file is a CMATH class definition file. SIMPLE.CPP:
#include "math.h"
#include
Using namespace std;
Int main (int Argc, char * argv [])
{
ISIMPLEMATH * PSIMPLEMATH = NULL; // Declaration Interface Pointer
Iadvancedmath * padvmath = NULL;
// Create an object instance, we temporarily create an object instance, COM has a mechanism for creating an object instance
CMATH * PMATH = New CMATH;
/ / Query the interface ISIMPLEMATH
Pmath-> queryinterface (IID_ID_IMPLEMATH, (Void **) & psimplemath);
IF (PSIMPLEMATH)
COUT << "10 4 =" << psimplemath-> add (10, 4) << ENDL;
/ / Query the interface Iadvancedmath
psimplemath-> queryinterface (iid_iadvancedmath, (void **) & padvmath);
IF (PadVMATH)
Cout << 10 fabonacci is "<< padvmath-> fabonacci (10) << Endl; Padvmath-> Release ();
psimplemath-> release ();
Return 0;
}
This file is equivalent to the client's code, first create a CMATH object, then query the required interface according to this object, if the required interface pointer is correct, then call the interface method, and finally release the interface. Binary structure of Math components:
summary:
Examples are not true COM components (he is not DLL) strictly, but he has complied with the minimum requirements of COM (implementing the iUnknown interface). Let's take a COM DLL.
Create a COM component
The creation process is shown below:
In this process we will complete three steps: Create a DLL entry function, define interface files, and implement registration function.
1. A type of Win32 DLL project:
Create a Win32 DLL project called Mathcom. Select the "A SMIPLE DLL Project" option in the second step of the wizard. Of course, if you choose an empty project, you will complete the DLLMAIN definition yourself.
2. Interface file:
Generate an interface file called Mathcom.IDL. And add this file to the project you just created.
//Mathcom.idl file
// mathcom.idl: idl source for mathcom.dll
//
// this file will be processed by the Mid Tool To
// produted the Type library (Mathcom.tlb) and Marshalling Code.
Import "OAIDL.IDL";
Import "OCIDL.IDL";
[
UUID (FAEAE6B7-67BE-42A4-A318-3256781E945A),
Helpstring ("Isimplemath Interface",
Object,
Pointer_DEFAULT (UNIQUE)
]
Interface Isimplemath: IUNKNOWN
{
HRESULT ADD ([in] int NOP1, [IN] int NOP2, [OUT, RETVAL] INT * PRET);
HRESULT SUBTRACT ([In] int NOP1, [IN] int NOP2, [OUT, RETVAL] INT * PRET);
HRESULT MULTIPLY ([in] int NOP1, [IN] int NOP2, [OUT, RETVAL] INT * PRET);
HRESULT DIVIDE ([In] int NOP1, [IN] int NOP2, [OUT, RETVAL] INT * PRET);
}
[
UUID (01147c39-9da0-4f7f-b525-d129745aad1e),
Helpstring ("Iadvancedmath Interface),
Object,
Pointer_DEFAULT (UNIQUE)
]
Interface Iadvancedmath: IUNKNOWN
{
HRESULT FACTORAL ([in] int NOP1, [OUT, RETVAL] INT * PRET);
HRESULT FABONACCI ([In] int NOP1, [OUT, RETVAL] INT * PRET);
}
[
UUID (CA3B37EA-E44A-49B8-9729-6E9222CAE844),
Version (1.0),
Helpstring ("Mathcom 1.0 Type Library"]]]
Library MathComlib
{
Importlib ("stdole32.tlb");
Importlib ("stdole2.tlb");
[
UUID (3BCFE27E-C88D-453C-8C94-F5F7B97E7841),
Helpstring ("Mathcom Class")
]
CoClass Mathcom
{
[default] interface isimath;
Interface Iadvancedmath;
}
}
Check the settings in Project / Setting / MIDL before compiling this project. Correctly set the following picture: After the correct settings, if there is no error in compilation, then four in the directory of the project
file name
effect
Mathcom.h
The header file of the interface, use this file if you want to declare or define an interface
MATHCOM_I.C
Define interfaces and class objects and libraries, only introduced this file when you want to use something related to GUID, this file can only be introduced throughout the project, otherwise there will be repeated definition errors
Mathcom_p.c
For stub and agents
DLLDATA.C
unknown
3. Add registration function:
As a function of COM, you must register and log out. Add a MATHCOM.DEF file, the DEF file is the module definition file. It allows the extraction symbol to be posed to different introduction symbols.
//Mathcom.def file
Mathcom.def: Declares the module parameters.
Library "mathcom.dll"
Exports
DllcanunloadNow @ 1 Private
DllgetClassObject @ 2 private
DllRegisterServer @ 3 private
DllunregisterServer @ 4 private
DllunregisterServer This is a function name @ 4 <- This is the function serial number private next to DllRegisterServer () and DllunregisterServer (). (The role of other two functions will be described later) DllRegisterServer () and dllunregisterServer () DllRegisterServer () functions The role is to register the COM server to this unit. The effect of the DllunregisterServer () function is to log out of the COM server from this unit. MATHCOM.CPP file:
Now, please modify the mathcom.cpp file as follows:
// Mathcom.cpp: Defines the entry point for the dll application.
//
#include "stdafx.h"
#include
#include
#include "mathcom.h"
// Standard Self-Registration Table
Const char * g_regtable [] [3] = {
{"CLSID / / {3BCFE27E-C88D-453C-8C94-F5F7B97E7841}", 0, "Mathcom"}
{"CLSID / / {3BCFE27E-C88D-453C-8C94-F5F7B97E7841} // InprocServer32",
0,
(const char *) -1 / * Represents the value of the file name * /},
{"CLSID // {3BCFE27E-C88D-453C-8C94-F5F7B97E7841} // progid", 0, "Tulip.mathcom.1"},
{"tulip.mathcom.1", 0, "mathcom"},
{"Tulip.mathcom.1 // CLSID", 0, "{3BCFE27E-C88D-453C-8C94-F5F7B97E7841}"}
}
Hinstance g_hinstdll;
Bool apientry dllmain (Handle Hmodule,
DWORD UL_REASON_FOR_CALL,
LPVOID LPRESERVED
)
{
g_hinstdll = (hinstance) hmodule;
Return True;
}
/ ************************************************** *******************
* Function Declare: DllunRegisterServer
* EXPLAIN: Self-unregistration Routine
* Parameters:
* void -
* Return:
* Stdapi -
* Author: Tulip
* TIME: 2003-10-29 19:07:42
*********************************************************** ****************** /
StDAPI DllunregisterServer (Void)
{
HRESULT HR = S_OK;
Char szfilename [MAX_PATH];
:: getModuleFileName (g_hinstdll, szfilename, max_path);
INT NENTRIES = SIZEOF (g_regtable) / sizeof (* g_regtable);
For (int i = 0; succeeded (hr) && i
{
Const char * pszkeyname = g_regtable [i] [0];
Long Err = :: regdeletekey (hkey_classes_root, pszkeyname);
IF (Err! = Error_Success)
HR = s_false;
}
Return HR;
}
/ ************************************************** *******************
* Function Declare: DllRegisterServer
* EXPLAIN: SELF Registration Routine
* Parameters:
* void -
* Return:
* Stdapi -
* Author: Tulip
* TIME: 2003-10-29 19:43:51
*********************************************************** ****************** /
StDAPI DLLREGISTERSERVER (VOID)
{
HRESULT HR = S_OK;
Char szfilename [MAX_PATH];
:: getModuleFileName (g_hinstdll, szfilename, max_path);
INT NENTRIES = SIZEOF (g_regtable) / sizeof (* g_regtable);
For (int i = 0; succeeded (hr) && i
{
Const char * pszkeyname = g_regtable [i] [0]; const char * pszvaluename = g_regtable [i] [1];
Const char * pszvalue = g_regtable [i] [2];
IF (pszvalue == (const char *) - 1)
{
pszvalue = szfilename;
}
HKEY HKEY;
Long Err = :: regReateKey (HKEY_CLASS_ROOT, PSZKEYNAME, & HKEY);
IF (err == error_success)
{
Err = :: RegSetValueex (HKEY,
Pszvaluename,
0,
REG_SZ,
(const byte *) pszvalue,
Strlen (pszvalue) 1);
:: regcloseKey (HKEY);
}
IF (Err! = Error_Success)
{
:: DllunregisterServer ();
HR = E_FAIL;
}
}
Return HR;
}
Stdapi DllgetClassObject (Refclsid Rclsid, Refiid Riid, Void ** PPV)
{
Return Class_e_classNotavailable;
}
StDAPI DLLCanunloadNow (Void)
{
Return E_FAIL;
}
I just add a few necessary header files and several global variables in this file. DllRegisterServer () and DllunregisterServer () are implemented. And for other two-in-one function I only returned a wrong value.
summary:
Now there should be as follows:
file name
effect
STDAFX.H and stdafx.cpp
Pre-compilation file
Mathcom.cpp
DLL entry function and other important functions defined
Mathcom.def
Module definition file
Mathcom.IDL
Interface definition file (if compiled after 1.2, there should be four files)
Ok, now, my so-called COM has implemented registration and logout. If you do the following "Regsvr32 absolute path mathcom.dll" is registered. This COM component is performed under the command line or "Run" menu. After performing the completed command, check if the HKEY_CLASSES_ROOT / CLSID item of the registry key is existed in the 3BCFE27E-C88D-453C-8C94-F5F7B97E7841. Like the "Regsvr32 -u absolute path Mathcom.dll", then look at the registry. In fact, the DLL that has just been generated is not a COM component, haha! ! ! Because he did not implement dllgetClassObject () nor did any one of IsMipleMath and Iadvancedmath two interfaces. Let us continue to travel! ! !
4. Implement ISMIPLEMATH, IADVANCEDMATH interface and dllgetClassObject ()
Implementing the ISMIPLEMATH and IADVANCEDMATH interfaces let us modify the original CMATH interface to implement the ISMIPLEMATH interface and the IadvancedMath interface. The modified place is as follows:
1) Math.h file
/ * @ ** # --- 2003-10-29 21:33:44 (tulip) --- # ** @
#include "interface.h" * /
#include "mathcom.h" // Added, replacing the above, Dongdong Class Cmath: Public IsImPleMath,
Public Iadvancedmath
{
Private:
Ulong m_cref;
Private:
INT CALCFACTORIAL (int NOP);
INT CALCFABONACCI (INT NOP);
PUBLIC:
CMATH ();
// iUnknown method
STDMETHOD (QueryInterface) (Refiid Riid, Void ** PPV);
STDMETHOD_ (ULONG, ADDREF) ();
STDMETHOD_ (ULONG, RELEASE) ();
// Isimplemath Method
StdMethod (Add) (int NOP1, INT NOP2, INT * PRET);
StdMethod (Subtract) (int NOP1, INT NOP2, INT * PRET);
StdMethod (INT NOP1, INT NOP2, INT * PRET);
STDMETHOD (Divide) (int NOP1, INT NOP2, INT * PRET);
// Iadvancedmath Method
StdMethod (INT NOP, INT * PRET);
StdMethod (INT NOP, INT * PRET);
}
2) Math.cpp file
/ * @ ** # --- 2003-10-29 21:32:35 (tulip) --- # ** @
#include "interface.h" * /
#include "math.h"
STDMETHODIMP CMATH :: Queryinterface (Refiid Riid, Void ** PPV)
{// Here this is the function of implementing Dynamic_cast, but because Dynamic_CAST is related to the compiler.
IF (riid == iid_isimplemath)
* ppv = static_cast
(this);
Else IF (riid == iid_iadvancedmath)
* ppv = static_cast
(this);
Else IF (riid == iid_iunknown)
* ppv = static_cast
(this);
Else {
* ppv = 0;
Return E_NOINTERFACE;
}
Reinterpret_cast
(* ppv) -> addRef ();
//
This should be this because the reference count is for the component
Return S_OK;
}
STDMETHODIMP_ (ULONG) CMATH :: AddRef ()
{
Return m_cref;
}
STDMETHODIMP_ (ULONG) CMATH :: release ()
{
Ulong res = --m_cref; // Use temporary variables to cache the modified reference count value
If (res == 0) // Because the data will be quoted after the object has been destroyed, this object will be illegal.
DELETE THIS;
Return res;
}
STDMETHODIMP CMATH :: Add (int NOP1, INT NOP2, INT * PRET)
{
* PRET = NOP1 NOP2;
Return S_OK;
}
STDMETHODIMP CMATH :: Subtract (int NOP1, INT NOP2, INT * PRET) {
* PRET = NOP1 - NOP2;
Return S_OK;
}
STDMETHODIMP CMATH :: Multiply (int NOP1, INT NOP2, INT * PRET)
{
* PRET = NOP1 * NOP2;
Return S_OK;
}
StdMethodimp Cmath :: Divide (int NOP1, INT NOP2, INT * PRET)
{
* PRET = NOP1 / NOP2;
Return S_OK;
}
INT CMATH :: CalcFactorial (int NOP)
{
IF (NOP <= 1)
Return 1;
Return NOP * CALCFACTORIAL (NOP - 1);
}
StdMethodimp Cmath :: Factorial (int NOP, INT * PRET)
{
* PRET = CalcFactorial (NOP);
Return S_OK;
}
Int cmath :: Calcfabonacci (int NOP)
{
IF (NOP <= 1)
Return 1;
RETURN CALCFABONACCI (NOP - 1) Calcfabonacci (NOP - 2);
}
StdMethodimp Cmath :: Fabonacci (int NOP, INT * PRET)
{
* Pret = Calcfabonacci (NOP);
Return S_OK;
}
Cmath :: cmath ()
{
m_cref = 0;
}
COM components are transferred to the rough process
1) COM library initialization uses the Coinitialize sequence function (application)
2) Activate COM (application)
3) Turn the corresponding DLL into the COM library (COM library) through the registry key
4) Call the DllgetClassObject () function (COM component) in the COM component
5) This step is not required by returning the interface pointer (COM library) through the class factory.
DllgetClassObject () implements the following statement in Mathcom.cpp.
#include "math.h"
#include "mathcom_i.c"
And modify the dllgetClassObject () in matHcom.cpp into the following:
/ ************************************************** *******************
* Function Declare: DllgetClassObject
* EXPLAIN:
* Parameters:
* Refclsid rclsid -
* Refiid Riid -
* void ** PPV -
* Return:
* Stdapi -
* Author: Tulip
* TIME: 2003-10-29 22:03:53
*********************************************************** ****************** /
Stdapi DllgetClassObject (Refclsid Rclsid, Refiid Riid, Void ** PPV)
{
Static CMATH * PM_MATH = New CMATH;
IF (rclsid == CLSID_MATHCOM)
RETURN PM_MATH-> QueryInterface (RIID, PPV);
Return class_e_classnotavailable;}
5. Test
Next we write a client program to test this COM. Newly built a Win32 Console project with Testmathcom, add it to Mathcom Workspace. Add a file called main.cpp in the TestMathcom engineering, this file is as follows:
//main.cpp file
#include
#include "../mathcom.h"// here, please pay attention to the path
#include "../mathcom_i.c"// here, please pay attention to the path
#include
Using namespace std;
Void main (void)
{
// Initialize the COM library
HRESULT HR = :: Coinitialize (0);
ISIMPLEMATH * PSIMPLEMATH = NULL;
Iadvancedmath * padvancedmath = NULL;
INT nreturnvalue = 0;
HR = :: CogetherClassObject (CLSID_MATHCOM,
CLSCTX_INPROC,
NULL, IID_IMPLEMATH,
(void **) & psimplemath);
En (ac))
{
HR = psimplemath-> add (10, 4, & nreturnValue);
En (ac))
COUT << "10 4 =" <
<< ENDL;
NRETURNVALUE = 0;
}
/ / Query the interface Iadvancedmath
HR = psimplemath-> queryinterface (IID_IADVANCEDMATH, (Void **) & padvancedmath);
En (ac))
{
HR = padvancedmath-> fabonacci (10, & nreturnValue);
En (ac))
Cout << "10 fabonacci is" << nreturnValue << Endl;
}
Padvancedmath-> release ();
psimplemath-> release ();
:: Couninitialize ();
:: System ("Pause");
Return;
}
Small knot: Now we should have 2 projects and 8 files, as follows:
engineering
file
effect
Mathcom
STDAFX.H and stdafx.cpp
Pre-compilation file
Mathcom.cpp
DLL entry function and other important functions defined
Mathcom.def
Module definition file
Mathcom.IDL
Interface definition file (if compiled after 1.2, there should be four files)
Math.h and math.cpp
ISMIPLEMATH, IADVANCEDMATH interface implementation class
Testmathcom
Main.cpp
Mathcom's client for testing Mathcom components
In this section we have completed a practical COM component. We completed the client of this COM component. If you have created a COM instance, you may find that the client in this section is not creating a COM instance in cocreateInstance (), because we have not implemented the iClassFactory interface in this COM component (this interface is implemented in the next part) . Through this example, I hope everyone understands the following points: 1) DllgetClassObject () The role of DllgetClassObject (), please see the COM component to transfer the rough process, and please play the breakpoint on the dllgetclassobject () function, take a closer look at him Implementation (in the case where there is no IclassFactory interface) and his incoming parameters.
2) Why don't use COCREATEINSTANCE () in this client program to create a COM instance using CogetherClassObject (). You can try COCREATEINSTANCE () to create CMATH to see what the first parameter of DllgetClassObject () is?
3) Realizing the IclassFactory interface is not required, but it should be necessary (how to implement it, see the next chapter)
4) Master the implementation of DllRegisterServer () and DllunregisterServer ().
5) The client requires that several files when calling the COM component (as long as two files generated by the IDL file)
Class factory:
In the previous section, we create a component instance and get the interface pointer as follows: First call COM API COCREATEINSTANCE at the client user, this function calls another COM API COGETCLASSOBJECT to get the component's class factory interface pointer, at which time the COM library loads the component. DLL (EXE processing method is slightly different, we will explain the export function dllgetClassObject () in the later chapter), and get the method of the class factory to create the object instance and pass the QueryInterface of the component object after obtaining the type factory interface pointer. ) Get the needed interface pointer. Previously we didn't really completely complete COM components, now we will implement a real COM component, implement the core of component creation mechanism: Class Factory - Create an object of component objects. COM is common and unified and convenient for management. The COM specification requires all standard COM components to implement the iClassFactory interface (see Msnd RESource / SELECTED Online Column / Welcome to the Msnd Library / Msnd Resource / Selected Online Column / Msnd Resource / Selected Online Column Dr.Gui Online / Dr. Gui on Components, COM, And ATL / Part 5)
2.2 Increasing the implementation of IclassFactory This time we will modify the files as follows
Construction name
file name
Modify attribute
Mathcom
Mathcom.cpp
modify
Mathfactory.h and MathFactory.cpp
Add new
Testmathcom
Main.cpp
modify
2.2.1 Mathcom.cpp
#include "math.h"
#include "mathcom_i.c"
#include "mathfactory.h"
//
// Server lock, if the flag is S_OK, you can uninstall the server of the current component.
/ / About the reference count and the server with the relationship of the COM object, then explain again
Long g_cObjectandlocks = 0;
// standard self-registration TableConst char * g_regtable [] [3] = {....................
..............................
Stdapi DllgetClassObject (Refclsid Rclsid, Refiid Riid, Void ** PPV)
{
IF (rclsid == CLSID_MATHCOM)
{
CMathFactory * pFactory = new cmathfactory; // Create a class factory object
IF (pFactory == Null)
Return E_OUTOFMEMORY;
///
// Under normal circumstances COM hope that users only query iClassFactory,
// iClassFactory2 and iunknow
HRESULT HR = PFactory-> QueryInterface (IID, PPV);
Return HR;
}
Return Class_e_classNotavailable;
}
StDAPI DLLCanunloadNow (Void)
{
Return (g_cobjectandlocks == 0)? S_OK: E_FAIL;
}
2.2.2 MathFactory.h
// MathFactory.h: interface for the cmathfactory class.
//
//
#ifndef MathFactory_H
#define mathfactory_h
#include
Class CmathFactory: Public iClassFactory: Public ICLASSFACTORY
{
PUBLIC:
CMathFactory (): m_cref (0) {}
// iUnknow method
STDMETHODIMP QueryInterface (Refiid, Void **);
STDMETHODIMP_ (ULONG) AddRef ();
STDMETHODIMP_ (ULONG) Release ();
// iClassFactoryMETHOD
StdMethodimp CreateInstance (iUnknown *, refiid, void **);
STDMETHODIMP LOCKSERVER (BOOL FLOCK);
protected:
Long m_cref;
}
#ENDIF
2.2.3 MathFactory.cpp
// MathFactory.cpp: Implementation of the cmathfactory class.
//
//
#include "math.h"
#include "mathfactory.h"
Extern long g_cobjectandlocks;
//
// construction / destruction
//
STDMETHODIMP_ (ULONG) CMathFactory :: AddRef (void)
{
Return InterlockedIncrement (& M_CREF);
}
STDMETHODIMP_ (ULONG) CMathFactory :: Release (Void)
{
Return :: InterlockedDecrement; & m_cref;
}
STDMETHODIMP CMATHFAACTORY :: queryinterface (refiid riid, void ** ppv)
{
* ppv = NULL;
IF (RIID == iid_iunknown || riid == iid_iclassfactory)
{
* ppv = static_cast
(this);
Reinterpret_cast
(* ppv) -> addRef ();
Return S_OK;
Else
Return (* PPV = 0), E_NOINTERFACE;
}
STDMETHODIMP CMATHFAACTORY :: CreateInstance (IUNKNOWN * PUNKOUTER, REFIID RIID, VOID ** PPV)
{
* ppv = NULL;
// Do not support aggregation now
IF (Punkouter! = NULL)
RETURN CLASS_E_NOAGGREGATION;
CMATH * PMATH = New CMATH;
IF (pmath == null)
Return E_OUTOFMEMORY;
HRESULT HR = Pmath-> QueryInterface (RIID, PPV);
IF (Failed (HR))
Delete pmath;
Return HR;
}
STDMETHODIMP CMATHFAACTORY :: LOCKSERVER (BOOL FLOCK)
{
IF (FLOCK)
:: InterlockedIncrement (& g_cobjectandlocks);
Else
:: InterlockedDecrement (& g_cObjectandlocks);
Return noerror;
}
2.2.4 main.cpp
#include
#include "../mathcom.h"
#include "../mathcom_i.c"
#include
Using namespace std;
Void main (void)
{
// Initialize the COM library
HRESULT HR = :: Coinitialize (0);
ISIMPLEMATH * PSIMPLEMATH = NULL;
Iadvancedmath * padvancedmath = NULL;
INT nreturnvalue = 0;
// If you want to use CocreateInstance () to get the interface pointer, please use the first IclassFactory interface as follows
/ *************** Here please note ************************** /
// method one
HR = :: CocreateInstance (CLSID_MATHCOM,
CLSCTX_INPROC,
NULL,
IID_ISIMPLEMATH,
(void *) & psimplemath);
///
// The advantage of this method is not much less code, let COM process the process of creating the object of the real class factory.
/ / At the same time, the improved version of this function COCREATEINSTANCEEX can retrieve more in the distributed object application.
// interface pointer. Avoid too much to waste time on the network About this function I will later
// explain in the chapter. You can also refer to MSDN or related books.
// Method Two
IClassFactory * PCLASSFAACTORY = NULL; // class factory interface pointer
// Get the object's class factory interface pointer
HR = :: CogetherClassObject (CLSID_MATHCOM,
CLSCTX_INPROC,
NULL,
IID_ICLASSFACTORY,
(void **) & pclassFactory;
// Really create an object
HR = PCLASSFAACTORY-> CREATEINSTANCE (NULL, IID_ID_IMPLEMATH, (VOID **) & PSIMPLEMATH);
/ / The advantage of this method is that you can create multiple objects at a time, no need
// Test the IDispatch interface below
En (ac))
{
HR = psimplemath-> add (10, 4, & nreturnValue);
IF (succeeded (hr)) cout << "10 4 =" <
<< ENDL;
NRETURNVALUE = 0;
}
/ / Query the interface Iadvancedmath
HR = psimplemath-> queryinterface (IID_IADVANCEDMATH, (Void **) & padvancedmath);
En (ac))
{
HR = padvancedmath-> fabonacci (10, & nreturnValue);
En (ac))
Cout << "10 fabonacci is" << nreturnValue << Endl;
}
Padvancedmath-> release ();
psimplemath-> release ();
:: Couninitialize ();
Return;
}
summary:
In this section we implements the IclassFactory interface, you can say a real COM object, we can use a general COM client method in C to create objects, implement methods, etc. But don't know if the user finds that COM's goal is nothing. It does not support pointers in VB, and the script is explained (but CoM needs to be binded during the compilation). How to do it? Is there a way to achieve? The method is of course yes. The next section I didn't explain the language of the language that does not support the pointer and provides supported interface (also known as scheduling interface). Provide a solution to the above language to a slightly poor efficiency but higher flexibility. This chapter lets us implement the IDispatch interface to use our COM components in the script environment.