COM basic principle

zhaozj2021-02-16  175

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.

转载请注明原文地址:https://www.9cbs.com/read-7871.html

New Post(0)