ATL (Active
Template Library is a set of COM (Component) developed by Microsoft.
Object Model, Component Object Model)
Supported libraries. Generally, it is of little significance to discuss the class library from the supported objects. I will write a simple article to introduce it.
Com
It is also a stepping stone, just hope you don't hit me. (Since everyone on this forum is right
C ++ is very familiar, so I will use C ++ and COM
Many comparisons are made, that is, the readers I expect are at least familiar with C ++. Besides, although
Differences between objects and interfaces in C ++
But I may mix the two without causing confusion. In addition
Com versions are not differentiated. That is to say, I use com to name them.
Com, DCOM (Distributed COM), and COM + (supported from Windows 2000
Com ).)
1. binary object standards
A. c ++ object Layout
As we all know, in C ++
Inside, a class can have member data and member functions, if I have a class and a function:
Class myclass
{
Int
Number;
String
Name;
Public:
Myclass (INT,
Name );
String
Getname () const;
//...
};
Void print (const myclass & OBJ)
{
Cout <obj. getname () <Endl;
}
Experienced programmers know that if this class and function are
If it is compiled, do not try to use it in Borland C ++ builder. Not to mention
The LIB file format is different. Even if it is the same, you can ensure that the strings under the two Compilers
Same definition? Can you ensure that the alignment mode during VC compilation is the same as your current alignment mode? You can guarantee
Heap and BCB used in VC
? Any subtle difference may cause problems, and it is Crash. Therefore, C ++
Object standards are not binary, but source code-level. Even different C ++
Compilers do not follow a standard, let alone interaction with other languages (VB, Pascal.
B. Only vtable classes
In C ++
Class, there is a function called virtual function. The call of a virtual function is "dynamically bound", that is, it is determined during running. For example, this Code:
Class myinterface
{
Virtual int
GETID () const = 0;
};
Myinterface * P = getsomeobject ();
Cout <p-> GETID () <Endl;
In this Code, p-> GETID ()
May be similar to the following pseudo code:
Function_pointer * vtbl = (function_pointer *) P;
P-> vtbl [0];
That is to say, when we call a function, we use an integer (subscript of the virtual function table) to uniquely determine this function. Besides, because we have no data members, this class may have only one pointer. The offset of this pointer does not need to be calculated.
0; or, if the vtbl
The layout is the same, and the call specifications for calling a function are the same, so we can share this object pointer between different compilers. Unified
Vtbl
The layout and calling method of is much simpler than unifying the layout of different compiler classes, the implementation of the standard library, and various compilation parameters.
C. com
Com, all called component object model, is a MS
A binary object standard. It is the same as we mentioned in B.
Vtbl layout. Any language that can call a function through an indirect pointer can be implemented or used.
COM Object. These languages include C/C ++, VB, Pascal, Java,..., and even DHTML. In
Com, class users see one "interface" after another, that is, there is only one vtbl
Class. The call method of each function is _ stdcall.
2. iunknown-life cycle, discovering new content and versions
A. Object Lifecycle
In OO systems, object ownership and life cycle are an eternal topic: this is because, in complex
Oo
In the system, the relationship between objects is very complex. We do not want to see that an object does not exist when it is referenced, you do not want a useless object to continue occupying system resources in the memory. C ++
Proposed
Auto_ptr, shared_ptr,..., all of which are used to facilitate object lifecycle management. In
Garbage Collection
In the system, one of the common management methods is reference count. When you need to use an object, add one to its reference count. When it is used up, subtract one from its reference count. Objects can maintain an internal
The counter can also ignore this information (for static/stack objects). That is to say, we use an object reference count to make management of different object lifecycles have the same interface.
The iunknown interface has two methods:
Ulong addref ();
Ulong release ();
The former can add one to the reference count of the interface, and the latter can reduce the reference count of the interface by one (please note that it is the reference count of the interface! This is different from the reference count of an object)
At the same time, using reference counting can also avoid a problem, that is, the creation form is different. For example
The dll contains a function: string * getname ();. You are in the EXE
Call this function to obtain a pointer. After using this pointer, you may
Delete it, because in the DLL, this pointer is passed through the new
Created. However, this will probably crash because your DLL and your exe
Different heaps may be used. In this way, the delete of exe
Looking for this pointer in your own heap often fails.
B. Discover new content
C ++
If we have a base class pointer, we can obtain the pointer of the derived class through forced type conversion to obtain more functions:
Class derived: public Base
{
Public:
Virtual void
Anothercall ();
};
Base * B = getbase ();
Derived * D = (derived *) B;
However, this is generally considered a very dangerous operation, because if you cannot confirm this B
It does point to a D, so the subsequent use of D may bring about a program crash. C ++
Provides a mechanism to add type information to the class and use dynamic_cast
To obtain valid pointers. For various reasons (early compilers for dynamic_cast
Poor support, or the addition of type information is often global with high overhead...) some class libraries, such
You have implemented a similar mechanism. The implementation of such a mechanism is often based on maintaining a table within the class to know what "oneself" is and what classes are related to "oneself ,...; at the same time,
Provides an external interface for querying this information. To do this, you must solve two problems: How can I obtain this public interface and how can I identify a class. In the standard
In C ++, we use the typeid operator to obtain a const type_info &. In
In MFC, because all classes that support dynamic type information are
And its subclass inheritance, so we are in the cobject
. In this way, the first problem is solved for both of them. In standard C ++
Indicates that the dynamic information of a class is
Type_info, you can compare it, judge it, or get a name without definite meaning, but you cannot use it to do more things. In
MFC
Using a string to identify a class. You can use a string to dynamically obtain the type information of the class it represents. Because the use of simple strings is very prone to conflicts
It uses a 128-bit random integer GUID (Global unique identifier)
), Such random integers are considered unlikely to conflict. Iunknown
Another method in is:
Hresult QueryInterface (refiid IID, void ** Interface );
This refiid
It is the unique identifier of an interface, and we also become the interface ID. You call an interface pointer
QueryInterface. If it supports this interface, a pointer is returned, or an error is returned.
D. Some conventions
-Any COM interface must be derived from the iuknown interface.
-QueryInterface
The result must support self-inverse, pass-through, reversible, and persistent. That is to say:
For
Interface must be successful
If you query interface B for interface a of type A and return
B, then you can ask B about a again.
If you query interface B for interface a of type A and return
From B to C, you must be able
A asks the pointer to interface C. Please note that the pointer to this C is not necessarily the same as the previous C
The pointer is the same. (That is, this Convention only guarantees that the query is successful, but does not guarantee that the returned pointer is the same)
If you
If api a has succeeded in api B, it will be successful in every future query.
-
If you want to pass an interface to the function, you should ensure that this interface is valid before the function returns. If a function returns an interface pointer
Similarly, if you get an interface pointer from a function, you do not need
Addref is used up, but it should be release after use.
-In particular, according to the previous one, you call QueryInterface for an interface.
Later, this interface is previously returned by addref.
-
To query another interface multiple times with the same interface pointer, the pointer returned each time is not necessarily the same, but if the interface you query
If the ID is iid_iunknown, the pointer returned each time is the same. This statement is equivalent to pointing
The iunknown pointer is a com
The identifier of the object. That is to say, the only common method to compare whether two interfaces belong to the same object is to compare them.
The iunknown interface. In addition, you must note that each COM interface is
Iunknown is derived, but you cannot simply assign an interface pointer to
Iunknown pointer to obtain a class ID, although this is legal in C ++.
-The reference count is based on the interface, so this Code may be faulty. iinterface1 * P1 =
Getobj ();
Iinterface2 * P2;
P1-> QueryInterface (iid_interface2, (lpvoid *) & p2
); // The assumption is successful.
P1-> release ();
P1-> func (); // at this time, P1 may be invalid !! Although this object is valid
P2-> release ();
3. IDL
The Interface Definition Language (IDL)
). As we said earlier, com
All functions are presented through interfaces. As a binary standard, we need a common method to describe interfaces. C ++
Although powerful, it is not suitable for doing this. First, it is too complicated. Second, many of its data types are not necessarily supported by other languages. We need a neutral language to define the data exchange of the entire interface (we don't need it to define the interface function, because it depends on the specific implementation .) IDL
This is the language. You can use IDL to describe a COM object or a COM object.
Interface Properties: What parameters does this function accept, and the flow of each parameter ,.... IDL is better than C ++
Another advantage is that it is relatively simple and can be processed by tools. The binary information generated can be used to fully describe the external features of your interface.
In fact, in other orb systems
As the original definition language of the interface. For example, in CORBA, you first use IDL
Describes the interface, and then converts some programs into a C ++ definition.
Define the function of continuing to implement the interface, which is called IDL ing from IDL to C ++ ). MS
The midl compiler can also implement the same function, but the concept is different. In COM
You use C ++ directly without IDL
An interface is a legal action and a common action at the beginning.
You write a C ++
Ing is considered a clever action (of course, people familiar with it can do this ).