contents   index   previous   next



The IDispatch interface and even more terminology

 

[35]

 

One of the standard interfaces that can be exposed by COM objects is IDispatch. IDispatch is the interface that exposes the Automation protocol. Applications that expose objects through automation are called ActiveX or Automation Servers. The objects exposed by Automation servers are usually called ActiveX or Automation Objects. For example, Microsoft Excel is an Automation server that exposes many objects that you can use to create new applications and programming tools. Within Microsoft Excel, objects are organized hierarchically, with a root object named Application at the top of the hierarchy (Figure 6.2)

 

Each ActiveX object has its own set of member functions. An object can expose three types of members:

 

Methods are actions that an object can perform. For example, the Worksheet object in Excel provides a Calculate method that recalculates the values in the worksheet.

 

Properties are functions that access or set information about the state of an object. For example, the Worksheet object's Visible property determines whether the worksheet is visible.

 

Events are actions recognized by an object, such as clicking the mouse or pressing a key. You can write code to respond to such actions. In Automation, an event is a method that is called, rather than implemented, by an object.

 

There are two basic types of ActiveX servers; in-process and out-of-process servers. An in-process server runs in the same process space as the client that uses it. In-process servers usually reside in Dynamic Link Libraries (DLLs), and are located in the same computer where the clients are running. An out-of-process server runs in a different process space than its clients. Out-of-process servers can be located in the same machine where the clients are running or in a different computer. In this last case, the communication between the server and its clients takes place through the network. Out-of-process servers usually reside in executable files (.EXE files). Because the server and its clients run in different processes, the communication between them is mediated by a complicated marshalling protocol that ensures data integrity and security during their interaction.

 

An ActiveX Client is an application or programming tool that manipulates ActiveX objects. These objects can exist in the same application process (when provided by in-process servers) or in another process (objects provided by out-of-process servers). A client does not need to be aware of whether the server is running as an in-process or out-of-process server; the COM/Automation protocol takes care of identifying the server characteristics and location during the installation of the server application. Clients can use existing objects, create new instances of objects, get and set properties, and invoke methods supported by the object. Perhaps the most typical example of an ActiveX client is a Visual Basic application. You can use Visual Basic and similar programming tools to create packaged scripts that access automation objects.

 

Because all Automation objects are COM objects, they also implement the IUnknown interface. In fact, the IDispatch interface derives (inherits) its AddRef, Release and QueryInterface methods from the object’s IUnknown interface. The Automation (IDispatch) interface provides the means for a client application to find out what properties and methods are supported by an object at run-time, and a standard protocol to invoke these properties and methods. Client applications do not need to be aware of the object members when they are compiled. At run-time, the client application queries the ActiveX object for a method or property. If the object supports the property or method, the client can execute the function associated with the member through a proxy method (called Invoke) provided by the IDispatch interface. This process is called late-binding. It is the most flexible method to access ActiveX objects, but it is also slower because each time a property or method is invoked, the Automation server must check if the property or method is supported by the object, and whether the client is invoking the member function with the appropriate number and type of arguments.

 

So far, we know that the IDispatch interface exposes at least four methods: AddRef, Release, QueryInterface (all derived from IUnknown) and Invoke. Here is a complete list of the member functions in IDispatch:

 

 

 

Methods exposed by IDispatch interface Description
AddRef Increases the reference-counter of the interface.
Release Releases the interface.
QueryInterface Queries for another interface exposed by the object
GetTypeInfoCount Tells whether the object can provide type information about the interface.
GetTypeInfo Gets a pointer to the type information (ITypeInfo) of the interface.
GetIDsOfNames Gets the Dispatch ID (DispID) of a member property or method of the interface.
Invoke Sets or retrieves a property, or executes a method, exposed by the interface.

 

 

The heart of the IDispatch interface is the Invoke method, so we’ll only explain this method here [36]. This method is in fact a mini-interpreter for the functionality of the object. Once an application gets a pointer to the IDispatch interface of an object, it can call the Invoke method to execute particular methods on the server, or set or retrieve the server object properties. If you checked the definition of the Invoke method in the OLE type library, you would see that a Fortran-f90VB translation would look much likes this:

 

interface

 

function Invoke(DispID, IID, LocaleID, Flags, Params, &
VarResult, EInfo, ArgErr)

 

integer(HRESULT_KIND)::Invoke
integer(LONG_KIND),intent(in)::DispID
type(GUID)::IID
integer(LONG_KIND),intent(in):: LocaleID
integer(LONG_KIND),intent(in)::Flags
type(DISPPARAMS)::Params
type(VARIANT),intent(out)::VarResult
type(EXCEPINFO),intent(out)::Einfo
integer(LONG_KIND),intent(out)::ArgErr

 

end function Invoke

 

end interface

 

Each member function an object exposes through the IDispatch interface has an ID number. This ID is known as DispID. If an application knows the name of a method, but not its ID, it can call IDispatch::GetIDsOfNames passing the name as an argument. If the method is defined, GetIDsOfNames returns the DispID of the method, otherwise it returns an error value (more on this later). The IID argument of Invoke is not currently used and is reserved for future use, so you should always pass a null IID for this argument. LocaleID contains language information for objects that implement their functionality in different languages. In most cases, using the constants LOCALE_SYSTEM_DEFAULT or LOCALE_USER_DEFAULT will work fine. Argument Flags indicates the kind of method to be invoked, and whether it is a normal method or a put or get function for a property. Table 6.1 shows allowed values for this argument and their meaning.

 

The Params argument is a special structure that contains the parameters that need to be passed to the invoked method or property. If you check the f90VB modules, you can see that this structure is defined as follows:

 

type DISPPARAMS
     sequence
     integer(POINTER_KIND)::rgvarg 
     integer(POINTER_KIND)::rgdispidNamedArgs 
     integer(LONG_KIND)::cArgs 
     integer(LONG_KIND)::cNamedArgs 
end type

 

Field cArgs contains the total number of arguments the client application is passing to the invoked method. If the application is passing named arguments to the invoked method, cNamedArgs contains the number of these arguments. Field rgvarg is a pointer to an array of variant values, each containing one of the arguments passed to the invoked method or property. The arguments are stored in inverse order, so the last argument appears as the first entry of the array. rgdispidNamedArgs is a pointer to an array containing the IDs of named arguments included in rgvarg. Array rgvarg must contain an entry for each argument in the invoked member function. This also includes any optional arguments in the invoked method or property. If a controller does not want to use an optional argument in the invoked member function, it must pass a variant of type VT_ERROR with content DISP_E_PARAMNOTFOUND for this argument. Argument Params is used to handle all the arguments of invoked methods, or the new value of a property put or set invocation. Methods that change the content of an argument must receive a variant with the VT_BYREF flag set.

 

Whereas the Params argument to Invoke handles all the arguments to a method or the new value for a property put, the VarResult argument handles the return value of a method or the return value of a property get. This VarResult exists because Invoke is a function that returns an integer(HRESULT_KIND) so it can indicate whether an invoked member function executed successfully. Only if Invoke returns S_OK does the result in VarResult have any meaning. If an error occurred during the execution of the Invoke method (or the invoked member function), then arguments Einfo and ArgErr may contain additional information describing the error. If the error is due to an invalid argument, ArgErr contains the index of the offending argument.

 

Einfo is a structured type used to describe IDispatch exceptions. The Fortran translation of this structure is as follows:

 

type EXCEPINFO
     sequence
     integer(WORD_KIND)::wCode           
     integer(WORD_KIND)::wReserved 
     integer(BSTRHNDL_KIND)::bstrSource 
     integer(BSTRHNDL_KIND)::bstrDescription 
     integer(BSTRHNDL_KIND)::bstrHelpFile 
     integer(DWORD_KIND)::dwHelpContext 
     integer(POINTER_KIND)::pvReserved 
     integer(POINTER_KIND)::pfnDeferredFillIn 
     integer(LONG_KIND)::scode
end type EXCEPINFO

 

Table 6.2 describes the fields in this structure.