DCOM Explained
by Rosemary Rock-Evans Digital Press ISBN: 1555582168 Pub Date: 09/01/98 |
Previous | Table of Contents | Next |
Microsoft often uses the term binary call standard. This term refers to the standard that defines the layout of the call stack for all method invocationsa call stack called a Vtable. Vtables hold the pointers to where methods can be found.
Vtables are used for the compiled static approach to interface generation.
As we saw, each class can have more than one interface. Every client wanting to use an interface keeps a Vtable in memory for every interface it uses. In practice, the client first keeps a pointer to the interface. This pointer then points to another pointerknown as the pVtbl pointer, which itself points to the Vtablethe Virtual Function Table.
Figure 5.5 The Vtable approach
The Vtable then contains an array of pointers to the objects implementations of the member functions. By using this approach, the client can use the name of the interface (the first pointer) and does not have to use any other pointers.
Clearly, if an object has more than one interface, other Vtables are created for each of the interfaces. If the client invokes methods on many objects, it will have sets of Vtables in memory for every one of the objects and methods it invokes.
So, where do the final pointers to the function implementations point to?
Clearly, the functions could be part of in-process objects. Where the object is an in-process object, the Vtable function pointers in the table are actual pointers to the implementationso a function call from the client to an interface function directly transfers execution control to the member function.
But, if the process is out of process whether local or remote, the pointers in the table cannot be in memory because they cannot be shared between processes. In this case, the pointer points to the Proxy Object.
Who creates these tables? Perhaps of most importance is that the C form of the interface generates the same binary structure as the C++ interface does. But C++ is more convenient for an object implementation because the compiler automatically generates the Vtable and the object structure pointing to it in the course of instantiating the object.
A C object implementor must define an object structure with the pVtbl first; explicitly allocate both object structure and interface Vtbl structure; fill in the fields of the Vtbl structures, and point the Vtbl field in the object structure to the Vtbl structure. There is thus much more explicit coding needed if C is used on the client. In C++, the compiler handles pointers to the Vtbl pointer and also sets up pointers on the stack. If C is used, extra code has to be added to do this.
We saw that the Type Library is a language-independent replacement for the C++ header files with a content the same as the C++ header file. The Type Library contains type information about interfaces (methods classes and so on) and is stored in compiled binary form so that details of the interface can be accessed by program at runtime.
By using the Type Library, interfaces can be accessed dynamically and type checking done at runtime. This feature is particularly useful if you are using an interpreted language such as Visual Basic, Java, or similar language where the VTable cannot be accessed in an interpreted manner so cannot be used as the means of finding the functions.
In fact, the general approach recommended by Microsoft is to use VTables if you are using any form of compiled language and the Type Library for interpreted code. Visual Basic hides much of the underlying code of this invocation anyway if you use the normal commandsin fact, you never really see what is happening underneath.
The Type Library first has to be specifically loaded by the client. Once loaded, the developer gets the information he or she needs about the interface from the Type Library and then uses the IDispatch interface to get information about the location of the functions in it. A Visual Basic programmer doesnt have to worry about IDispatch; this is hidden from him or her and happens under the covers.
When a client uses IDispatch in order to execute a function, it first gets the ID of the function using a method on the IDispatch interface called GetIDsofNames. This ID isnt a GUID; it is a convenient string with which to identify the function.
After the ID has been obtained, the Invoke method on the IDispatch interface is then invoked! The arguments (parameters) used in the invocation include the function ID just obtained, the actual parameters of the function being invoked, the type of function being called (normal, function of put property, function of put property by reference, etc.), a pointer to the field that should hold the results of the function, and a pointer to the structure that should hold exception information. The function arguments/parameters can be obtained from the Type Library information.
Figure 5.6 The GetIDs of Names method of IDispatch Interface
The effect of the Invoke method is to cause DCOM to use the IDs to either find pointers to the functions themselves (Disp interface) or find a separate Vtable that points to the functions.
Figure 5.7 IDispatch Interface
Where a component can offer two ways of getting to its functionsdirectly and indirectly via the Invoke functionthe interface is known as a Dual Interface.
Components that implement the IDispatch interface are known as Automation Servers. COM clients that communicate with Automation Servers via the IDispatch interface are known as Automation Controllers. In effect, Automation Controllers use IDispatch to indirectly call functions in an Automation Server.
Figure 5.8 Dual Interface
COM enables a developer to define interfaces to components using a language called the Microsoft Interface Definition Language. The MIDL description is used by the MIDL compiler to generate C, C++, Visual Basic, and Java files, which can be used to create entries in a Type Library and used to form the stubs and proxies in clients and servers.
Where the stubs and proxies are compiled statically with client and server programs, the functions (whether these are the functions themselves or their proxies) are found using VTables. Where information about interfaces is found dynamically at runtime, the programmer uses the Type Libraries and the IDispatch interface to find the functions or proxies.
Dynamic invocation is useful for interpreted languages, and Visual Basic has been specifically set up to hide many of the complexities of dynamic invocation. Static invocation is useful with languages such as C or C++ that you want to compile into an executable for use at runtime.
Previous | Table of Contents | Next |