I. Preface
We Use ATL to write a simple COM component. The reason for this is that only one custom interface (IFun) is implemented in the component. Of course, if you want to be lazy, we can add all 200 functions to this interface. If so, no one will like to use this component. Since a component can provide multiple interfaces, we should classify functions according to their functions during design, and present functions of different function classifications using multiple interfaces. This provides the following benefits:
1. The number of functions in an interface is limited and functions are concentrated. Users can easily learn, remember, and call functions. How many functions does an interface provide? The answer is: if you are a gorilla, a single interface can have up to three functions. If you are a human, it is best to have no more than seven functions for one interface. (Note 1)
2. easy to maintain. At least it is easier for you to search by the naked eye.
3. Easy to upgrade. When adding a function to a component, do not modify the published interface, but provide a new interface to complete function expansion. (Note 2)
This book is written in ------ how to implement one component and multiple interfaces.
Ii. Interface Structure
Figure 1. component A has two custom interfaces. Component B is an upgrade of component.
One day, we designed component A, which has two custom interfaces. IMathe has the Add () function to complete the integer addition, and IStr has the function Cat () to complete the string connection. One day later, we upgraded component A to component B to add A function Mul () to complete integer multiplication. Note that since we have published component A, we cannot arrange this function in the IMathe interface of the old interface. The solution is to define another interface IMathe2, Add the Mul () function to the new interface, and retain the Add () function. In this way, the old user does not know the existence of the new interface IMathe2, and he still uses the old interface IMathe; while the new user can discard IMathe and directly use the new interface function of IMathe2. Look, how smooth the upgrade is!
Iii. Implementation
3-1,First, Use ATL to implement a COM component of the custom (M m) interface IMathe, and complete the Add () integer addition function in the interface.
Note !!!It must be a custom interface (dual interface will be introduced later ). If you do not understand this operation, please read my previous article again.
3-2,View the IDL file. After completing the previous step, open the IDL file with the following content: (the name and UUID will be different from the IDL in your program)
1 import "oaidl.idl";
2 import "ocidl.idl";
3 [
4 object,
5 uuid(072EA6CA-7D08-4E7E-B2B7-B2FB0B875595),
6 helpstring("IMathe Interface"),
7 pointer_default(unique)
8 ]
9 interface IMathe : IUnknown
10 {
11 [helpstring("method Add")] HRESULT Add([in] long n1, [in] long n2, [out,retval] long *pnVal);
12 };
13 [
14 uuid(CD7672F7-C0B4-4090-A2F8-234C0062F42C),
15 version(1.0),
16 helpstring("Simple3 1.0 Type Library")
17 ]
18 library SIMPLE3Lib
19 {
20 importlib("stdole32.tlb");
21 importlib("stdole2.tlb");
22 [
23 uuid(C6F241E2-43F6-4449-A024-B7340553221E),
24 helpstring("Mathe Class")
25 ]
26 coclass Mathe
27 {
28 [default] interface IMathe;
29 };
30 };
1-2 |
Introduce other interface description files defined by IUnknown and ATL. Import is similar to # include in C. |
3-12 |
Complete description of an interface |
4 |
Object indicates that this block describes an interface. The IDL file adopts the PRC remote data exchange format description. |
5 |
The IID of the uuid (...) interface, which is automatically generated by ATL and can be manually modified or generated by guidgen.exe (note 3) |
6 |
You can see this prompt in some software or tools. |
7 |
Define the default properties of the pointer used by parameters in the interface function (note 4) |
9 |
The interface is called IMathe and is derived from IUnknown. Therefore, the first three functions of the IMathe interface must be QueryInterface, AddRef, and Release. |
10-12 |
Interface function list |
13-30 |
The complete description of the Type Library (the concept of the Type Library will be discussed later). The lines described below need to be understood first. |
18 |
# Default namespace during import |
23 |
CLSID of the component. The first parameter of CoCreateInstance () is |
27-29 |
Interface list |
28 |
[Default] indicates who provides the IUnknown Interface |
3-3Manually modify the IDL file. The black text is manually entered. Save the settings.
Import "oaidl. idl ";
Import "ocidl. idl ";
[
Object,
Uuid (072EA6CA-7D08-4E7E-B2B7-B2FB0B875595 ),
Helpstring ("IMathe Interface "),
Pointer_default (unique)
]
Interface IMathe: IUnknown
{
[Helpstring ("method Add")] HRESULT Add ([in] long n1, [in] long n2, [out, retval] long * pnVal );
};
[// The so-called manual input is actually skillful: copy and paste the above interface description (IMathe), and then modify it more conveniently.
Object, uuid (072EA6CB-7D08-4E7E-B2B7-B2FB0B875595 ),
// The IID generated manually or using a tool
Helpstring ("IStr Interface "),
Pointer_default (unique)
]
Interface IStr: IUnknown
{
// No interface functions};[Uuid (CD7672F7-C0B4-4090-A2F8-234C0062F42C), version (1.0), helpstring ("Simple3 1.0 Type Library ")
]
Library SIMPLE3Lib
{
Importlib ("stdole32.tlb"); importlib ("stdole2.tlb ");
[
Uuid (C6F241E2-43F6-4449-A024-B7340553221E ),
Helpstring ("Mathe Class ")
]
Coclass Mathe
{
[Default] interface IMathe;
Interface IStr;// Don't forget, there is another one here
};
};
3-4, Open the header file (Mathe. h), manually add the class derivation relationship and interface entry table, and then save.
Class ATL_NO_VTABLE CMathe:
Public CComObjectRootEx <CComSingleThreadModel>,
Public CComCoClass <CMathe, & CLSID_Mathe>,
Public IMathe, // do not forget to add a comma here
Public IStr// Add a base class
{
Public:
CMathe ()
{
}
DECLARE_REGISTRY_RESOURCEID (IDR_MATHE)
DECLARE_PROTECT_FINAL_CONSTRUCT ()
BEGIN_COM_MAP (CMathe) // interface entry table. The interface entered here can be found by QueryInterface ()
COM_INTERFACE_ENTRY (IMathe)
COM_INTERFACE_ENTRY (IStr)
END_COM_MAP ()
3-5All right, everything is ready. Next, you can add a function to the IStr interface. The following example adds a function for string connection:
HRESULT Cat ([in] BSTR s1, [in] BSTR s2, [out, retval] BSTR * psVal); if you do not know how to do this, read the content of the first three times.
Iv. Interface upgrade
We have released this component, but suddenly we need to add another function on the IMathe interface one day... no!
It cannot be directly modified on IMathe! What should I do? Solution: ------ add another interface. Let's call it IMathe2,
If you want to add a function later, we will add another interface called IMathe3.
4-1Modify the IDL file. If you understand the content in the above section, it is very easy to add an interface.
import "oaidl.idl";
import "ocidl.idl";
[
object,
uuid(072EA6CA-7D08-4E7E-B2B7-B2FB0B875595),
helpstring("IMathe Interface"),
pointer_default(unique)
]
interface IMathe : IUnknown
{
[helpstring("method Add")] HRESULT Add([in] long n1, [in] long n2, [out,retval] long *pnVal);
};
[ object,
uuid(072EA6CB-7D08-4E7E-B2B7-B2FB0B875595),
helpstring("IStr Interface"),
pointer_default(unique)
]
interface IStr : IUnknown
{
[helpstring("method Cat")] HRESULT Cat([in] BSTR s1, [in] BSTR s2, [out,retval] BSTR *psVal);
};
[
object,
uuid(072EA6CC-7D08-4E7E-B2B