COM library functions
--------------------------------
Using COM library functions to use code components is the most troublesome and difficult method described in this article. It requires developers to have a deep understanding of the principles of COM. The steps for implementing this method are as follows:
1. First add the COM initial and termination code. Add the following code to the initialization instance function InitInstance () of the application class:
CoInitialize (NULL );
......
CoUnInitialize ();
The preceding statement runs in the MFC framework or non-MFC framework. However, because the program in this article uses the MFC framework, you can also use the AfxOleInit () function to initialize it.
2. Use the # include statement to include the reference to the component header file and create the component object. The header file contains the C ++ definition of the interface and the symbolic constant that describes the interface id iid and the class id clsid. Create a job in the initialization dialog box function:
IAccount pAccount = NULL;
......
CoCreateInstance (CLSID_Account,
NULL,
CLSCTX_INPROC_SERVER,
IID_Iaccount,
Reinterpret_cast (& pAccount ));
3. Finally, release the component object. This work should be completed before the program exits, for example, in the response function of message WM_CLOSE:
If (pAccount! = NULL)
PAccount-> reallocate ();
To call other functions in the Code component, you can use the interface pointer pAccount of the component object:
......
BSTR bstrResult;
PAccount-> Post (100, bstrResult );
SysFreeString (bstrResult );
......
Because the COM Support class is defined in comdef. h, you must include a reference to this header file to make the program run normally.
--------------------------------
Class Wizard
--------------------------------
You can use the Class Wizard to directly read the component type library and generate classes for each interface in the packaging type library. The member functions of these classes can access the methods and properties of the component interface, the method is similar to that of ActiveX control.
First, add the code to initialize the COM component. We can add the. tlb Library file of the component through the From a Type Library in the Class Wizard and introduce its interface class. The Type Library File introduced in this example only contains an IAccount of the component packaging class derived from the ColeDispatchDriver. Through the members of the packaging class, you can understand what services the component interfaces can provide and access the methods and attributes of the component interfaces through them.
In the initialization dialog box, use the CreateDispatch () member function of the COleDispatchDriver class to create an Account component object:
IAccount m_account;
......
M_account.CreateDispatch ("ATLSample. Account.1 "));
The ProgID value "ATLSample. Account. 1" can be found through the OLE View tool in Microsoft Visual Studio Tools 6.0, provided that the component has been successfully registered.
You can also use the releasedispatch () function of the coledispatch-Driver Class to release the account component object.
The post method used in the com library function method can be called using the following methods:
Cstring STR = m_account. Post (100 );
It can be seen that this method implements the same function, but it is easier to implement than the previous method, and the requirements for understanding com are not high.
--------------------------------
# Import command
--------------------------------
# The import command method is very simple. This command is very suitable for type library files, because the path is fixed for type library files, whether it is the debug version or the release version. # The import command extracts two files from the type library to be introduced during execution: One. tlh file and. TLI file, the latter is only the function implementation of the packaging class, and the former contains a lot of important information. Smart interface pointers are also defined here:
_ Com_smartptr_typedef (iaccount ,__ uuidof (iaccount ));
During actual compilation, the compiler expands it into the following code and defines a smart pointer iaccountptr for the iaccount interface through the _ com_ptr_t template class. It is a smart pointer because it automatically processes cocreate-instance and all iunknow methods when replacing iaccount, which is very convenient to use:
Typedef _ com_ptr_t <_ com_iiid <iaccount ,__ uuidof (iaccount)> iaccountptr;
With smart pointers, we can call the createinstance () function of the _ com_ptr_t template class to create interface pointers:
IAccountPtr m_account = NULL;
M_account.CreateInstance (_ uuidof (Account ));
Because. the tlh file contains the structure declaration and declspec (uuid ("") Declaration. Therefore, you can easily use _ uuidof (Account) to obtain the GUID of the interface. The declspec (uuid ("") Statement associates the GUID with the class and each interface, allowing developers to use the uuidof operator to obtain the GUID of the class and interface.
Note: To prevent name conflicts between the original code and the newly introduced code, the compiler defines a namespace identified by the Type Library name, and add an identifier to any name declared in it. To avoid specifying the namespace identifier, you can add using namespace after the # import Statement, and use rename_namespace to change the namespace. For example, you can perform the following operations in this example:
# Import "Account. tlb" rename_namespace ("AccountDriver ")
Using namespace AccountDriver;
In this way, you only need to define the Smart interface pointer IAccountPtr:
IAccountPtr m_account;
The call to functions and attributes in the Code component is the same as that in the first two methods, and the access is completed through m_account. Because of the introduction of the _ com_ptr_t template class and smart pointer, the # import command method is the simplest method to use the COM component among the three methods.
----------------------------------------------------------------------------
----------------------------------------------------------------------------
Prerequisites:
The COM server is an in-process server, and the DLL name is simpCOM. dll. This component has only one interface IFoo, and this interface has only one method HRESULT SayHello (void)
Call in SDK
============================================
1. The simplest and most common method is to use the # import Type Library and the smart pointer packaging class provided by VC.
DEMO code:
# Import "D: \ Temp \ vc \ simpCOM \ Debug \ simpCOM. dll" no_namespace
CoInitialize (NULL );
{
IFooPtr spFoo = NULL;
SpFoo. CreateInstance (_ uuidof (Foo ));
SpFoo-> SayHello ();
}
CoUninitialize ();
2. Import the *. h, * _ I. c file generated by midl.exe and call it using the CoCreateInstance function.
DEMO code:
/* Add the * _ I. c file to the project. For example, the simpCOM_ I .c file in this example defines the guid value of the class and interface. If it is not introduced, a connection error occurs. */
# Include "D: \ temp \ Vc \ simpcom. H"
Coinitialize (null );
Ifoo * pfoo = NULL;
Hresult hR = cocreateinstance (clsid_foo, null, clsctx_all, iid_ifoo, (void **) & pfoo );
If (succeeded (HR) & (pfoo! = NULL ))
{
Pfoo-> sayhello ();
Pfoo-> release ();
}
Couninitialize ();
3. Use cocreateinstance to obtain the class factory object interface directly using cogetclassobejct, and then use the createinstance method of this interface to generate an instance.
DEMO code:
/* Preparations are described in method 2 */
Iclassfactory * PCF = NULL;
Hresult hR = cogetclassobject (clsid_foo, clsctx_all, null, iid_iclassfactory, (void **) & PCF );
If (succeeded (HR) & (PCF! = NULL ))
{
Ifoo * pfoo = NULL;
HR = PCF-> createinstance (null, iid_ifoo, (void **) & pfoo );
If (SUCCEEDED (hr) & (pFoo! = NULL ))
{
PFoo-> SayHello ();
PFoo-> Release ();
}
Pcf-> Release ();
}
4. You do not need to use CoCreateInstance or CoGetClassObject to directly obtain DllGetClassObject from the dll, and then generate class objects and class instances (this method is suitable for you to use a component, but do not want to register this component in the Registry)
DEMO code:
/* Preparations are described in method 2. In fact, you only need to get the definition of CLSID and IID and interface */
Typedef HRESULT (_ stdcall * pfnGCO) (REFCLSID, REFIID, void **);
PfnGCO fnGCO = NULL;
HINSTANCE hdllInst = LoadLibrary ("D :\\ Temp \ vc \ simpCOM \ Debug \ simpCOM. dll ");
FnGCO = (pfnGCO) GetProcAddress (hdllInst, "DllGetClassObject ");
If (fnGCO! = 0)
{
IClassFactory * pcf = NULL;
HRESULT hr = (fnGCO) (CLSID_Foo, IID_IClassFactory, (void **) & pcf );
If (SUCCEEDED (hr) & (pcf! = NULL ))
{
Ifoo * pfoo = NULL;
HR = PCF-> createinstance (null, iid_ifoo, (void **) & pfoo );
If (succeeded (HR) & (pfoo! = NULL ))
{
Pfoo-> sayhello ();
Pfoo-> release ();
}
PCF-> release ();
}
}
Freelibrary (hdllinst );
Call in MFC
============================================
In addition to the above methods, there is also a more convenient method in MFC, that is, using classwizard to generate a packaging class using the type library, however, the premise is that the COM Component Interface must be derived from idispatch.
Specific Method:
1. Press Ctrl + W to bring up the Class Wizard, press add class to bring up a new menu, select from a type Libarary, and then go to simpcom. DLL, and then all the interfaces in the simpcom will come out. After selecting the interface packaging class you want to generate, The Wizard will automatically generate the corresponding. CPP and. h file.
In this way, you can use the COM component like a common class in your MFC project.
DEMO code:
Coinitialize (null );
Ifoo Foo;
If (FOO. createdispatch ("simpcom. foo ")! = 0)
{
Foo. sayhello ();
Foo. releasedispatch ();
}
Couninitialize ();
----------------------------------------------------------------------
Call service components in a VC program
1. run VC 6.0 and use the MFC program Wizard to create a new dialog box-based MFC application.
2. Use # import to import the service component, copy prjado. DLL to the VC project directory, open the stdafx. h file, and add the following code:
# Import "prjado. dll"
Using namespace prjado;
This code should be placed in:
// {Afx_insert_location }}
// Microsoft Visual C ++ will insert additional declarations after immediately and before # endif.
Importing a DLL in stdafx. h file allows the compiler to connect to the DLL Type Library at runtime. # import it to automatically generate a guids definition and automatically generate a clsado object encapsulation. You can also list the types that can be found in the class. VC ++ will automatically generate two files during compilation:
A header file (. tlh) that contains the enumerated types and definitions of objects in the Type Library;
An implementation file (. TLI) encapsulates methods in the object model of the Type Library.
Namespace is used to define a namespace. You can use unsing to convert the current type context to the location specified by the namespace, so that we can access the service component method.
If we modify the service component program, we recommend that you delete these two files and re-compile the project completely so that the compiler can re-List class attributes and functions.
3. Add a button in the dialog box and set the title to "test ". Double-CLICK the test button. The system prompts you to create a CLICK event corresponding to the OnButton1 function. The code for the OnButton1 function is as follows:
HRESULT hresult;
CLSID clsid;
CoInitialize (NULL );
// Initialize the COM interface
Hresult = CLSIDFromProgID (OLESTR ("prjado. clsado"), & clsid );
// Obtain the CLSID of the component.
_ Clsado * t;
// This is the class we defined in PRJADO. DLL.
Hresult = CoCreateInstance (clsid, NULL, CLSCTX_INPROC_SERVER ,__ uuidof (_ clsado), (LPVOID *) & t );
Initialize CLSADO. The first parameter of CoCreateInstance () is the CLSID (Class Code) of the object. The 128-bit code uniquely identifies the component service, its path and running parameters are stored in the system registry. The second parameter is generally set to NULL. The third parameter is used to specify the running environment of the object, such as remote or local, it is set to CLSCTX_INPROC_SERVER, indicating that the service component is a DLL; the fourth parameter indicates the ID used to communicate with the object interface, which is also a 128-bit code; the fifth parameter is the interface pointer used to receive objects.
If (FAILED (hresult ))
{
AfxMessageBox ("service component initialization failed ");
Return;
}
// If initialization fails, exit the program after the prompt dialog box is displayed.
T-> ado_Init ();
// Call the initialization Function
T-> ado_add ("calling components from VC ");
// Call the Add record Function
T-> ado_UnInit ();
// Call the function to close the connection
T-> Release ();
// Release the interface pointer
CoUninitialize ();
// Close the COM library connection
AfxMessageBox ("service component invocation completed ");
Save the project and compile and run the VC program. Click the "test" button. After the prompt is completed, open the database and you will see the added record.