On the COM technology (a) Author: venture download the source code directory
I. COM is a better C 1. COM is from C to DLL to COM 2.1 C 2.2 DLL 2.3 COM 2. COM Basics 1. COM Basic Knowledge 1.1 Return Value HRESULT 1.2 First Idl 1.3 IUNKOWN interface 2 A relatively simple COM 2.1 interface.h file 2.2 Math.h file 2.3 Math.cpp file 2.4 Simple.cpp file 2.5 math component binary structure Figure 2.6 Small knot 3. Pure manual creation a COM component 1. From construction to implementation Registration 1.1 Creating a type for Win32 DLL Project 1.2 Definition Interface File 1.3 Increase Registration Features 1.3.1 Add a Mathcom.def file 1.3.2 DllRegisterServer () and dllunregisterServer () 1.4 mathcom.cpp file 1.5 Summary 2. Implement IsmipleMath, IadvancedMath interface And DllgetClassObject () 2.1 Implementation of ISMIPLEMATH and IADVANCEDMATH Interface 2.2 COM Components Tunes Rough Procedure 2.3 DllgetClassObject () Implement 2.4 Client 2.5 Small Junction 3. Appendix A I know a little about the DLL 1.1 Unlike Lib DLL 1.2 Debug DLL in LIB. DLL 2.1 Create a DLL 2.2 debug with lib with liberation with libctions with a reference but there is no header file. DLL 3.1 with header file creates a lead information head DLL 3.2 debugging with header files with header files.
First, COM is a better C 1, what Don Box is saying "COM IS Love". The full name of COM is the Component Object Model component object model. 2, from C to DLL to COM2.1 C , such as a software vendor publishing a class library (CMATH four operation), at which time the class library will become an inextensible part of the customer application. Suppose the generated machine code of this library occupies 4MB of space in the target executable. When three applications use the CMATH library, then each executable file contains 4MB library code (see Figure 1.1). When three applications run together, they will take up 12MB virtual memory. The problem is far away. Once the class library vendor finds that the CMATH class library has a defect, release a new class library, which requires all applications that use this class library. There is no other law. Figure 1.1 Three CMATH's three customers 2.2 DLL Solve the above problem is to encapsulate the CMATH class into a dynamic link library (DLL, DYNAMIC LINK LIBRARY). When using this technology, all methods of CMATH will be added to the Export List of the CMATH DLL, and the linker will generate an introduction library. This library exposes the symbol of the CMATH method member. When a customer link is introduced into the library, some settles will be introduced into the executable, which notifies the loader dynamically load CMATH DLL at runtime. When CMATH is in the DLL, his running model is shown in Figure 1.2 CMATH introduction library 2.3 COM "Simply lead C class definition from DLL" This scheme does not provide a reasonable binary component structure. 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. Let's start the com tour. Second, COM Basics 1. COM Basic Know 1.1 Return Value HRESULTCOM requires all methods to return a HRESULT type error number.
HRESULT is actually a type definition: typedef long hresult; related to HRESULT definition See WineError.h file // Values Are 32 bit valuees layed out as Follows: //// 3 2 2 2 2 2 2 2 2 2 1 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 //////////////////////////////////////////////////////////////////////////////////////////////////////10 The facility / '/' s status code We generally have the following macro to judge whether the method is successful: #define successdeded (hr) (long (hr)> = 0) #define failed (hr) (long (hr) <0) 1.2 first 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 (00000000-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 with your proxies, clients and servers ") cpp_quote (" // ") HRESULT QueryInterface ([in] REFIID riid, [out, iid_is (riid )] void ** ppvobject); ulong address (); ulong release ();} [local] property is forbidden to generate 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] Property All the inline pointer specifies a default pointer attribute typedf [unique] iUnknown * lpunkNown; this is a type definition CPP_QUOTE This is a more interesting, this is a method of writing annotations in the IDL file. These annotations will be saved to ***. H and *** _ i.c file [in] indicates that this parameter is incorporated [OUT] means that this parameter is exported [IID_IS (RIID)] indicates that this parameter needs the previous one. RIID parameter. Note: All parameters with OUT properties need to be a pointer type.
1.3 IUNKOWN Interface All Example In addition to IUNKOWN, others should not feel unfamiliar! COM requirements (the most basic requirements) All interfaces need to be inherited from the iUnknown interface, so the iUnknown interface has the "source of evil". The IUNKOWN interface defines three ways. HRESULT Queryinterface ([OUT] void ** ppv); ulong address (); ulong release (); where addReft () and release () are responsible for object reference count, and queryinterface () method is used The interface is implemented in the query. 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. 2, a relatively simple COM this example has four files:
File Name Description Interface.h Interface Class Definition File Math.h and Math.cpp Implementation Class SIMPLE.CPP Main Function Document This Use of Client 2.1 Interface.h File #ifndef Interface_H # Define Interface_h # include
Note: m_cref is used for object counts. When m_cref is 0 component objects, it should be automatically deleted. 2.3 Math.cpp file #include "interface.h" #include "math.h" stdmethodimp cmath :: queryinterface (refiid riid, void ** ppv) {// Here is the function of dynamic_cast, but due to Dynamic_cast and compiler Related. 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 the reference count is RETURN S_OK;} stdmethodimp_ (ulong) cmath :: addRef () {Return m_cref;} stdmethodimp_ (ulong) cmath :: addRef;} stdmethodimp_ (ulong) CMATH: : Release () {ulong res = --m_cref; // Use a temporary variable to cache the modified reference count value (res == 0) // because the data will be illegal after the object has been destroyed. 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 :: factial (int NOP) {Return Calcfactorial (NOP);} int Cmath :: Calcfabonacci (int NOP) {ix (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 CMATH Class definition file. 2.4 Simple.cpp file #include "math.h" #include
// 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 psimth-> queryinterface (IID_IADVANCEDMATH, (void **) & padvmath; if (padvmath) cout << "10 fabonacci is" << "10) << 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. 2.5 Binary Structure of Math Components Figure 1.3 Math Components Binary Structure Figure 2.6 Summary This example is not a true COM component (he is not a DLL) strictly, but he has complied with the minimum requirements of COM (implement the iUnknown interface). Let's take a COM DLL (but not ATL). (to be continued)
- Author: admin-- Published: 2004-12-102: 16: 00--
On the COM technology (two) Author: venture download the source code of the first part of the directory
First, COM is a better C 1. COM is 2. From C to DLL to COM 2.1 C 2.2 DLL 2.3 COM 2, COM foundation 1. COM Basic knowledge 1.1 Return Value HRESULT 1.2 First IDL 1.3 IUNKOWN interface 2 A relatively simple COM 2.1 interface.h file 2.2 Math.h file 2.3 Math.cpp file 2.4 Simple.cpp file 2.5 binary structure of the Math component Figure 2.6 Small knot three, handmade a COM component 1. From construction to implementation Registration 1.1 Creating a type for Win32 DLL Project 1.2 Definition Interface File 1.3 Increase Registration Features 1.3.1 Add a Mathcom.def file 1.3.2 DllRegisterServer () and dllunregisterServer () 1.4 mathcom.cpp file 1.5 Summary 2. Implement IsmipleMath, IadvancedMath interface And DllgetClassObject () 2.1 Implementation of ISMIPLEMATH and IADVANCEDMATH Interface 2.2 COM Components Tunes Rough Procedure 2.3 DllgetClassObject () Implement 2.4 Client 2.5 Small Junction 3. Appendix A I know a little about the DLL 1.1 Unlike Lib DLL 1.2 Debug DLL in LIB. DLL 2.1 Create a DLL 2.2 debug with lib with liberation with libctions with a reference but there is no header file. DLL 3.1 with header file creates a lead information head DLL 3.2 debugging with the header file DLL IV. Small knots, hand-manually created a COM component 1, from the construction of the project to implement the registration in this process we will complete the three steps: Create a DLL entry function, define the interface File, implementation Registration Function 1.1 Creating a type of Win32 DLL project called Mathcom for Win32 DLL project. 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. 1.2 Defining Interface files 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 proced by the midl tool to // produce the type library (mathcom.tlb) and matshalling 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 Factorial ([in] int nOp1, [out, retval] int * pret); HRESULT Fabonacci ([ INT NOP1, [OUT, RETVAL] INT * PRET);}; [UUID (CA3B37EA-E44A-49B8-9729-6E9222CAE844), Version (1.0), Helpstring ("Mathcom 1.0 Typ e Library ")] library MATHCOMLib {importlib (" stdole32.tlb "); importlib (" stdole2.tlb "); [uuid (3BCFE27E-C88D-453C-8C94-F5F7B97E7841), helpstring (" MATHCOM Class ")] coclass MATHCOM {[Default] interface isimath; interface}; check the settings in Project / Setting / MIDL before compiling this project. Correctly set as shown below: Figure 1.4 MIDL's correct settings After the correct settings, if the compilation is no error, then four in the directory of the project
File Name The header file of the MATHCOM.H interface, if you want to declare or define the interface, use this file Mathcom_i.c definition interface and class objects and libraries, only this file is introduced when you want to use something related to GUID. This file can only be introduced throughout the project, otherwise there will be repeated definition Mathcom_p.c Used for stub and proxy DLLDATA.C Unknown 1.3 Increase the registration function as COM must register and log out. 1.3.1 Add a MATHCOM.DEF file DEF file is a 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 the function name @ 4 <- this It is the function serial number private next to DllRegisterServer () and DllunregisterServer (). (The role of other two functions will be described later) 1.3.2 DllRegisterServer () and dllunregisterServer () DllRegisterServer () functions The role is to register the COM server to the unit. The effect of the DllunregisterServer () function is to log out of the COM server from this unit.
1.4 MATHCOM.CPP file now modify the mathcom.cpp file as follows: // Mathcom.cpp: defines the entry point for the dll Application.//include "stdafx.h" #include } 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 File Name Schemes STDAFX.H and Stdafx.cpp Precommination File Mathcom.cppdll Entry Functions and Other Important Functions Defined Local Mathcom.def Module Definition File Mathcom.IDL Interface Definition File (If compiled after 1.2, there should be four files Well, now, my so-called CoM has implemented registration and logout. If you do the following "Regsvr32 absolute path mathcom.dll" is registered, you will register this COM component. After performing this command, check if the HKEY_CLASSES_ROOT / / CLSID item of the registration item is to see if the 3BCFE27E-C88D-453C-8C94-F5F7B97E7841 exists (God bless the existence). 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! ! ! 2. Implement IsmipleMath, IadvancedMath interface and DllgetClassObject () 2.1 Implementation IsMipleMath and IadvanceDmath interfaces Let the original CMATH class to implement the ISMIPLEMATH interface and IadvancedMath interface. The modified place is as follows: 1) Math.h file / * @ ** # --- 2003-10-29 21:33:44 (tulip) --- # ** @ # @ @ 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); PUBLIC: Cmath (); // i inown method (queryinterface) (REFID RIID, VOID ** PPV); stdmethod_ (ulong, addref) (); stdmethod_ (ulong, release) (); // isimath method stdmethod (add) (int) (int) (INT) NOP1, int NOP2, INT * PRET); stdmethod (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) --- # ** @ # incrude "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 1) COM library initialization Using COINITIALIZE Sequence Function (Client) 2) Activation COM (Client) 3) Turn the corresponding DLL into the COM library () 4) Call DllgetClassObject () 4) Call COM Components through the registry entry Function (COM Components) 5) This step is not required by the Class Factory (COM library) This step is not a required 2.3 dllgetClassObject () implementation in Mathcom.cpp to add the following statement, #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; } 2.4 Client 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 named main.cpp in the TestMathcom engineering, this file is as follows: //main.cpp file #include 1) DLLGETCLASSOBJECT (), please see the COM component to transfer the approval process, and also put the breakpoint on the dllgetclassobject () function, take a closer look at his implementation (without achieving the 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) Implementing the iClassFactory interface is not required, but it should be said to be necessary (how to implement it Next chapter) 4) The implementation of DllRegisterServer () and DllunregisterServer () should be grasped. 5) The client requires those files when calling the COM component (as long as the two files generated by the IDL file) 3, the class is appendix A I am a little understanding of the DLL: Write a few simple DLLs and learn about ** .dll and **. LIB. One: DLL1.1 without lib builds a DLL without LIB 1) Create a COM_1.cpp file (note that this DLL does not use) 2) Code below COM_1.CPP 3) Press F5 to run, all things are pressed. 4) the following error should appear: Linking ... Creating library Debug / COM_1.lib and object Debug / COM_1.expLIBCD.lib (crt0.obj): error LNK2001: unresolved external symbol _mainDebug / COM_1.exe: fatal error LNK1120: 1 Unresolved Externals 5) Enter Project | Setting, "Project Options" in the "C / C " intribute box "/ d / '/' _ console / '/'" modified "/ d / '/' _ windows / '/ '". 6) Enter Project | Setting, adding the following compilation switch "/ DLL" in "Project Options" in the "LINK" property box is as follows: kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib Advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib ipbc32.lib odbccp32.lib / NOLOGO / DLL / INCREMENTAL: YES /PDB :"debug/com_1.pdb "/ debug / machine: i386 / out:" Debug /Com_1.dll "/implib:"debug/com_1.lib" / pdbtype: sept Note: "/ DLL" should have a space between the back of the switch //com_1.cpp#include The new code is as follows: #include Our DLL code only needs to modify a little bit, the code is as follows: #include - Author: admin-- Published: 2004-12-10 2: 19: COM Technology Exploration 00-- (c) - a real COM Author: venture a download the source code to achieve ISmipleMath, IAdvancedMath interfaces and DllGetClassObject ( 1.1 Implementing the ISMIPLEMATH and IADVANCedMath interfaces Let us implement the original CMATH class (CMATH is actually "CMTH) Class Class in the CM Technology (2) CMATH Class ISMIPLEMATH interface and Iadvancedmath interface. The modified place is as follows: 1) Math.h file / * @ ** # --- 2003-10-29 21:33:44 (tulip) --- # ** @ # @ @ 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); PUBLIC: Cmath (); // i inown method (queryinterface) (REFID RIID, VOID ** PPV); stdmethod_ (ulong, addref) (); stdmethod_ (ulong, release) (); // isimath method stdmethod (add) (int) (int) (INT) NOP1, int NOP2, INT * PRET); stdmethod (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 "math.h" stdmethodimp cmath :: queryinterface (refiid riid, void ** ppv) {// Here This is the function of achieving Dynamic_cast, but because Dynamic_CAST is related to the compiler. if (riid == IID_ISimpleMath) * ppv = static_cast (Client) 2) Activate COM (Client) 3) Turn the corresponding DLL into the COM library (COM Run Environment) 4) Call the DllgetClassObject () export function (COM component) 5) in the COM component via the registry key By the class factory return to the interface pointer (if the client does not need to cache the class factory interface pointer when you create a component using CoCreateInstance, this step is not returned to the client in the COM runtime, while immediately entering step 6. Instead, the client caches the component class factory interface pointer. This method is useful when the customer needs to create multiple instances.) (COM library) 6) Call CREATEINSTANCE Create a component instance via a class plant interface pointer. 1.3 DllgetClassObject () Implementation in Mathcom.cpp Add the following statement #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) {IF ( Rclsid == CLSID_MATHCOM) {RETURN PM_MATH-> QueryInterface (riid, ppv);} return class_e_classnotavailable;} 1.4 Client Next We write a client program to test this COM. The new empty name is a Win32 Console project to Mathcom Workspace is added to MATHCOM WORKSPACE. Add a file named main.cpp in the TestMathcom engineering, this file is as follows: //main.cpp file #include file effect MathcomstDafx.h and stdafx.cpp pre-compiled file Mathcom.cppdll Entrance function and other important function defined places MATHCOM.DEF module definition file MATHCOM.IDL interface definition file (if compiled after 1.2) Math. H and Math.cppismiPLEMATH, IADVANCEDMATH interface Implementation class Testmathcommain.cppmathcom's client, used to test Mathcom Components In this section we have completed a practical approach to complete COM components (no intact place is still DLLCanunloadNow) ))). 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 () role (for details of this function See << COM Nature >> P86), please see the COM component to transfer the approval process, Also hit the breakpoint on the DllgetClassObject () function, take a closer look at his implementation (without achieving the 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) Implementing the iClassFactory interface is not required, but it should be said to be necessary (how to implement it Next chapter) 4) The implementation of DllRegisterServer () and DllunregisterServer () should be grasped. 5) The client requires those files when calling the COM component (as long as two files generated by the IDL file) II, class factory 2.1 review in the last section, we create the component instance and get the interface pointer as follows: First The client user calls COM API COCREATEINSTANCE. This function calls another COM API COGETCLASSOBJECT to get the component's class factory interface pointer. At this time, the COM library will load component DLL (Exe is slightly different, we will explain in the later chapter) The export function DllgetClassObject (), obtains the method of the class factory, which is called the class factory. CreateInstance, creates an object instance and obtains the required interface pointer by queryinterface () of the component object. 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 Increase ICLASSFACTORY This time we will modify the files as follows file name Modify attribute Mathcommathcom.cpp Modify MathFactory.h and MathFactory.cpp New TestMathcommain.cpp Modified 2.2.1 Mathcom.cpp #include "Math.h" #include "Mathcom_i.c" #include "MathFactory.h" server lock, if the logo is S_OK, you can uninstall the server, // about the reference count and the server with the server, and then explain 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; / / / / General COM hopes 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 } STDMETHODIMP CMathFactory :: QueryInterface (REFIID riid, void ** ppv) {* ppv = NULL; if (riid == IID_IUnknown || riid == IID_IClassFactory) {* ppv = static_cast // Really create an object hr = pclassfactory-> createInstance (NULL, IID_ID_IMPLEMATH, (VOID **) & psimpty); // This method is the advantage that multiple objects can be created at a time, no need to test the IDispatch interface if (successited) HR)) {hr = psimplemath-> add (10, 4, & nreturnValue); if (succeededed (hr)) cout << "10 4 =" << nreturnValue << endl; nreturnValue = 0;} // Query object Interface implemented IAdvancedMath hr = pSimpleMath-> QueryInterface (IID_IAdvancedMath, (void **) & pAdvancedMath); if (SUCCEEDED (hr)) {hr = pAdvancedMath-> Fabonacci (10, & nReturnValue); if (SUCCEEDED (hr)) cout < <"10 fabonacci is" << nreturnValue << Endl;} padvancedmath-> release (); psimplemath-> release () ;: couninitialize (); return;} 2.3 Skumping In this section we implemented the IclassFactory interface, you can say A real COM object is implemented, we can use a general COM client method in C to create objects, execute 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. Third, implementation interface In order to use COM components in the scripting language environment, the COM specification specifies that the COM to be used in the scripting language environment must implement the IDispatch interface. At this time, the COM interface is called a distribution interface. Remember the contents of the interface we describe the interface? At that time, we didn't set this instructions for the interface: Custom and Dual. The former is a custom interface, that is, the interface derived from iUnknown. The latter is the interface derived from Idispatch, of course Idispatch must also be derived from iUnknown. This COM component can only be used without supporting a pointer and a scripting environment when the interface is derived from iDispatch. Now let our components also support dual interfaces. 3.1 IdisPatch interface IDSPATCH interface has four methods, which is only important (Invoke). Other methods We are temporarily unable to do it. If the reader is interested, you can refer to the relevant information. It is not very difficult. You can hand over interface processing such as getidsofName and so on. It may be complex here. Let's explain to readers later. Our MATHCOM components also only implements the Invoke method, and other methods are returned to E_NOTIMPL indicating that there is no implementation. For IDSPATCH interface, please refer to the MSND document or << COM nature >> P295 page 3.2 Supporting the MATHCOM component of the distribution interface To allow our MATHCOM components to support dual interface, you need to modify the following file engineering name file name Mathcommathcom.idl Math.h and Math.cppTestMathCommain.cpp 3.2.1 Modify Mathcom.Idlmathcom.idl files need to modify three places. 1) Increase the DAUL attribute to indicate that our interface is a dual interface. 2) Base class of the interface by IUNKNOW interface 3) 3) Each method of the interface plus the modified mathcom.IDL modified by the serial number attribute (please find a modified place) // mathcom.idl: IDL SOURCE FOR MATHCOM.DLL this file will be processed by the mid t t / p p; ÄIDL.IDL "; Import" OCIDL.IDL "; [UUID (FAEAE6B7-67BE- 42A4-A318-3256781E945A), Helpstring ("Isimplemath Interface"), Object, Dual, // This identifies that we have never encountered. Pointer_Default (unique)] interface isimath: idispatch {[ID (1)] HRESULT ADD ([in] int NOP1, [IN] int NOP2, [OUT, RETVAL] INT * PRET); [ID (2)] HRESULT SUBTRACT INT NOP1, [IN] int * PRET); [ID (3)] HRESULT MULTIPLY ([in] int NOP1, [IN] int NOP2, [OUT, RETVAL] INT * PRET); [ID (4)] HRESULT DIVIDE ([in] int NOP1, [IN] int NOP2, [OUT, RETVAL] INT * PRET);}; [UUID (01147c39-9da0-4f7f-b525-d129745aad1e), Helpstring ("Iadvancedmath Interface", Object, Dual, Pointer_Default (unique)] Interface Iadvancedmath: idispatch {[ID (1)] HRESULT FACTORIAL ([in] int NOP1, [OUT, RETVAL] INT * PRET); [ID 2)] HRESULT FABONACCI ([in] int NOP1, [OUT, RETVAL] INT * PRET);}; [UUID (CA3B37EA-E44A-49B8-9729-6E92222CAE844), 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}; 3.2.2 Modify Math.h file in MA Th.H Add four ways to declare the IDispatch interface and implement three simple implementations. After the modified Math.h, see // The same cmath (); // iUryinterface (Refiid Riid, Void ** PPV); stdmethod_ (ulong, addref) (); stdmethod_ (ulong, release) () ; // IDispatch MethodSTDMETHOD (GetTypeInfoCount) (UINT * pit) {return E_NOTIMPL;} STDMETHOD (GetTypeInfo) (UINT it, LCID lcid, ITypeInfo ** ppti) {return E_NOTIMPL;} STDMETHOD (GetIDsOfNames) (REFIID riid, OLECHAR ** pNames, UINT nNames, LCID lcid, DISPID * pdispids) {return E_NOTIMPL;} STDMETHOD (Invoke) (DISPID id, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS * pd, VARIANT * pVarResult, EXCEPINFO * pe, UINT * pu) ; // isimath methodStdMethod (add) (int NOP1, INT NOP2, INT * PRET); stdmethod (int NOP1, INT NOP2, INT * PRET); stdmethod (INT NOP1, INT NOP2, INT * PRET) ); Stdmethod (int NOP1, INT NOP2, INT * PRET); // The same 3.2.3 modify the implementation of the IdisPatch interface in the IDispatch interface. The modified Math.cpp file is shown below // front of the same cmath :: cmath () {m_cref = 0;} / ********************** ***************************************************** FUNCTION DECLARE: CMATH :: INVOKE * EXPLAIN: Idispatch interface Invoke method * parameters: * Dispid ID - Method scheduling ID (compared to IDL in the IDL) * Refiid Riid - Interface IID * LCID LCID - Language ID * Word WFLAGS - - * Dispparams * PD - Incoming parameter structure (for specific structure) * Variant * PvarResult - Export parameter (Variant See the MSDN document or << in-depth analysis ATL >> p56 * excepinfo * PE - - Abnormal (general null) * uint * pu - * return: * stdmethodimp - * Author: Tulip * Time: 2003-10-30 15:56:37 ************ *********************************************************** ****** / stdmethodimp cmath :: Invoke (Dispid ID, Refiid RIID, LCID LCID, Word WFLAGS, Disprams * Pd, Variant * PvarResult, Excepinfo * PE, UINT * PU) {IF (RIID == IID_ID_IMPLEMATH) { IF (1 == id) Return Add (PD-> Rgvarg [0] .intval, PD-> Rgvarg [1] .intval, & pvarresult-> intVal); Else IF (2 == id) Return Subtract (PD-> Rgvarg [0] .intval, pd-> rgvarg [1] .intval, & pvarresult-> intVAL); Else IF (3 == id) Return Multiply (PD -> Rgvarg [0] .intval, pd-> rgvarg [1] .intval, & pvarresult-> intVal); Else IF (4 == id) Return Divide (pd-> rgvarg [0] .intval, pd-> rgvarg [1] .intVal, & pvarresult-> intVal); Else Return E_FAIL;} else if (riid == iid_iadvancedmath) {if (1 == id) Return Factorial (PD-> Rgvarg [0] .intval, & pvarResult-> intVal ELSE IF (2 == id) Return Fabonacci (PD-> Rgvarg [0] .intval, & pvarresult-> intVal); Else Return E_FAIL;} Else Return E_NOINTERFACE;} After the modification, the above three files, please recompile (If you have moved overhead before registration, re-register) 3.2.4 Modify Main.cpp file Modifying the main purpose of the main.cpp file to test our components through the INVOKE method in the iDispatch interface. Encountered main.cpp files are shown in #include HRESULT hr = :: CoInitialize (NULL); ISimpleMath * pSimpleMath = NULL; IAdvancedMath * pAdvancedMath = NULL; IDispatch * pDispatch = NULL; // distribution interface pointer int nReturnValue = 0; hr = :: CoCreateInstance (CLSID_MATHCOM, CLSCTX_INPROC, NULL, IID_ISIMPLEMATH, (VOID *) & psimpty; / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / << endl; ccomvariant varresult; ccomvariant varresult2; ccomvariant * pvars = new ccomvariant [2]; ccomvariant * pvars2 = new ccomvariant [1]; varresult.clear (); pvars [1] = 4; pvars [0] = 10; DISPPARAMS disp = {pvars, NULL, 2, 0}; hr = pDispatch-> Invoke (0x1, IID_ISimpleMath, LOCALE_USER_DEFAULT, DISPATCH_METHOD, & disp, & varResult, NULL, NULL); if (SUCCEEDED (hr)) cout << "10 4 = "<< varresult.int2.Clear (); pvars2 [0] = 10; Dispparams Disp2 = {PVARS2, NULL, 1, 10}; hr = pdispatch-> invoke (0x2, IID _Iadvancedmath, locale_user_default, dispatch_method, & disp, & varresult2, null, null; if (succeeded (hr)) cout << 10 fabonacci is "<< varresult2.intval << endl; cout <<" iDispatch interface test "<< Endl; :: system ("pause");} / * * iDispatch interface test * / if (succeeded (hr)) {hr = psimpty-> add (10, 4, & nreturnValue); if (successded (HR)) Cout << "10 4 =" << nreturnValue << Endl; NRETURNVALUE = 0;} // Query object implemented interface Iadvancedmath HR = psimplemath-> QueryInterface (IID_IAdvancedMath, (void **) & pAdvancedMath); if (SUCCEEDED (hr)) {hr = pAdvancedMath-> Fabonacci (10, & nReturnValue); if (SUCCEEDED (hr)) cout << "10 Fabonacci is" << nReturnValue << Endl;} padvancedmath-> release (); psimplemath-> release (); pdispatch-> release () ;:: counitialize (); return;} quad summary is really happy, finally paying. Let's take a look at it, what we have done, we implemented a class factory, achieving a real COM object, and in order to use COM without supporting a pointer and a script environment, we have implemented the IDSPATCH distribution interface. As for why Idispach, iDispatch is implemented, which is the concept of early bundling and late bundle. We will explain in the next chapter. I hope everyone can see that there is no direction here. However, there are still many things you see, but I don't know what it is, I don't hurry. Slowly, I will tell these concepts in detail later. Now I want you to know that a COM component is roughly created, and COM has a certain macro understanding. After all, my level is limited, there is no master's explanation. I just share my understanding of COM. I hope everyone will progress together. In the first part, I think everyone knows the benefits of COM. Next, we see the COM core structural map (all the examples are centered on Figure 1.3). In the third part, I Step by Step tells how to implement a complete COM component. The COM principle is relatively simple, but it is more flexible when implementing, this has caused most people feel difficult to master, in fact, as long as the essence of COM, the other things are relatively simple. If you understand the "**", you know most. If you completely understand what is interface class, implement class, class object, and the relationship between them, then you have advanced a big step. Finally, I hope that everyone can feel happy in learning COM. I have time to communicate together in the future, haha !! "COM is love". Five-Reference Information COM (in addition to Pan Amin in COM, you can see if there are all things in China.) << COM Nature >> DON BOX (If you haven't seen this book, your COM Just like that ^ _ ^) << COM technology insider >> (more shallow, suitable for entry) << COM principle Implementation and application >> (Pan Aiming, this book is more detailed in detailing several core applications of COM) ATL aspect