IDL Files

An IDL source file, which looks somewhat like a Java class definition, describes the functions and constants that are exported by the interfaces supported by a COM object. You probably won’t write many IDL files when you are working with Visual J++; the ActiveX Wizard for Java handles that task for you by creating an IDL file that defines a single interface to expose the public methods for all your COM-compliant classes. But you might want to remove some public functions from the generated interface definition, or you might want to distribute methods among two or more interfaces. A basic understanding of IDL syntax is essential if you’re going to do such fine-tuning. What follows is an explanation of the type of IDL file that you’ll be using with Visual J++; if you work with COM components defined in other languages, you’ll need to study the full IDL specification, which you can find on the Microsoft Developer Network.

For the purposes of Java, an IDL file has the following general format.

// Declare the library
[
    uuid(nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn),
    helpstring("tname Type Library"),
    version(n.n)
]
library name
{
    // Import standard COM/OLE type library
    importlib("stdole32.tlb");

    // Declare an IDispatch interface
    [
        uuid(nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn),
        helpstring("iname Interface")
    ]
    dispinterface iname
    {
        properties:
            property-def
        methods:
            method-def
    }

    // Declare a dual (IDispatch/vtable) interface
    [
        object,
        uuid(nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn),
        dual,
        pointer_default(unique),
        helpstring("diname Interface")
    ]
    interface diname : IDispatch
    {
        di-method-def
    }

    // Declare a COM class
    [
        uuid(nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn),
        helpstring("cname Object")
    ]
    coclass cname
    {
        [ default ]
        dispinterface iname;
        interface diname;
    };

};

Each uuid entry must be unique so that each component of the type library can be correctly identified. The helpstring text provides documentation through certain COM facilities and should describe the definition entry immediately following it.

For the sake of example, let’s assume we’re converting a Java class named Ticker to a class that supports COM. The type library name, tname, is often the name of the Java class with the suffix “Lib” or “TLB” added; in this case, tname will be replaced by TickerLib.

The coclass statement defines a COM component and lists the interfaces that it supports. In the case of the Ticker class, our coclass name will be CTicker, in keeping with COM naming standards. The coclass statement is listed last in the library definition because the interfaces must be defined before they can be assigned to a COM class.

Interfaces in IDL

The dispinterface statement defines an interface derived from IDispatch; the interface’s iname would be ITicker. (The “I” prefix designates an interface.) Since Java classes do not, in general, expose data members, there will be no items listed under the properties keyword. Under methods, each of the public Java methods will be given an entry. For example, if the Java function is declared like this,

public String formatComma(int n);

the IDL file will contain an entry like this,

[ helpstring("formatComma Method") ]
BSTR formatComma([in] long p1);

The helpstring declaration defines text that can be automatically displayed in a graphic development tool, describing a component’s exposed methods and properties.

Some types, such as String, will be translated from Java types into IDL-compatible types. Table 6-1 shows how Java types and IDL types correspond. The correspondences are relatively straightforward, and all of these types should be familiar to you. The possible exception might be the VARIANT class, a sort of “stores anything” object that is often found in Visual Basic; Microsoft Visual Basic, Scripting Edition; and Visual Basic for Applications programs.

Table 6-1

Java-to-IDL Type Correspondences

Classification Java Type IDL Type
Simple types boolean boolean
char char
double double
float float
int int
long int64
int long
single-element array of type pointer to type
short short
byte unsigned char
void void
Compound types class java.lang.String BTSR
long (divide by 10,000 to get CURRENCY
original fixed-point number)
double DATE
int (see text) HRESULT
class com.ms.com.SafeArray SAFEARRAY
int (same as HRESULT) SCODE
class com.ms.com.Variant VARIANT
Interfaces interface com.ms.com.IUnknown IUnknown
class java.lang.Object IDispatch

IDL specifies the nature of each method parameter by including qualifiers inside square brackets. The [in] designation declares an input value that is read by the method; [out] declares a value that can be changed by the method and that is assumed to be a pointer. Again, the IDispatch::Invoke method will perform any necessary reference manipulations.

Unlike C and C++, Java does not support pointers. When you are writing code that calls a COM interface that requires a type * pointer parameter, you must use a one-element array of type instead. Since Java passes array parameters by reference, this piece of programming legerdemain simulates a pointer. For example, if a COM method defines its parameters as follows,

void SomeMethod([in] long p1, [out] long * p2);

you call it in Java using the following syntax,

int x = new int[1];
SomeMethod(23, x);

If you don’t declare a dispinterface, the interface statement will define ITicker as a dual interface. The dual interface requires more code, and the definition of methods for it is different. Whereas an IDispatch method is declared much like a Java method, with a return type, a method in a dual interface must declare its return value as a value of type HRESULT. The actual return value (if not void) is added to the parameter list with the qualifier [out, retval].

[ helpstring("formatComma Method") ]
HRESULT formatComma([in] long p1, [out, retval] BSTR * rtn);

An HRESULT is an integer value that can indicate whether or not an error has occurred during a method call. The only success value returned by HRESULT is the COM constant S_OK; all other possible HRESULTs are error indications. Since COM does not support the “thrown” exception model, a C++ program needs to check the HRESULT of a called COM function and throw an exception if the value is not S_OK. The Java virtual machine, however, once again provides a simpler model by throwing a ComFailException exception whenever a COM call returns an error value. The JVM stores the value of the HRESULT in the ComFailException object. And since ComFailException is extended from RuntimeException, you don’t need to declare it in a throws statement for functions that call COM methods.

An HRESULT is also returned for a dispinterface method, even though the function definition will not be written in IDL to indicate this.

Examples

I’ll borrow a bit of code from the next chapter to show you an IDL file generated for a class by the ActiveX Wizard for Java. This class, FormatNumbers, supports only the universal IDispatch interface.

[
    uuid(3a82ef02-9276-11d0-be9b-0020afd208b9),
    helpstring("FormatNumbersLib Type Library"),
    version(1.0)
]
library FormatNumbersLib
{
    importlib("stdole32.tlb");

    [
        uuid(3a82ef01-9276-11d0-be9b-0020afd208b9),
        helpstring("IFormatNumbers Interface")
    ]
    dispinterface IFormatNumbers
    {
        properties:
        methods:
        [ helpstring("setSeparatorSymbol Method"), id(1) ]
        void setSeparatorSymbol([in] char p1);

        [ helpstring("getSeparatorSymbol Method"), id(2) ]
        char getSeparatorSymbol();

© 1997 by Scott Ladd. All rights reserved.