Using Java and COM Together Previous
Previous
Introduction
Introduction
Next
Next

Using a COM Object from Java

Using the JavaTLB Command-Line Tool , Using a COM Object in Your Java Code , What the JavaTLB Tool Generates , Trusted vs Untrusted Applets , Type Mappings Between Java and COM , COM Programming in Java and C++ Compared , Handling COM Errors in Java

With compiler support for Java/COM integration, you can refer to COM objects directly from your Java source code. This makes any COM service, including those offered by programmable controls or Automation objects, available to any Java program.


Using the JavaTLB Command-Line Tool

In order to use a COM class from Java, you must first import it; this means creating a Java class that represents the COM class in the context of Java.

The JavaTLB tool generates .CLASS files for the classes and interfaces described by a type library. These .CLASS files allow COM services to be used by Java programs.

Type libraries are a mechanism defined by COM to store type information; each type library contains complete type information about one or more COM entities, including classes, interfaces, dispinterfaces, and others. For more information about type libraries, see the Win32 SDK. To find out how to use the interfaces available from a particular programmable control or Automation server, consult the documentation provided by the vendor.

The typical usage is as follows:

javatlb filename

where filename is the name of the type library (.TLB, .OLB, .OCX, .DLL or .EXE).

For example:

javatlb widgets.tlb

This command first creates a \widgets subdirectory underneath the trusted library directory specified by the registry key HKEY_LOCAL_MACHINE\Software\Microsoft\Java VM\TrustedLibsDirectory. If the trusted library directory is \windows\java\trustlib, the above command creates the directory \windows\java\trustlib\widgets, and fills it with .CLASS files, one for each class, structure, enumeration, and interface described by the widgets.TLB type library.

If the type library contains an importlib statement, JavaTLB creates a separate Java package in a separate directory for the imported type library.

Note The packages and directories created by JavaTLB always have all-lowercase names.

You can also use a response file to run JavaTLB on multiple type libraries at once. For example:

javatlb @list

The filename after the @ must specify a text file containing the name of the type library files.

For more information about the output of JavaTLB, see What the JavaTLB Tool Generates.

Options

JavaTLB also supports certain command-line options:

/U classname

This option causes JavaTLB to display the signatures for all the public methods in the .CLASS file. For example:

javatlb /U IDooHickey.class

This command would produce output similar to the following:

public interface widgets/IDooHickey extends java.lang.Object
{
	public native short getThingie();
	public native void putThingie(short);
	public native void doWhatever();
}

This describes the methods you can call when using the IDooHickey interface. There are several things worth noting about the output:

For information on how COM methods and parameters are translated into Java, see Type Mappings Between Java and COM.

/U:T

This option generates .CLASS files and then writes the signature information to a text file. For example, running the command:

javatlb /U:T widgets.tlb

is the equivalent of first running the command "javatlb widgets.tlb" and then running the command "javatlb /U *.class > summary.txt" in the /widgets subdirectory.

/p package

This option lets you specify where JavaTLB will place the .CLASS files it generates. For example:

javatlb /p gremlinsoft widgets.tlb

This places the .CLASS files in the directory \windows\java\trustlib\gremlinsoft\widgets. This option allows you to define, for example, a company-specific directory tree that contains the .CLASS files for all the COM objects produced by your company.

The package parameter can have multiple levels; for example, the command "javatlb /p gremlinsoft.toolworks widgets.tlb" would place the .CLASS files in the directory \windows\java\trustlib\gremlinsoft\toolworks\widgets. To use these classes in your Java program, you would need to specify an import statement of the form "import gremlinsoft.toolworks.widgets.*;" in your source code.


Using a COM Object in Your Java Code

As an example, suppose comserver.DLL, which defines a CComBeeper class and an IComBeeper interface, is registered as having type library information. Running the JavaTLB tool on comserver.DLL would create a package named "comserver" containing the Java class CComBeeper and the Java interface IComBeeper. If you use the /U option, it would also create a SUMMARY.TXT file describing what methods that Java class and interface provide.

Once you've run JavaTLB on comserver.DLL, you can use the import statement in your Java source code to easily refer to classes in the comserver package. For example:

import comserver.*;   // import comserver package 

This is identical to Java's syntax for importing an entire package.

You could also import individual classes within a type library explicitly:

import comserver.IComBeeper;  
import comserver.CComBeeper;  

Again, this is identical to Java's syntax for importing a single class.

The Java classes that wrap COM classes can be used like other Java classes. For example:

IComBeeper testBeep = (IComBeeper)new CComBeeper();
int myTone = testBeep.getSound();
testBeep.putSound(64);
testBeep.Beep();

The above code declares a reference of type IComBeeper, initializes it by creating an instance of the COM class CComBeeper, gets and sets the value of a property of the object, and then calls a method on the object. For more information, see Type Mappings Between Java and COM and COM Programming in Java and C++ Compared.

Important Note The only restriction on using Java classes that wrap COM classes is that you cannot use an instance of the class directly; you must always use it through an interface. This is a limitation of the JavaTLB tool, not the VM. Future tools may remove this restriction.

For example, the following would be legal Java code, but will cause errors when used with a COM class:

CComBeeper testBeep = new CComBeeper(); // DON'T DO WITH COM CLASS
int myTone = testBeep.getSound(); // CAUSES RUN-TIME ERROR WITH COM CLASS

Note Because CComBeeper is a COM class, you must use one of its interfaces to manipulate an instance of the class.

COM does not support accessing properties or methods on a class independently from its interfaces.

Note that in the above example, the statement "import comserver.*;" is not strictly necessary. In Java, any class can be referenced using its fully qualified name (for example, java.awt.Canvas), as long as a class fitting that name can be found when searching the class path. The import statement simply allows you to refer to the class using its short name (for example, Canvas).

The same is true for COM classes. The import statement is not required in order to use the COM class, it simply allows the class to be referenced using its short name. Any COM class can always be referenced using its fully qualified name (comserver.CComBeeper, in the above example).


What the JavaTLB Tool Generates

The JavaTLB tool is used to generate Java class wrappers out of type library information. To use it, simply type "javatlb filename", where filename is the name of the .TLB file (or .OCX, .DLL, or .EXE file containing the type library information.)

For each type library on which it is run, the JavaTLB tool creates a directory below the trusted library directory having the same name as the type library. The JavaTLB tool fills that directory with .CLASS files, one for each COM class and/or interface described in the type library. All the generated classes and interfaces are part of a Java package having the same name as the type library file. (If the type library contains an importlib statement, the JavaTLB tool creates a separate Java package in a separate directory for the imported type library.)

For instance, in the Comserver example, running the JavaTLB tool on comserver.DLL would create the directory \windows\java\trustlib\comserver (this assumes that \windows\java\trustlib is the trusted library directory) and place the files CComBeeper.class and IComBeeper.class there. Because the \comserver subdirectory is below the trusted library directory, the Java compiler can find the comserver subdirectory and its contents, and the statement "import comserver.*;" allows you to refer to the classes by their short names.

Each .CLASS file generated by the JavaTLB tool contains a special attribute identifying it as a wrapper for a COM class. When the Java support in Internet Explorer sees this attribute on a class, it translates all Java method invocations on the class into COM function invocations on the COM class. (For a COM interface that defines properties, the corresponding Java interface defines two methods for each property, named getproperty and putproperty, where property indicates the property name. If the COM interface defines methods with the propget or propput attributes, the Java interface versions of those methods have get or put prepended to their names. )

Once you have run the JavaTLB tool for a given type library, you don't need to re-run it unless the type library has changed. Once the JavaTLB tool has generated .CLASS files for a type library, your Java program has no further need for the type library. When distributing an applet that uses COM, your Java program needs only its own .CLASS files, the .DLL, .EXE, or .OCX that implements the COM services, and the generated .CLASS files for the COM services. You must also be sure to register the COM object appropriately.

If you include COM objects with Java applets embedded on a Web page, the .OCX or .DLL files that implement the COM object should have digital signatures. The Java applets should be packaged into a digitally signed cabinet (.CAB) file.

See Using the JavaTLB Command-Line Tool for more information on using this tool.


Trusted vs Untrusted Applets

Java applets typically run in a "sandbox," a carefully delimited execution environment that prevents them from doing anything that could interfere with your system. The use of COM services means accessing resources outside the sandbox. To prevent Java applets from posing a security threat, the Java support in Internet Explorer categorizes classes as either trusted or untrusted.

Note An applet must be packaged into a .CAB file and digitally signed in order to use COM services. Although in some development environments, such as Visual J++ Developer Studio, this restriction is suppressed during application development, it is always enforced in browsers supporting .CAB files, such as the Microsoft Internet Explorer browser.

When executing a Java class, Internet Explorer behaves differently depending on whether the class is trusted or not. The primary difference is the way that Internet Explorer searches the class path.

There are four class path-related registry keys that are relevant to the security of Java applets. All of these keys are subkeys of HKEY_LOCAL_MACHINE\Software\Microsoft\Java VM:


Class Path Searching During Execution

When executing a trusted applet, Internet Explorer looks in the following places for classes referenced by the applet:

  1. The trusted class path.
  2. The trusted library directory.
  3. The class path.
  4. The library directory.

When executing an untrusted applet, Internet Explorer looks in the following places for classes referenced by the applet:

  1. The class path.
  2. The library directory.

The Java support in Internet Explorer also employs security mechanisms besides restricting the class path searching. For example, any classes that are Java wrappers for COM classes are inaccessible to untrusted applets, even if those classes happen to be located on the regular class path or in the libraries directory.

In summary:


Class Path Searching During Development

During compilation of any Java program, the compiler looks in:

  1. The trusted class path.
  2. The trusted library directory.
  3. The class path.
  4. The library directory.
  5. The class path as specified in the CLASSPATH environment variable.


Type Mappings Between Java and COM

The Java support in Internet Explorer allows most constructs that can be specified in a type library to be accessed from Java. COM constructs that cannot be described in a type library are inaccessible from Java. To see exactly how the COM constructs are exposed in Java, see the SUMMARY.TXT files created by the JavaTLB tool for each class and interface.

Library Elements

There are five basic types of elements that can be defined in Object Description Language (ODL), and thus in a type library. These are mapped to Java as follows:
ODL element Java element
coclass public class
interface public interface
dispinterface public interface
typedef (struct, enum or union) public final class
module public final class with public static final members

The interface keyword in ODL is used to define custom (that is, v-table based) interfaces.

The dispinterface keyword in ODL is used to define dispatch interfaces. Properties in the dispatch interface are accessible in Java through two methods named get<property> and put<property> in the Java interface.

Interface Methods

The methods generated for an interface do not include those it inherits from IUnknown or IDispatch.

Methods declared with the propget or propput attributes are exposed with get or put prepended to their names.

Parameters

The following ODL types are supported, and they map to Java types in the following manner:
ODL Type Java Type
boolean boolean
char char
double double
int int
int64 long
float float
long int
short short
unsigned char byte
BSTR class java.lang.String
CURRENCY/CY long (divide by 10,000 to get the original value as a fixed-point number)
DATE double
SCODE/HRESULT int (see also class com.ms.com.ComException)
VARIANT class com.ms.com.Variant
IUnknown * interface com.ms.com.IUnknown
IDispatch * class java.lang.Object
SAFEARRAY(typename) class com.ms.com.SafeArray
typename * single-element array of typename on [out], error on [in]
void void

For information on accessing the contents of a VARIANT structure, see the class Variant.

IUnknown is the interface from which all COM interfaces are derived. The Java versions of COM interfaces are derived from com.ms.com.IUnknown. Because IUnknown is simply a placeholder for COM interfaces, you never have to call any methods on com.ms.com.IUnknown. If your Java program calls a COM method that takes a parameter of type com.ms.com.IUnknown, you can pass any COM interface. If your Java program calls a COM method that has com.ms.com.IUnknown as its return type, you can cast the return value to the COM interface you're expecting.

Certain ODL attributes cause a parameter to be treated in a special manner:

The following are examples of ODL declarations and their corresponding Java declarations.

Declarations with simple parameters:
HRESULT Func([in] int x); void Func(int x);
HRESULT Func([in,out] int* x); void Func(int[] x);
HRESULT Func([out,retval] int* x); int Func();

Declarations with string parameters:
HRESULT Func([in] BSTR x); void Func(java.lang.String x);
HRESULT Func([in,out] BSTR* x); void Func(java.lang.String[] x);
HRESULT Func([out,retval] BSTR* x); java.lang.String Func();

Declarations with VARIANT parameters:
HRESULT Func([in] VARIANT x); void Func(com.ms.com.Variant x);
HRESULT Func([in] VARIANT* x); void Func(com.ms.com.Variant x);
HRESULT Func([in,out] VARIANT* x); void Func(com.ms.com.Variant x);
HRESULT Func([out,retval] VARIANT* x); com.ms.com.Variant Func();
HRESULT Func([in,out] VARIANT** x); void Func(com.ms.com.Variant[] x);

Declarations with interface pointer parameters:
HRESULT Func([in] IBar* x); void Func(IBar x);
HRESULT Func([in,out] IBar** x); void Func(IBar[] x);
HRESULT Func([out,retval] IBar** x); IBar Func();

For information on the HRESULT returned by a COM function, see Handling COM Errors in Java.

For more information about type libraries, see the OLE SDK.


COM Programming in Java and C++ Compared

For those who are familiar with COM programming in C++, this topic compares it with COM programming in Java. Java's notion of multiple interfaces on an object, along with Java's garbage collection, map readily to COM's paradigm for managing objects. For more information on COM, see the Component Object Model Specification in the Win32 Software Development Kit.

Object Allocation

In C++, you allocate a new COM object using syntax like the following:

IDrawable pDrawable;
CoCreateInstance(CLSID_MyCircle, NULL, CLSCTX_SERVER,
                 IID_IDrawable, (void**)&pDrawable );

In Java, the equivalent code would look like this:

IDrawable drawable = (IDrawable)new MyCircle();

This is identical to Java's syntax for allocating ordinary Java objects. Behind the scenes, this line performs a call to the COM API function CoCreateInstance instead of simply allocating space in the run-time heap. However, that is invisible to the Java programmer.

Important Note Note that when using Java classes that wrap COM classes, you cannot use an instance of the class directly; you must always use it through an interface.

For example, the following code should not be used:

MyCircle circ = new MyCircle(); // DON'T DO WITH COM CLASS

You can use MyCircle only through one of the interfaces that it supports. Otherwise, you will get a run-time error when you try and use the class itself.

Changing Interfaces

COM objects must implement the IUnknown::QueryInterface function to allow clients to switch between the object's supported interfaces. In Java, the details are handled by Internet Explorer's Java support, so at the source-code level it is simply done with a typecast.

For example, in C++ you might have code like this:

// pDrawable points to an object that supports 
// both IDrawable and IPrintable
IPrintable *pPrintable;
pDrawable->QueryInterface( IID_IPrintable, 
                           (void **)&pPrintable );

In Java, the equivalent code would look like this:

// drawable refers to an object that supports
// both IDrawable and IPrintable
IPrintable printable;
printable = (IPrintable)drawable;

If the object does not implement the requested interface, a ClassCastException is thrown when you attempt the cast. You can also use the instanceof operator to check beforehand whether the object implements the requested interface. Again, this is identical to Java's syntax for casting between ordinary Java object types.

Object Identity

In COM, object identity is defined as having the same IUnknown pointer. For example, in C++, to check whether two pointers refer to the same object, you need code like this:

// comparing pDrawable and pPrintable
IUnknown *pUnk1, *pUnk2;
pDrawable->QueryInterface( IID_IUnknown, 
                           (void **)&pUnk1 );
pPrintable->QueryInterface( IID_IUnknown,
                            (void **)&pUnk2 );
if ( pUnk1 == pUnk2 )
    printf( "It's the same object" );

In Java, the equivalent code would look like this:

// comparing drawable and printable
if (drawable == printable )
    System.out.println( "It's the same object" );

As in the previous examples, this is identical to Java's syntax for comparing two object references.

Reference Counting

Reference counting is handled automatically in Java. There is no need to call IUnknown::AddRef when creating a new reference to an object, nor do you need to call IUnknown::Release when you're finished using a reference to an object. The Java garbage collector automatically keeps track of how many references there are to an object.

Summary

As shown by these examples, COM programming is much simpler in Java than in C++. The Java support in Internet Explorer performs all the tedious work for you, making COM classes as easy to use as native Java classes.


Handling COM Errors in Java

COM methods typically return a value known as an HRESULT, which is a 32-bit error code. The Java support for Internet Explorer defines a class called com.ms.com.ComException. This class wraps the HRESULT error code, and is used to communicate error information from COM back to Java whenever a COM method fails.

Whenever a COM method is exposed to Java, it is exposed as a Java method with an implicit throws clause. For example:

int convert( char x ) throws com.ms.com.ComException;

Because ComException is derived from the Java class RuntimeException, the compiler does not strictly require a throws clause in the method declaration. Nor does the compiler require try and catch blocks; run-time exceptions are unchecked by the compiler, so it is up to your discretion when to use try-catch blocks.

The ComException class defines a getHResult method that returns the error code, in the form of a Java int, describing the specific error. You can also use the getMessage method (defined by the Java class Throwable) to get the detail message.

There are two subclasses of ComException: ComFailException and ComSuccessException. ComFailException is the one you typically try to catch.

try
{
    // call COM methods
}
catch (com.ms.com.ComFailException e)
{
    System.out.println( "COM Exception:" );
    System.out.println( e.getHResult() );
    System.out.println( e.getMessage() );
}

Note that the ComFailException class is referenced using its fully-qualified name. If you added an "import com.ms.com.*;" statement to the beginning of the file, you could refer to the class by its short name.

For a list of the values of common system-defined HRESULTs, see ComFailException. For domain-specific errors, consult the documentation for the component you are using.

The documentation for many components describes errors in terms of Visual Basic Err.Number values rather than HRESULTs. However, some components use a convention where there is a correspondence between the HRESULT returned and the Err.Number value. For example, if you are using Data Access Objects (DAO) or Remote Data Objects (RDO), you can call the getHResult method on the ComFailException object, take the lower 16 bits of the returned HRESULT, convert that value to decimal, and check it against the errors described in the DAO or RDO documentation.

Top© 1997 Microsoft Corporation. All rights reserved. Legal Notices.