Technical Information
Using COM Objects from Java

Chad Verbowski
Software Design Engineer
Microsoft Corporation

January 1999

DownloadDownload this document in Microsoft Word format (zipped, 78 KB)

Contents

Introduction
Overview of COM
Java-Callable Wrappers
Apartment Threading
Creating an Instance of a COM Object
Invoking COM Interface Methods
Threading of COM Object Method Parameters
Garbage Collection of COM Objects
Generating JCWs for COM Objects
COM Coclasses in Java
COM Interfaces in Java
VTable, Dispatch, and Dual Interfaces
COM Interface Methods in Java
COM Method Parameters in Java
Java-Callable Data Wrappers as Parameters
Using JCWs in Java Applications
Using JCWs with AWT Controls
Distributed COM

Introduction

This tutorial describes how the Microsoft virtual machine (Microsoft VM) creates and exposes Component Object Model (COM) objects to the Java developer. The reader should have a general understanding of what COM is and some experience programming in Java. This tutorial also has samples that are based on COM objects exposed by the Microsoft® Internet Explorer 4.0 COM object model. They demonstrate how COM objects can be used in Java applications. Additional Java/COM information is available in the Microsoft SDK for Java.

COM is a popular object model for creating software applications from independent components. The binary interfaces exposed by COM objects are platform-independent. Therefore, various facets of applications can be written in any COM-compliant language. COM objects also promote encapsulation and object reuse. For example, earlier functionality can be contained in COM wrappers and reused in Microsoft® Windows® Distributed interNet Applications Architecture (Windows DNA) and other Web environments.

By using Java/COM wrappers, the Microsoft VM presents COM objects as regular Java objects. These Java objects contain extra information that the Microsoft VM uses to create and maintain the underlying COM object. The Microsoft VM automatically handles reference counting, garbage collection, marshaling, and threading for every Java/COM object. It does so by combining internal manipulation of COM interfaces with basic Java functionality.

Back to TopBack to Top

Overview of COM

COM defines a language-independent binary standard for component interoperability. Each COM component can potentially implement several standard or custom interfaces to expose its functionality. These interfaces are the binary standards through which clients and component objects communicate. COM interfaces define related groups of methods. Every COM interface and class has its own globally unique identifier (GUID). The GUID is a 128-bit identification number that uniquely represents the COM interface or class across platforms, computers, and applications. The GUID of a COM interface is an interface identifier (IID), and the GUID of a COM class is a class identifier (CLSID).

COM interfaces can be defined with the Interface Definition Language (IDL). These definitions can be converted into binary form by the Microsoft Interface Definition Language (MIDL) compiler.

Binary interface definitions permit runtime reuse of classes, and permit the actual implementation of COM component object classes (coclasses) and their interfaces to occur in the most appropriate languages. All COM interfaces must extend the root interface IUnknown, and every COM object must implement IUnknown. The IUnknown methods are as follows:

  • IUnknown::AddRef( ) increments the reference count for an interface on an object.
  • IUnknown::QueryInterface( ) requests another interface that is implemented by the COM object. If the object supports the requested interface, QueryInterface( ) retrieves a pointer to the interface while also calling AddRef( ).
  • IUnknown::Release( ) decrements the reference count for the calling interface on a object. If the reference count on the object falls to zero, the object is freed from memory.

Microsoft has defined COM interfaces that provide common functionality. For example, IPersist and interfaces that inherit from IPersist contain methods that allow a client to ask an object to load its persistent data, thus initializing itself. COM objects can implement the IDispatch interface to make themselves accessible from high-level languages such as Microsoft® Visual Basic® and scripting languages such as JavaScript, Microsoft® Visual Basic® Scripting Edition (VBScript), and Active Server Pages.

COM objects are implemented by creating an object in a COM-compliant language, and implementing IUnknown along with other Microsoft- or custom-defined COM interfaces. The MSDN® Library provides detailed information on the Microsoft-defined COM interfaces.

For more information about COM interfaces, see the COM Interface Reference This link takes you to a site on microsoft.com.

For information about CoCreateInstanceEx( ), see the COM Functions Reference This link takes you to a site on microsoft.com.

Back to TopBack to Top

Java-Callable Wrappers

Java-Callable Wrappers (JCW) are simple Java objects with additional class file attributes. The Microsoft VM uses Microsoft-defined attributes in Java classes to expose COM objects to Java applications. These attributes are typically generated by the Microsoft Java compiler, jvc, from @com directives in Java source files. The Java representation of COM coclasses and interfaces looks exactly like other Java classes and interfaces, except for the addition of @com directive comments above the class, interface, and method prototypes.

A coclass might look like this:

  /**
  * @com.class(classid=0002DF01-0000-0000-C000-000000000046, DynamicCasts)
  */
  public class InternetExplorer implements IUnknown, ... {
 

An interface definition could look like this:

  /**
  * @com.interface(iid=0002DF05-0000-0000-C000-000000000046, thread=AUTO, type=DUAL)
  */
  public interface IWebBrowserApp {
 

Interface methods may look like this:

  /**
  * @com.method(vtoffset=48, dispid=407, type=PROPPUT, name="FullScreen",
                addFlagsVtable=4)
  * @com.parameters([in,type=BOOLEAN] pbFullScreen) 
  */
  public void setFullScreen(boolean pbFullScreen);
 

Because the @com directives appear as comments in Java source code, compilers that do not support them ignore the directives and compile the class as a regular Java class file. Similarly, virtual machines that do not support the COM attributes in class files ignore them.

The following example shows how the Microsoft VM exposes COM objects to Java runtime code as regular Java objects using a generic Java object (Figure 1) and an exposed COM object (Figure 2). Figure 1 shows how the Java instance is represented in memory, including its references to various components from the object's class file. A typical Java class is represented inside the Microsoft VM as follows:

  package test;
 
  public class MyClass{
    public int nField1 = 0;
    public String strField2 = 0;
    public char chField3 = ' ';
  }

A generic Java object at runtime

Figure 1: Abstract representation of a generic Java object at runtime in the Microsoft VM

The Microsoft VM internally uses a Java-Callable Wrapper (JCW) to represent a COM object in Java. JCWs appear to Java developers as generic Java objects. JCWs are programmatically manipulated in exactly the same way as any regular Java object. The garbage collector handles any cleanup required if no Java references to the Java/COM object exist, and interfaces are automatically queried whenever a cast operation occurs. Figure 2 is a high-level diagram of the JCW coclass.

A Java-Callable Wrapper

Figure 2: Abstract representation of a Java-Callable Wrapper in the Microsoft VM

Notice that the JCW representation is an extension of the regular Java object internal structure. (The shaded boxes indicate COM extensions to the structure.) The JCW contains all the information necessary for the Microsoft VM to manipulate the underlying COM object. The threading model is used with the thread context (apartment) for marshaling to the correct thread when the COM object is not callable from any thread (see the Apartment Threading section of this topic for more details). The class file attributes created from the @com directives in the Java source file provide the necessary information for the Microsoft VM to create the COM object, call vtable or dispatch methods, and marshal parameters between Java and COM. The cache of interfaces associated with each JCW optimizes interface queries by storing references to previously queried interfaces.

CreateInstance( )

Object creation is accomplished in COM through a standard creation method. COM-compliant languages typically expose a function to create a new instance of a COM class. Typically, this function takes a CLSID or human-readable programmatic identifier (ProgID) as a parameter and returns a reference to the new COM object's IUnknown interface. IUnknown::QueryInterface( ) obtains a pointer to the required interface implemented by the COM object. The Microsoft Guidgen tool generates new GUIDs by using the CoCreateGuid( ) function from the COM API. For more details about GUIDs and Guidgen, see the COM specification on http://www.microsoft.com/com/default.asp This link takes you to a site on microsoft.com.

The CreateInstance( ) method must obtain the class factory for the specified COM class before it can create a new instance and return it. CreateInstance( ) will internally use the function CoGetClassObject( ) for accomplishing this. CoGetClassObject( ) looks in the Windows registry under the HKEY_CLASSES_ROOT\CLSID key for a subkey with the same name as the GUID for the class of the COM object it is trying to create. This key will have subkeys that contain the name of the dynamic-link library (DLL) or application that implements the class factory for creating instances of that COM class. CoGetClassObject( ) returns this class factory to CreateInstance( ), which uses it to create a new instance of the object, and then returns it to the caller. The class factories returned by CoGetClassObject( ) are COM objects, which implement the IClassFactory interface or one of its derivatives.

After an application is finished using a COM object, it calls the Release( ) method from the COM object's IUnknown interface. When all the clients using the COM object have released their references, the COM object removes itself from memory, and then unloads the associated library or application if it was the last object being used from that COM object provider.

COM objects can be used in the same manner as regular Java objects because the Microsoft VM exposes COM objects as Java objects. A COM object is created by applying the new operator to the JCW class representing the COM object's class. The Microsoft VM checks if the class used to create the instance is a JCW. If so, it performs the necessary COM operations to create the underlying COM object. The Microsoft VM reads the CLSID for the underlying COM object from the class file's COM_CLASS_TYPE attribute as specified in the @com.class(clsid=...) directive, and uses this in a call to CoCreateInstance( ). If this call succeeds, the resulting interface is stored inside the Microsoft VM's representation of the JCW (see Figure 2).

Some COM objects can only be used from the thread that they were created from. As a result, the Microsoft VM will store information about the thread used to create the COM object in the JCW. That thread information allows the Microsoft VM to handle the underlying COM object from the correct thread context when performing operations on the underlying COM object, such as querying for interfaces.

Microsoft® J/Direct® can also be used to access the Microsoft® Win32® API's COM functions to create new instances of COM classes. The com.ms.win32.Ole32 class contains J/Direct method mappings for many COM functions, including CoCreateInstance( ) and CoCreateInstanceEx( ). CoCreateInstanceEx( ) is particularly useful: It takes a remote computer's name and security credentials as parameters to facilitate remote instantiation of COM objects. CoCreateInstanceEx( ) is the best way to access the functionality of Distributed COM (DCOM).

The J/Direct CoCreateInstance[Ex]( ) function calls can be used to create new instances of COM objects, even if no JCW has been created for the COM object. When the Microsoft VM attempts to marshal a COM object between native code and Java, it coerces the result into the expected Java type, which would typically be the JCW for the COM object or interface. When using a generic CreateInstance[Ex]( ) function through J/Direct, however, the return value will be typed as a generic java.lang.Object. The Microsoft VM has a generic JCW (com.ms.com.CUnknown) that it uses to represent an unknown COM object in Java. CUnknown can be cast to any JCW representing a COM interface supported by the underlying COM object.

It is occasionally useful to create and use an arbitrary COM object from Java without having to first generate JCWs. Script programmers will be familiar with the CreateObject function that takes a COM object's ProgID as a parameter. Create a COM object using Active Server Pages (ASP) as follows:

     Set Obj = Server.CreateObject("IISSample.HelloWorld")

Although there isn't a single method that wraps this up as neatly as the IIS service, the following code sample uses J/Direct to get the same effect. The com.ms.com.Dispatch class can be used for late-bound IDispatch access to an object.

import com.ms.com.*;
public class CreateObject {
private static native _Guid CLSIDFromProgID(String str);
 
  private static _Guid IID_IUnknown = new _Guid("{00000000-0000-0000-C000-000000000046}");
 
  private static Object createObject(String str) {
    return com.ms.win32.Ole32.CoCreateInstance(
            com.ms.win32.Ole32.CLSIDFromProgID(str), 
            null, ComContext.INPROC_SERVER | 
              com.ms.win32.win.CLSCTX_LOCAL_SERVER, 
            IID_IUnknown);    }
 
    public static void main(String args[]) {
    //  Load Excel and print its name property.
    Object excel = createObject("Excel.Application");
    System.out.println(Dispatch.get(excel, "name"));
    com.ms.com.ComLib.release(excel);
}

QueryInterface( )

IUnknown is the base interface in COM that every COM object must implement. Its QueryInterface( ) method is used to query a COM object for any of its implemented interfaces. The Java/COM integration provided by the Microsoft VM provides QueryInterface( ) functionality through the Java cast operation. When it performs the casting operation, the Microsoft VM checks if the object being cast is a JCW, and if the type being cast to is a Java class representing a COM interface. If both these conditions are met, the Microsoft VM queries the underlying COM object for the required interface and continues. The Microsoft VM supports the ability to cast the COM object to any of its COM interfaces, even if its JCW class doesn't explicitly implement a Java class representing those COM interfaces. This is specified in the JCW for the coclass by adding the DynamicCasts parameter to the @com.class directive. The QueryInterface( ) operation is described in Figure 3.

A QueryInterface() operation

Figure 3: How the Microsoft VM performs a QueryInterface( ) operation on a JCW

  1. The Microsoft VM checks the JCW's interface cache for the required interface. If found, it uses the cached copy and continues.
  2. If the interface is not in the JCW's interface cache, the Microsoft VM marshals to the COM object's home thread to perform a QueryInterface( ) method call.
  3. Next, the Microsoft VM queries for the requested interface.
  4. Then, the Microsoft VM stores the interface in the JCW's interface cache, and then continues.

Exceptions

COM functions and interface methods typically indicate error conditions by returning HRESULTs. Java methods, on the other hand, typically indicate error conditions by throwing Java exceptions. To make working with COM objects more like operating on Java objects, HRESULTs are mapped by the Microsoft VM to Java exceptions. The Microsoft VM will automatically throw an instance of a derivative from the abstract exception class com.ms.com.ComException, such as com.ms.com.ComFailException or com.ms.com.ComSuccessException, if the HRESULT returned from a JCW method call is other than S_OK. For more information on HRESULTs, see the MSDN Library. For details on the ComException classes, see the Microsoft SDK for Java.

Back to TopBack to Top

Apartment Threading

COM objects are sensitive about which threads they can be created on and which threads their methods can be invoked from. By exposing COM objects to Java through JCWs, the Microsoft VM handles the threading issues related to using COM objects for the Java developer. As a result, invoking methods and initializing threads makes working with COM from Java easier and more productive.

The threading contexts that COM objects are useable from are called apartments. COM objects that can't be used in a multi-threaded environment require a single-threaded apartment (STA). A Microsoft® Windows® thread prepares itself to host an STA COM object by calling the COM initialization function CoInitialize( ), and then starting a message pump to forward the COM-related Win32 messages that it will receive. Access to the hosted COM object can only occur within the STA's thread context. The process of preparing to operate on the COM object from the correct thread (marshaling to the thread) will generate Win32 messages posted to the STA, which effectively synchronizes access to the hosted COM object.

The Microsoft VM internally maintains an STA thread for creating COM objects. This STA will be used whenever a Java application creates a new instance of a COM object from a regular Java thread. For performance reasons, it is sometimes desirable to create a Java STA thread for the COM object to be created and hosted on1.

1 The performance enhancements of creating an STA versus using the default VM STA are that method calls don't need to be marshaled to the VM's STA, and the fact that having many COM objects in an STA will queue access to them, which could cause delays.

To create a Java thread capable of directly creating and hosting COM objects, call the ComLib.declareMessagePumpThread( ) method at the start of the Java thread's run( ) method. This tells the Microsoft VM that the Java thread will implement a message pump, if necessary, to service incoming COM calls. An example of this is shown as follows:

package tutorial.sample;
 
public class STA extends Thread {
   /** 
    *Hosted COM object
    */
   private Object comObject = null;
   /**
    *   The returned object will be a proxy to the hosted COM object.
    *   The Microsoft VM will automatically take care of any thread
    *   marshaling requirements, allowing the returned object to be
    *   used like any other Java object.
    */
   public Object getHostedCOMObject( ){
      return com.ms.com.ComLib.makeProxyRef(comObject);
   }
   
   public void run(){
      com.ms.com.ComLib.declareMessagePumpThread();
      comObject = new SomeJCWClass();
      com.ms.win32.MSG msg = new com.ms.win32.MSG();
         while (com.ms.win32.User32.GetMessage(msg, 0, 0, 0)) {
            com.ms.win32.User32.TranslateMessage(msg);
              com.ms.win32.User32.DispatchMessage(msg);
      }
   }
}

COM objects that support multi-threaded apartments (MTAs) are capable of receiving method calls from other threads at any time, and must implement synchronization in their interface method implementations as required. A process contains only one MTA in which all threads reside that are initialized as part of the MTA. However, that same process may also contain many STAs. Method calls on a COM object that resides in the MTA can be serviced from any MTA thread in the process. This means that a caller doesn't need to marshal to a different thread before invoking a method on an MTA COM object on any MTA thread.

com.ms.com.ComLib.startMTAThread(Thread) automatically starts a Java thread and initializes the thread as an MTA thread by calling CoInitializeEx( ) with the necessary parameters. java.lang.Thread.start( ) always calls CoInitialize( ), which initializes a thread as an STA thread.

Back to TopBack to Top

Creating an Instance of a COM Object

The Windows registry contains a list of all COM classes registered on the local system. It has information on how to create new instances and their supported threading models. In particular, the ThreadingModel value under the InprocServer32 and LocalServer32 keys for each COM class entry specify the supported threading models. The following table shows their possible values.

ThreadingModel

Description

Absence of ThreadingModel

or

None

Originally, COM components didn't support threading models; new instances had to be created on the thread that called CoInitialize( ) to initialize COM operations on that thread. This is denoted in the registry through the absence of a ThreadingModel value in the InprocServer32 or LocalServer32 keys or by setting ThreadingModel=None.

Apartment

Apartment-threaded components can only be created on threads capable of hosting such objects. A thread prepares to host apartment-threaded COM objects by calling CoInitialize( ) to initialize itself as an STA, and then starts a message pump to forward COM-related Win32 messages it will receive. STA COM objects can only have their methods invoked from the STA they reside in. In the Microsoft VM, Thread.start( ) automatically calls CoInitialize( ).

Free

Indicates that the COM class supports free-threading, and is hosted in an MTA. Method invocations can occur from any thread in the MTA's thread pool. A thread joins an MTA thread pool by calling CoInitializeEx(COINIT_MULTITHREADED). In Java, com.ms.com.ComLib.startMTAThread(Thread) automatically calls CoInitializeEx(COINIT_MULTITHREADED).

Both

Specifies that the COM object can be hosted on both STA and MTA threads.

 

STA COM objects created (by default) by the Java new operator on a JCW class are created and serviced on a separate Microsoft VM-implemented STA thread. A Java thread that wants to directly create and manipulate STA COM objects, without marshaling to the Microsoft VM's internal STA thread, can call com.ms.com.ComLib.declareMessagePumpThread( ) and run a message pump. The Microsoft VM treats all COM classes implemented by local servers as STA COM classes, and uses the default STA rules for handling any Java new operations. J/Direct CoCreateInstance( ) calls return a proxy owned by the calling thread's COM apartment.

The Microsoft VM handles the marshaling for CoCreateInstance. This eliminates resorting to awkward pointer routines (as defined in com.ms.win32.Ole32.CoCreateInstance) as shown in the following example:

 
     /** @dll.import("ole32", ole) */
     private static native com.ms.com.IUnknown CoCreateInstance
       (com.ms.com._Guid rclsid, com.ms.com.IUnknown outer,
        int dwClsContext, com.ms.com._Guid riid);

CoCreateInstance( ) returns an interface reference that the Java developer can cast to any required COM interface. The resulting JCW contains the current threading context and will be automatically marshaled (Thread=AUTO behavior, discussed in Invoking COM Interface Methods).

Back to TopBack to Top

Invoking COM Interface Methods

Generally in COM, interface methods cannot be invoked on arbitrary threads. Whenever the Microsoft VM manipulates an external COM interface pointer underlying a Java interface instance (for example, IUnknown), it must perform any required marshaling of that interface pointer. The Microsoft VM stores the threading model type of the underlying COM object in the JCW instance used to expose the COM object to Java. If the JCW is marked free-threaded, the call happens on that thread. If the wrapper is marked apartment-threaded and the current thread context is not the wrapper's home context, the Microsoft VM switches to the correct context and executes the call there. As in standard COM STA marshaling, internal windows determine thread switches, but MTA threads have no obligation to pump messages. Once the Microsoft VM has marshaled to the correct thread context for performing the work on the interface, the Microsoft VM may need to marshal some of the parameters for the invocation. If any of these parameters are not on the right context (based on the same decision as previously mentioned), standard COM marshaling passes out a compatible interface pointer to the external code.

Back to TopBack to Top

Threading of COM Object Method Parameters

The Microsoft VM automatically determines (by default) the threading model for COM objects used as parameters in Java. It also performs the necessary marshaling to ensure method invocations occur from the correct thread. This behavior can be explicitly controlled on COM objects passed as COM interface method parameters by specifying the thread= AUTO | NO parameter in the method's @com.parameters directive. A default value for all COM objects used as parameters for all methods in the interface can be specified in the @com.interface directive. The Microsoft VM first checks the @com.parameters directive for a thread=<XXX> value for the particular parameter. If no value is specified, the Microsoft VM checks the @com.interface thread=<XXX> value. If none is found, the Microsoft VM uses the default thread=AUTO setting.

Possible values for the thread=<XXX> parameter are as follows:

Thread=AUTO- Indicates that the Microsoft VM should handle the threading of the COM object and take care of marshaling to the correct thread to operate on it. This value indicates that the COM object is either MTA or STA. The Microsoft VM checks any COM object marked with thread=AUTO to see if the object has aggregated the free-threaded marshaler (FTM), and if it has, the Microsoft VM treats the COM object as thread=NO. If the COM object has not aggregated the FTM, its JCW contains the current thread's context.

Thread=NO- Indicates that the Microsoft VM should not perform any threading operations and assumes that any threading issues have been taken care of. The COM object is dealt with as if it has been aggregated with the FTM. The COM object's methods can be invoked from any thread.

Back to TopBack to Top

Garbage Collection of COM Objects

The garbage collection thread will not do the final release on a COM object. Every COM object wrapped as a Java object contains the thread context where it is safe to use the object. This could potentially be any thread context if the COM object aggregates the FTM. When the Java wrapper is garbage-collected, the underlying COM object's Release method will be called on the appropriate thread context. This is similar to the Microsoft VM's marshaling calls on arbitrary Java threads to the appropriate thread context (when necessary).

When a JCW is garbage-collected, each COM interface cached in the JCW will have its Release( ) method called by posting a cleanup message to the thread owning the JCW. The Microsoft VM does not block waiting for the Release( ) calls to actually happen. If the thread no longer exists, the post fails, orphaning the interface pointers. The JCW itself is still garbage-collected, however, because the thread doing the garbage collection times out the request to the owning thread, and continues.

com.ms.com.ComLib.release(Object) is a shortcut for immediately releasing the underlying COM object, rendering it immediately unusable. Some COM objects tie their reference count to the release of resources without an explicit dispose( ) or close( ) call. As a result, a mechanism for immediately disconnecting the Microsoft VM's reference was required. Once garbage collection has run and the Microsoft VM has found unused Java wrappers around COM objects, it queues the Release( ) method calls to the appropriate thread contexts based on the JCWs' thread information.

Back to TopBack to Top

Generating JCWs for COM Objects

JCWs can be generated using the jactivex tool provided in the Microsoft SDK for Java. Wrappers can be generated for existing COM components by running jactivex against the type library that represents the COM component and its associated interfaces. Type libraries are cross-platform binary representations of COM coclasses and COM interface definitions. They are usually2 created by compiling Interface Definition Language (IDL) code with the Microsoft Interface Definition Language (MIDL) compiler, which is available in the Platform SDK section of the MSDN Library. Type libraries are used by COM-compliant languages to determine how to represent these coclasses and interfaces in those languages. For instance, Microsoft Visual Basic developers typically import a type library into the Visual Basic development environment to use the COM objects and interfaces the type library describes.

2 JCWs can be created in other ways, too. The VM may be asked to create a JCW, which is how Javareg.exe and Vjreg.exe create type libraries.

Type libraries generated by the MIDL compiler are binary files that have a .tlb extension. It is possible to add type library information to a dynamic-link library (DLL) or .exe file as a resource. Common file extensions of files that may contain type library information are as shown in the following table.

Module extension

Description

DLL

Dynamic-link libraries may contain type library information.

EXE

Applications may contain type library information.

OCX

DLLs that contain Microsoft® ActiveX® Controls.

OLB

Microsoft® Office components store their type libraries in this format.

TLB

Denotes a type library. This will be the output from MIDL.

 

OleView is a COM tool that ships with the Platform SDK in the MSDN Library and Microsoft® Visual Studio® products. OleView is a simple application for examining the COM objects on your system. It presents a treeview of COM components installed on the system, a list of registered COM interfaces, and the installed type libraries. Typically, registered COM objects and COM interfaces contain the location of the file that contains the type library describing it. It is instructive to use OleView to browse through the COM objects, interfaces, and type libraries installed on your system. You can use OleView to examine a file that might contain type library information. For example, look at the shdocvw.dll file like this:

     oleview c:\winnt\system32\shdocvw.dll

The type libraries registered on your system describe some of the COM object models exposed by the installed applications. Examine these files to learn how to use the COM objects and interfaces for integration with their associated applications. Jactivex is a tool available in the Microsoft SDK for Java that generates JCWs from any type library. This tool provides instant access to Java classes for integrating with Win32 applications. The shdocvw.dll file contains the type library for the Microsoft® Internet Explorer 4.0 COM object model, and is used here to demonstrate how JCWs are generated. Then, a simple application is presented that uses the generated wrappers.

To generate the JCWs for shdocvw.dll, use the jactivex tool like this:

     jactivex /d . /p:b- /p tutorial.ie c:\winnt\system32\shdocvw.dll

Jactivex creates a tutorial\ie directory structure that contains about 50 Java classes, all defined in the tutorial.ie package. These Java classes contain the @com directives that generate the COM attributes in the compiled class files to make the classes JCWs.

Back to TopBack to Top

COM Coclasses in Java

The following is the generated Java wrapper for the Microsoft® Internet Explorer coclass :

package tutorial.ie;
 
import com.ms.com.*;
import com.ms.com.IUnknown;
import com.ms.com.Variant;
 
/** @com.class(classid=0002DF01-0000-0000-C000-000000000046,
               DynamicCasts) */
public class InternetExplorer
              implements IUnknown,
                         com.ms.com.NoAutoScripting,
                         tutorial.ie.IWebBrowser2,
                         tutorial.ie.IWebBrowserApp
{
  /** @com.method()
      @hidden */
  public native void GoBack();
 
  /** @com.method()
      @hidden */
  public native void GoForward();
 
  /** @com.method()
      @hidden */
  public native void GoHome();
 
  /** @com.method()
      @hidden */
  public native void GoSearch();
 
  /** @com.method()
      @hidden */
  public native void Navigate(String URL, Variant Flags, Variant TargetFrameName, 
    Variant PostData, Variant Headers);
 
  /** @com.method()
      @hidden */
  public native void Refresh();
 
[Code removed for brevity.]
 
  // getFullScreen UNMAPPABLE: Name is a keyword or conflicts with another member.
  //  /** @com.method()
  //      @hidden */
  //  public native boolean getFullScreen();
 
  // setFullScreen UNMAPPABLE: Name is a keyword or conflicts with another member.
  //  /** @com.method()
  //      @hidden */
  //  public native void setFullScreen(boolean pbFullScreen);
 
  public static final com.ms.com._Guid clsid = new com.ms.com._Guid((int)0x2df01,
    (short)0x0, (short)0x0, (byte)0xc0, (byte)0x0, (byte)0x0, (byte)0x0, (byte)0x0,
      (byte)0x0, (byte)0x0, (byte)0x46);
}

@com.class

The comments at the start of the source file were generated by jactivex, which contains the exact command line parameters used. The Java comment block above the class definition contains an @com.class directive, which specifies the GUID for the represented COM class and indicates that this class supports dynamic casts. A full description of the @com.class directive is presented here.

The @com.class directive is applied at the class level to indicate that the Java class definition represents a COM component object class (coclass).

Syntax

@com.class(classid=<COM CLSID>, DynamicCasts, safe, safeAddFlags=<integer>)

Parameter

Description

classid=<COM CLSID>

This parameter is required.

Example: classid=0BE35203-8F91-11CE-9DE3-00AA004BB851

The CLSID associated with the Java-implemented COM class.

DynamicCasts

Indicates that this class supports dynamic casts, which allow the Java developer to cast it to COM interfaces not directly implemented by the Java class. The Microsoft VM supports this by calling QueryInterface( ) for the target interface of the cast on the underlying COM object.

safe

Specifies that the class may be safely used by untrusted classes. A COM_Safety attribute is attached to the class.

safeAddFlags=<int>

Specifies a word (2 bytes) of information to be put in the COM_Safety attribute.

Note   The Microsoft VM currently ignores this data when reading the COM_Safety attribute.

 

The following table shows the attributes that the compiler will add to the generated Java class file when compiling the @com.class directive.

Attribute

Scope

COM_ClassType

Class scope.

COM_GuidPool

Class scope.

COM_Safety

Class scope.

 

The tutorial\ie\InternetExplorer.java file contains a class definition for the InternetExplorer coclass, which implements four interfaces. Three of these interfaces are JCWs that represent the COM interfaces IUnknown, IWebBrowser2, and IWebBrowserApp. The com.ms.com.NoAutoScripting interface is used as a flag by the Microsoft VM to indicate that this COM object is not accessible from scripting languages.

The methods presented in the source file are designated as hidden; they exist only to satisfy the Java requirement that all methods from all implemented interfaces are represented. The native designation on each method in the coclass tells the Microsoft VM that the implementation of the method is contained in the underlying COM object.

The static final CLSID field contains a com.ms.com._Guid initialized with the coclass's GUID.

Back to TopBack to Top

COM Interfaces in Java

The following is the jactivex-generated source file for the COM interface IWebBrowserApp:

package tutorial.ie;
 
import com.ms.com.*;
import com.ms.com.IUnknown;
import com.ms.com.Variant;
 
// Dual interface IWebBrowserApp
/** @com.interface(iid=0002DF05-0000-0000-C000-000000000046, thread=AUTO, type=DUAL) */
public interface IWebBrowserApp
{
  /** @com.method(vtoffset=4, dispid=100, type=METHOD, name="GoBack",
                  addFlagsVtable=4)
      @com.parameters() */
  public void GoBack();
 
  /** @com.method(vtoffset=5, dispid=101, type=METHOD, name="GoForward", addFlagsVtable=4)
      @com.parameters() */
  public void GoForward();
 
  /** @com.method(vtoffset=6, dispid=102, type=METHOD, name="GoHome", addFlagsVtable=4)
      @com.parameters() */
  public void GoHome();
 
  /** @com.method(vtoffset=7, dispid=103, type=METHOD, name="GoSearch", addFlagsVtable=4)
      @com.parameters() */
  public void GoSearch();
 
  /** @com.method(vtoffset=8, dispid=104, type=METHOD, name="Navigate", addFlagsVtable=4)
      @com.parameters([in,type=STRING] URL, [in,elementType=VARIANT,type=PTR] Flags,
                      [in,elementType=VARIANT,type=PTR] TargetFrameName,
                      [in,elementType=VARIANT,type=PTR] PostData,
                      [in,elementType=VARIANT,type=PTR] Headers) */
  public void Navigate(String URL, Variant Flags, Variant TargetFrameName, 
    Variant PostData, Variant Headers);
 
  /** @com.method(vtoffset=9, dispid=4294966746, type=METHOD, name="Refresh",
        addFlagsVtable=4)
      @com.parameters() */
  public void Refresh();
 
[Code removed for brevity.]
 
  /** @com.method(vtoffset=48, dispid=407, type=PROPPUT, name="FullScreen",
        addFlagsVtable=4)
      @com.parameters([in,type=BOOLEAN] pbFullScreen) */
  public void setFullScreen(boolean pbFullScreen);
 
  public static final com.ms.com._Guid iid = new com.ms.com._Guid((int)0x2df05,
    (short)0x0, (short)0x0, (byte)0xc0, (byte)0x0, (byte)0x0, (byte)0x0, (byte)0x0,
    (byte)0x0, (byte)0x0, (byte)0x46);
}

@com.interface

The tutorial\ie\IWebBrowserApp.java source file contains a Java interface definition that has been marked as a COM interface with a class-scope @com.interface directive. This directive contains the IID and specifies the type of COM interface that is represented (dual).

Syntax

@com.interface(iid=<GUID>, thread=AUTO | NO, type=DISPATCH | DUAL | VTABLE)

Parameter

Description

iid=<GUID>

Required. This GUID represents the IID for this interface.

thread=AUTO | NO

Specifies the default Microsoft VM marshaling behavior to be applied to the COM object method parameters in this interface's methods. If AUTO is specified, the Microsoft VM automatically marshals any calls from Java on this object to the thread that the object was created in. This is the safest option, and the default.

If NO is specified, the Microsoft VM assumes that the object is callable on any Java thread.

type=DUAL | DISPATCH | VTABLE

VTABLE indicates that this interface can be used only through a vtable.

DISPATCH indicates that this interface can be used only through IDispatch.

DUAL indicates that this interface is accessible through both its vtable and through IDispatch.

If the type is unspecified, vtable access is assumed.

 

The following table shows the attributes indirectly affected by @com.interface directive.

Attribute

Scope

COM_ExposedAs_Group

Method scope.

COM_GuidPool

Class scope.

COM_MethodPool

Class scope.

COM_ProxiesTo

Method scope.

 

Back to TopBack to Top

VTable, Dispatch, and Dual Interfaces

By default, COM interfaces use early binding through a virtual table (vtable) of function pointers. This means that references to COM interface methods are determined at compile time, and are therefore subject to all compile-time syntax checking rules. Each interface method is placed in the interface's vtable in a specific order. At compile time, the compiler can call an interface method through the code pointer at the method's offset in the interface's vtable. For example, looking at the interface definition for the base COM interface IUnknown, it contains three methods and has a specific vtable order for these methods. All COM interfaces extend IUnknown, have vtables that contain the three IUnknown methods in exactly the same vtable positions, and append their own methods to the base IUnknown vtable.

Automation is a mechanism that facilitates late binding to a COM object's interface methods by providing a generic Invoke( ) method. This is similar to using the reflection APIs in Java where the String form of the method name can be used to obtain a reference to the method. The generic Invoke( ) method is then called by passing the method identifier and all its required parameters. These late binding facilities are provided by the IDispatch interface, which contains methods for looking up the method ID (called the dispatch ID or DISPID) for a given method name, and for invoking the actual method. For this process of late binding to work correctly, it is necessary that only known data types be used as parameters to automation interfaces. The acceptable types are called automation data types, and are discussed in the COM Method Parameters in Java section of this topic.

Dispinterfaces are custom interfaces that extend IDispatch. By creating a dispinterface, a developer allows the interface's methods to be accessible through automation using the IDispatch interface. Dual interfaces are implemented as both dispinterfaces and vtable interfaces. This means that the functions they contain are accessible both from IDispatch and directly from the vtable. The implemented interface is available to C++ and Java programmers through early binding, and to Visual Basic and scripting programmers through the late binding of the IDispatch interface. Dual interfaces are the preferred way of implementing dispinterfaces.

Back to TopBack to Top

COM Interface Methods in Java

Each of the methods in the tutorial.ie.IWebBrowserApp interface definition has an associated @com.method directive that indicates how the COM method is mapped to Java.

@com.method

The @com.method directive indicates the method dispatch ID for dispatch interfaces, the vtable offset for vtable interfaces, or both for dual interfaces. It includes a set of parameters that indicate the mapping to the equivalent IDL form. Because COM interfaces support properties, the method can be a typical method or an accessor method for an interface property.

Syntax

@com.method(vtoffset=<offset>, dispid=<dispid>, name=<COM method name>, name2=<COM method name>, type=METHOD | PROPGET | PROPPUT | PROPPUTREF, nodispatch, returntype=VOID | HRESULT, addFlagsVtable=<int>

Parameter

Description

vtoffset=<offset>

This specifies the vtable offset for this method. Not required if the method is only being called through an IDispatch interface.

dispid=<dispid>

Indicates the dispatch ID for this method. Not required if this method is only being called through a vtable.

name="<COM method name>"

Example: name="<myMethod1>"

Specifies how to expose this Java method to COM by means of IDispatch. The Microsoft VM implements an IDispatch interface that maps the name given by this parameter to the DISPID given by the dispid parameter. If unspecified, the default is the method name.

name2="<COM method name>"

Specifies a secondary mapping from this Java method to COM by means of IDispatch. The Microsoft VM implements an IDispatch interface that maps the name given by this parameter to the DISPID given by the dispid parameter.

type=METHOD | PROPGET | PROPPUT | PROPPUTREF

Used for dispatch interfaces. Indicates the type of COM method represented by this Java method. The method may manipulate COM object properties or it may be a COM object method.

nodispatch

Specifies that this method should not be accessible through IDispatch.

returntype=VOID | HRESULT

Specifies the return type for this method. Generally, the default, HRESULT, is used. If HRESULT is specified, the COM method associated with this Java method returns an HRESULT. A com.ms.com.ComException will be thrown if the method returns a non-S_OK HRESULT. If the Java method returns a value, it is mapped to the last parameter in the COM method, which is assumed to be a return value.

If VOID is specified, the Java and COM method return values are directly related. That is, if the COM method returns an integer, its value is returned by the Java method.