Imagine a person learning to drive the driving process may be like this: First, he wants to know the basic knowledge of the car structure, then learn some basic actions (such as plugging key, ignition, throttle, clutch, brake, steering, etc.). With these skills, it is basically concluded that he can drive the car. It can be just simple to turn the car, and it does not mean that it has become a qualified driver. Therefore, in addition to basic skills, he must also master a large number of traffic regulations and automotive maintenance knowledge. After that, it is an excellent driver, and he is lacking is a rich practical experience.
The study process of COM is also true. First of all, we need to know the core most basic idea of COM (the skills you can do), then learn more about the COM world (the study of traffic regulations), and finally the cultivation of practical experience.
Next, we will gradually enter the world of COM according to this idea.
COM principle
What is the principle of COM? Simply put, it is to use the C base class pointer to call the virtual function implemented by the derived class.
In C , according to C , it is necessary to do some adjustments to our usual design habits. This adjustment is very simple and convenient to do not involve specific "traffic rules", and do not need to be except Knowledge outside C language.
First, you must clear the concept of abstract base class.
In the C language, if a class contains a pure virtual function, this class is automatically mad into an abstract class. This class itself cannot be instantiated unless a related pure virtual function is implemented in its derived class, its derived class cannot be instantiated. We do more stringent restrictions on this:
A A abstract base class cannot contain data members
b An abstract base class cannot contain non-pure virtual functions
C A abstract base class cannot be derived from non-abstract base classes
Second, apply the abstract base class to the program.
We need to score different abstract base classes in accordance with the function, each base class declare the generic function prototypes that the type function needs to be provided. A class that implements the specific function should inherit the self-corresponding abstract base class and complete the implementation of the function prototype declared in the abstract base class.
Finally, the module classified according to the logical function is produced in the form of a distributable and heavy, which is the understanding and application of the dynamic link library.
Abstract base classes are called "interface" in COM.
There are three concepts in COM to be clarified now. That is the library, classes, and interfaces. The library can be understood as the dynamic link library itself, usually the library is the minimum unit that can be distributed. A library contains one or more classes, this "class" is different from the concept of category C language, which refers to a collection of one or more logically associated interfaces. The interface is as the abstract base class we will say, it defines the prototype of a group of methods.
COM itself has developed a pile of predefined interfaces, and the implementation must implement one or more of them. It is such a wide interface that makes COM look into a difficult to understand. Let's talk about it, that is, the iUnknown interface and the iClassFactory interface.
The IUNKNOWN interface defines the prototype of 3 methods:
1) AddRef: Reference counting increment operation
2) Release: Reference counting reduction operation, if the reference count is zero, destroy the current object.
3) QueryInterface: Other interface pointers in the same class object from the current interface.
The iClassFactory interface defines two ways:
1) CREATEINSTANCE: Create a class instance and return a user specified interface pointer.
2) LOCKSERVER: Make sure that the implementation of this service resides in memory, you can get the best performance when you call CREATEINSTANCE multiple times.
The IunkNown interface is a ancestors of all interfaces. In addition to all interfaces outside the iUnknown interface, you must be derived from iUnknown directly or indirectly. This interface provides a reference count prototype to control the lifetime of the interface. The COM standard requires that each class (a) should have a class (b) that implements the iClassFactory interface, which is responsible for creating an instance of class (a) by this class (b) that implements iClassFactory. So who is this class (b) created again? COM specifies that each COM can distribute objects, that is, the DLL, must implement a DLLGETCLASSOBJECT, which creates the corresponding class (b) object instance.
There are still many optional predefined interfaces, such as iDispatch, iMoniker, IPersist, IconnectionPoint .... When you start learning COM, you can't get into these interface traps, so we may wish to wrap.
Next, we use an example to simply practice. In order not to refer to knowledge, this example is not created in full accordance with standards required by COM, just to understand some of the basic features of COM development.
/ * IUnknown interface * /
Class Iunknown
{
PUBLIC:
Virtual unsigned int Addref (void) = 0;
Virtual Unsigned Int Release (Void) = 0;
Virtual Bool QueryInterface (const char * interfaceename,
void ** ppinterface) = 0;
}
/ * IClassFactory interface * /
Class iClassFactory: Public IUNKNOWN
{
PUBLIC:
Virtual Bool CreateInstance (const char * interfaceename, void ** ppinterface) = 0;
Virtual Bool LockServer (Bool Block) = 0;
}
/ * User definition interface * /
Class IEquipment: Public IUNKNOWN
{
PUBLIC:
Virtual Bool Turnon (VOID) = 0;
Virtual Bool Turnoff (Void) = 0;
}
/ * User interface implementation a * /
Class CTV: Public IEquipment
{
Private:
Unsigned int m_ref;
PUBLIC:
CTV (void): m_ref (0) {};
protected:
Virtual ~ ctv (void) {};
PUBLIC:
/ * Inherited from iUnknown * /
Virtual Unsigned Int AddRef (Void)
{
Return m_ref;
}
Virtual Unsigned Int Release (Void)
{
Unsigned int uirtn = --m_ref;
IF (0 == m_ref)
{
DELETE THIS;
}
Return UIRTN;
}
Virtual Bool QueryInterface (const char * interfaceename,
void ** ppinterface)
{
IF (0 == Strcmp ("iUnknown", interfacename))
{
* ppinterface = Dynamic_cast
((IUNKNOWN *) (* ppinterface)) -> addref ();
}
Else IF (0 == Strcmp ("IEquipment", InterfaceName) {
* ppinterface = Dynamic_cast
(Iequipment *) (* ppinterface)) -> addref ();
}
Else
{
* ppinterface = NULL;
}
Return null! = * ppinterface;
}
/ * Inherited from iEquipment * /
Virtual Bool Turnon (Void)
{
//... Turn on TV
Return True;
}
Virtual Bool Turnoff (Void)
{
//...TURN OFF TV
Return True;
}
}
/ * Class Factory Realization * /
Class CclassFactoryObj: Public iClassFactory
{
PUBLIC:
Virtual Bool CreateInstance (const char * interfaceename, void ** ppinterface)
{
* ppinterface = NULL;
CTV * _PTV = New CTV ();
IF (NULL! = _PTV)
{
_PTV-> addref ();
IF (_PTV-> Queryinterface (InterfaceName, Ppinterface))
{
Return True;
}
Else
{
_PTV-> Release ();
_ptv = NULL;
}
}
Return False;
}
Virtual Bool LockServer (Bool Block)
{
/ * Do not support this, simply return false * /
Return False;
}
/ * Delivered from the IUNKNOWN function, slightly * /
...
}
In order to create a CTV instance using the class factory, we provide a single function:
Bool DllgetClassObject (const char * interfaceename, void ** ppinterface)
{
BOOL BRTN = FALSE;
CCLASSFACTORYOBJ * POBJ = New cclassFactoryObj ();
IF (NULL! = POBJ)
{
POBJ-> addRef ();
BRTN = POBJ-> CreateInstance (InterfaCename, PPinterface);
POBJ-> Release ();
POBJ = NULL;
}
Return BRTN;
}
The client can use this:
......
IEquipment * piequipment = null;
IF (DllgetClassObject ("IEquipment", & Parts))
{
PIEQUIPMENT-> Turnon ();
PIEQUIPMENT-> Turnoff ();
PIEQUIPMENT-> Release ();
PIEQUIPMENT = NULL;
}
......
The above is the basic idea of COM. This will then introduce the specific "traffic rules".
COM rules
GUID
GUID is a 128-bit number that is used to uniquely identify a library, one class, and each interface worldwide. Its concept Some MAC addresses like NIC.
The Tools that come with the VC Guidgen.exe can generate GUID, which is located in the "VC6 installation directory / common / Tools" directory.
In the queryInterface function mentioned earlier, the GUID of the interface should be used instead of the interface name specified directly with the string.
The GUID is often referred to as CLSID and IID relative to classes and interfaces in COM.
2. Return value
HRESULT is a standard COM interface function return value, a 32-bit integer. The meaning of you is as follows:
The highest bit: Severe degree, indicating successful operation or failure.
29 ~ 30: Reserved.
16 ~ 28: Operation Code, indicating what technology corresponds to HRESULT.
0 to 15 bits: information code, accurate results value in a given severity and corresponding technique.
There are two macros to simplify the check of HRESULT related information:
HRESULT HR;
...
Succeeded (HR); // If true, operation is successful
Failed (hr); // If true, the operation failed
3. Class Factory and Object
The client does not need to explicitly load the DLL and call DllgetClassObject to create a class. The mechanism for the COM will automatically complete all. COM provides 3 API functions for the creation of objects, and their prototypes are as follows:
HRESULT COGETCLASSOBJECT (Const CLSID & CLSID,
DWORD DWCLSCONTEXT,
CoserverInfo * PServerInfo,
Const IID & IID,
(void **) PPV);
HRESULT COCREATEINSTANCE (Const CLSID & CLSID,
IUNKNOWN * PunkNownouter,
DWORD DWCLSCONTEXT,
Const IID & IID,
(void **) PPV);
HRESULT COCREATEINSTANCEEX (Const CLSID & CLSID,
IUNKNOWN * PunkNownouter,
DWORD DWCLSCONTEXT,
CoserverInfo * PServerInfo,
DWORD DWCOUNT,
MULTI_QI * RGMULTIQI);
CLSID:
The CLSID of the object to be created.
DWCLSCONTEXT:
Specify the category of the component, which can be fixed as a CLSCTX_INPROC_SERVER in this stage, meaning the process within the process.
PSERVERINFO:
Distributed system use, at this stage designation as NULL.
IID:
The IID of the first interface you want to get after creating a class object.
PPV:
Returns the interface pointer specified by the IID.
Punknownouter:
Used to polymerize, if it is not involved, set to NULL.
CocreateInstanceex can return a plurality of interfaces after being created.
4. Polymerization and inclusion
The aggregation and inclusion is the two reuse models of COM.
Aggregate is a public inheritance mechanism in the C language. After the derived class inherits the parent class, it also has all the functions of the parent class.
Tolerate a member variable mechanism in the C language. For example, a class X that implements certain functions as a member variable of class A, then class A to implement a series of functions, map the customer's call to the corresponding function of the class X-type member variable.
Applying an inclusive model is very simple, just redefining the function workload of the call mapping is relatively large.
The realization of the polymerization model is difficult. The aggregated COM class must implement two sets of IUNKNOWN interfaces, a set ("true") returned to the founder when the object is created; another set ("false" ) Recycled all QueryInterace to the founder. Which interface is decided by the creator.
5. Connection point
The COM model determines that the function of calling the COM component by the customer is very convenient, but if the COM component is required to interact with the client program, it is necessary to introduce the connection point. The connection point is actually an interface implemented by the client, and the client program is handed over to the COM component; the COM component uses the function provided by this interface when you need to actively and the customer program. The ability to accept the COM components of the connection point provided by the client program, called the connectable object.
Connectable objects must implement the IConnectionPointContainer interface, which is defined as follows:
Class iconnectionPointContainer: Public iUnknown
{
PUBLIC:
Virtual HRESULT ENUMCONNECTIONPOINTS (IEnumConnectionPoints **) = 0;
Virtual HRESULT FINDCONNECTIONPOINT (const iid *, iconnectionPoint **) = 0;
}
IEnumConnectionPoints is called an enumerator interface that enumerates all connection point interfaces supported by this connectable object.
The most fundamental principle of COM is rough. Uncomparable parts also include columns - distributed COM (DCOM) principles. Because COM involves facing it is too wide, it is not possible to provide a relatively comprehensive introduction. This article only explains the part of the entry must understand.