Smart Clients and the vTable Interface

 < Free Open Study > 



Over the course of nine chapters, you have come to understand that the core element of COM is the interface. Each interface we have been building up to this point has been a vTable interface, which is expressed by the ATL Object Wizard as a "custom" interface. When creating COM objects that support custom vTable interfaces, the assumption is made that the clients using our coclasses have some manner in which to "include" our coclass-specific information. For example, a C++ client will typically make use of the preprocessor to include the following MIDL-generated files:

  • yourServer_i.c: Contains the GUIDs defined in the IDL file. Allows clients to program against the associated constants (e.g., IID_IDraw, CLSID_CoDot, and so forth) to create your coclass and ask for various custom interfaces.

  • yourServer.h: Contains the C and C++ interface definitions, allowing clients to declare interface variables for storage (e.g., IDraw*, IEngine*, IAmDrowning- InMacros*).

Using these files, C and C++ clients can compile the necessary externals into their own binary image and achieve what is known as early (vTable) binding. Binding is a term used to describe at what point the COM client "understands" the functionality of the COM objects it is using. As these MIDL-generated files are compiled directly into the C++ client binary image, we have "bound early" to the object.

An important corollary to early binding is that any syntactical errors in your client-side code can be resolved at compile time. If you have made a reference to some GUID not defined in the MIDL-generated files you are referencing, the compiler will let you know loud and clear that something is wrong. More likely than not, this is due to a simple typo (e.g., IDD_FooBar rather than IID_FooBar) in the client-side code.

The Visual Basic language also allows clients to work with early binding to access custom vTable interfaces using the MIDL-generated type library (the *.tlb file). As you have seen, by setting a reference to the server's type library, a VB client is able to also "understand" GUID and interface variables at compile time. You have also seen that the Visual Basic language is sophisticated enough to allow the VB developer to query for additional vTable interfaces beyond the [default] interface using the "Set =" syntax (as we first saw in Chapter 4). The type library is used for the same purpose in the Java/COM language mapping (COM wrappers) as well as the intrinsic Visual C++ COM support (remember the #import statement?).

Thus, Java, VB, and C++ clients can all "bind early" by making use of various MIDL-generated files. If our world was only composed of "vTable-able" languages, we would be able to end the discussion of binding right here. However, as you may have noticed, we have yet to use any of our COM objects from a web-enabled client. Here is a question: Could we use any of our CoCar projects from within an HTML page and VBScript? To answer this question, may I introduce "vTable-challenged" clients (lovingly referred to as dumb clients).

Dumb Clients: Life as a vTable-Challenged Language

Some COM-aware languages, such as VBScript, are not so lucky to have an upfront understanding of the objects they are using. Meaning, some COM-aware language mappings are not enlightened enough to allow direct access to custom vTable interfaces. Instead, the vTable-challenged client makes a shot in the dark when activating an object, hoping that "some object called X" has "some function called Y" which takes "some number of parameters of some type." This sort of object instancing is termed late binding, as it is at run time (not compile time) that the client understands the object it is attempting to use. Now, every language that is able to exercise early binding is also able to exercise late binding. As an example of late binding, here is a Visual Basic client calling into the Microsoft Excel EXE server, accessing the Application object and calling the CheckSpelling() method without setting a reference to a type library:

' This VB client has no type library reference selected. ' Rule: Object variable + CreateObject() = Late Binding (ergo IDispatch) ' Private Sub btnLateBound_Click()      Dim o As Object                              ' Holds IDispatch*      ' I think there is an object called Application in a server called Excel.      Set o = CreateObject("Excel.Application")    ' Query for IDispatch interface.      Dim b As Boolean      ' I think the method is called CheckSpelling() and I think it takes a String.      b = o.CheckSpelling("Is COM Love?")      If b Then           MsgBox "It's in there!"      Else           MsgBox "Not a word..."      End If End Sub

Although you are aware VB can access your custom vTable interfaces, historically speaking VB was unable to obtain custom interfaces. In order to allow VB to get into the COM game, a very special standard interface was introduced named IDispatch. When a COM object exposes properties and methods via IDispatch, the dumb client is able to access the object's exposed functionality even if it is unable to work with custom interfaces. The intrinsic VB Object variable is used to hold the IDispatch interface which is retrieved with a call to the CreateObject() function. Note that we send in the ProgID of the coclass we are interested in, and allow the COM runtime to look up the correct CLSID from the system registry. Using the standard IDispatch interface, a client may exercise late binding. Contrast this idea to traditional vTable interfaces, in which a client obtains an initial interface (often IUnknown) and then widens the connection to that object using numerous calls to QueryInterface().

Again, late binding between a client and COM object happens at run time. It is at this point that the client is able to figure out if the object indeed exists, if the methods and properties exposed by the object's IDispatch implementation exist, and if the set of parameters (if any) sent into the method or property are of the correct type. As all this information is resolved as the client is executing, you might imagine that late binding is slower than early binding. You're right. Typically, late binding will be slower. As we will see in this chapter, when a COM client accesses an object via IDispatch, two invocations must be made to trigger the method request (there are ways to streamline this process however).

So Then, Who Needs IDispatch?

So, if early binding is faster (fewer round trips) and more type safe, and if Visual Basic, C++, and Java are able to work with early binding and custom vTable interfaces, why do we need to understand IDispatch in this day and age? In the current state of COM, any web-based client (such as Microsoft Internet Explorer) is unable to access a COM object's functionality in any other way but through IDispatch. This means if you are creating a web-based solution using VBScript or JScript, you cannot work with any objects created in this book thus far, as they do not support the IDispatch interface. Scripting languages are not compiled into binary executables, cannot access type information, and have no preprocessor! Therefore they have no way to access any of the MIDL-generated files. Rather, VBScript and JScript code is embedded into the HTML file and interpreted on the fly at run time. Therefore your COM objects must support the IDispatch interface if you wish scripting clients to make use of them. Here is some VBScript code embedded within an HTML file that accesses the Excel spell checker using late binding:

' This block of scripting code dynamically activates the Application object of Excel. ' <SCRIPT language = VBScript>      dim o      set o = CreateObject("Excel.Application")      b = o.CheckSpelling("Is IDispatch Love?")      If b Then           MsgBox "It is in there!"      Else           MsgBox "Not a word..."      End If </SCRIPT>

The VBScript code above makes no use whatsoever of any custom interface. Using the CreateObject() method, the scripting engine loads up Excel and extracts the IDispatch interface from the Application object.

Sadly, there may be times when you as a C++ or VB developer are forced to access a COM object's functionality using IDispatch. Imagine you have a legacy COM server that was pre-engineered to only expose its functionality via IDispatch. This is not as uncommon as you may think. The typical ActiveX control exposes all of its custom functionality using IDispatch. Older versions of Microsoft Office expose their object model only using IDispatch. Thus, even though your client's language may support both early and late binding to a COM object, you might be forced to work with the IDispatch interface as the server does not supply custom vTable interfaces. As you will soon see, working with IDispatch can be a non-trivial endeavor in raw C++.

On the upside, most C++ frameworks provide some convenient wrapper classes which make working with the IDispatch interface much more palatable. MFC provides the COleDispatchDriver class, which will lovingly encapsulate you from low-level IDispatch calls if you have access to the server's type information. Nevertheless we will take the time to see how we can create servers that implement IDispatch, and how various clients may make used of this standard interface "in the raw."



 < Free Open Study > 



Developer's Workshop to COM and ATL 3.0
Developers Workshop to COM and ATL 3.0
ISBN: 1556227043
EAN: 2147483647
Year: 2000
Pages: 171

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net