1. Interface Query
About iunknown
All com interfaces inherit iunknown. The first three functions of each interface are QueryInterface, addref, and release. This allows all interfaces to be used as iunknown. Therefore, any component interface can be used by the customer to obtain other interfaces supported by the component.
Iunknown pointer acquisition
You can use the createinstance function to return an iunknown pointer without using the new operator.
QueryInterface
The QueryInterface function is used to query whether a component supports a specific interface. If yes, a pointer to this interface is returned. Otherwise, an error is returned.Code.
Hresult_ StdcallQueryInterface (ConstIID & riid,Void** Ppobject );
The first parameter indicates the interface required by the customer. It is an "interface identifier" structure.
The second parameter is the address where QueryInterface stores the wrong request interface pointer.
Returns an hresult value, which is a 32-bit specific structure value.
Use of QueryInterface
Assume that you have a pointer PI pointing to iuknown, you can:
VoidFoo (iunknown * PI)
{
// Define a pointer for the interface
IX * pix = NULL;
// Ask for interface3 IX
Hresulthr = pi-> QueryInterface (iid_ix ,(Void**) & Pix );
// Check Return Value
If(Succeeded (HR ))
PIX-> FX ();
}
Queries whether PI supports the interface identified by iid_ix. First, it is a programming habit to initialize the PIX to null as a number.
QueryInterface implementation
QueryInterface returns the corresponding interface based on a given IID. Returns s_ OK and corresponding pointers are supported. e_nointnterface is not returned and the corresponding pointer return value is null. Take the CA component as an example:
InterfaceIX: iunknown {};
InterfaceIy: iunknown {};
ClassCA:PublicIX,PublicIy {};
Note: iunknown is not virtual inheritance. IX and Iy do not inherit iunknown in virtual inheritance mode, which may cause vtbl incompatible with COM.
Hresult_ StdcallCA: QueryInterface (refiid riid,Void** Ppvobject)
{
If(Riid = iid_iunknown)
* Ppvobject =Static_cast<IX *> (This);
Else If(Riid = iid_ix)
* Ppvobject =Static_cast<IX *> (This);
Else If(Riid = iid_iy)
* Ppvobject =Static_cast<Iy *> (This);
Else
{
* Ppvobject = NULL;
ReturnE_nointerface;
}
Static_cast<Iunknown *> (* ppvobject)-> addref ();
ReturnS_ OK;
}
About type conversion
The address obtained by the IX pointer is different from the address obtained by converting it into an Iy pointer:
Static_cast<IX *> (This)! =Static_cast<Iy *> (This)
Static_cast<Void *> (This)! =Static_cast<Iy *> (This)
Generally, when this pointer is assigned to a void pointer, it should be converted to an appropriate type, as shown below:
* Ppvobject =Static_cast<Iunknown *> (This);
It is not clear when this pointer is converted to iunknown *, because both IX and Iy have iunknown inheritance, so it should be * ppvobject =Static_cast<Iunknown *> (Static_cast<IX *> (This));
The multi-inheritance memory structure in C ++ is as follows: (using Ca as an example)
2. QueryInterface Implementation Rules
Rules:
- The iunknown pointer is always returned by QueryInterface.
- If you have obtained an interface, you can always obtain it.
- The customer can obtain the existing interfaces again.
- The customer can return to the starting interface.
- If you can obtain a specific interface from an interface, you can obtain this interface from any interface.
Same iunknown
A component instance has only one iunknown interface. When querying an instance's iunknown interface, the same pointer is obtained through any interface.
Bool samecomponents (IX * pix, Iy * piy)
{
Iunknown * PI1 = NULL;
Iunknown * Pi2 = NULL;
// Get iunknown from IX
PIX-> QueryInterface (iid_iunknown ,(Void**) & PI1 );
// Get iunknown from Iy
Piy-> QueryInterface (iid_iunknown ,(Void**) & Pi2 );
// Are same ??
Return(PI1 = Pi2 );
}
The customer can obtain the previously obtained interfaces.
If the interfaces supported by the component change from time to time, it will be extremely difficult for the customer to write code, and it will not be possible to determine the functions of a component through programming.
You can obtain an existing interface again.
If you have an iX interface, you can obtain the IX interface pointer through IX, and it will be successful.
The customer can return from any interface to the starting Interface
If you have an iX interface pointer and use it to obtain the Iy interface for one day, you can use Iy to query an iX interface.
If you can obtain a specific interface from an interface, you can obtain this interface from any interface.
For example, you can obtain Iy from interface IX and iz through the Iy interface, so you can also obtain the IZ interface from Ix.
3. QueryInterface defines Components
A component is actually defined by QueryInterface. The interface set supported by the component is the interfaces for which QueryInterface can return interface pointers. The only method that the customer understands the interfaces supported by components is query.