Java/COM integration | CodeGuru

Java/COM integration

Bruce Eckel’s Thinking in Java Contents | Prev | Next COM (formerly known as OLE) is the Microsoft Component Object Model, the foundation of all ActiveX technologies. These include ActiveX Controls, Automation, and ActiveX Documents. But COM is much more; it’s a specification (and a partial implementation) for developing component objects that can interoperate using […]

Written By
CodeGuru Staff
CodeGuru Staff
Mar 1, 2001
16 minute read
CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More

COM


(formerly known as OLE) is the Microsoft Component Object Model, the foundation


of all ActiveX technologies. These include ActiveX Controls, Automation, and


ActiveX Documents. But COM is much more; it’s a specification (and a


partial implementation) for developing component objects that can interoperate


using dedicated features of the operating system. In practice, all of the new


software developed for Win32 systems has some relationship with COM – the


operating system exposes some of its features via COM objects. Third-party


components can be COM, and you can create and register your own COM components.


In one way or another, if you want to write Win32 code, you’ll have to


deal with COM. Here, I’ll just recap the fundamentals of COM programming,


and I’ll assume that you are familiar with the concept of a COM server


(any COM object that can expose services to COM clients) and a COM client (a


COM object that uses the services provided by a COM server). This section kept


things simple; the tools are actually much more powerful, and you can use them


in a more sophisticated way. But this requires a deep knowledge of COM, which


is beyond the scope of this appendix. If you’re interested in this


powerful but platform-dependent feature, you should investigate COM and the


Microsoft documentation on Java/COM integration. For more information, Dale


Rogerson’s “Inside COM” (Microsoft Press, 1997) is an


excellent book.

Since


COM is the architectural heart of all the new Win32 applications, being able to


use, or to expose, COM services from Java code can be important. The Java/COM


integration is no doubt one of the most interesting features of the Microsoft


Java compiler and virtual machine. Java and COM are so similar in their models


that the integration is conceptually straightforward and technically seamless


– there’s almost no special code to write in order to access COM.


Most the details are handled by the compiler and/or by the virtual machine. The


effect is that the COM objects are seen as ordinary Java objects by the Java


programmer, and COM clients can use COM servers implemented in Java just like


any other COM server. Again, I use the generic term COM, but by extension this


means that you can implement an ActiveX Automation server in Java, or you can


use an ActiveX Control in your Java programs.

The


most notable similarities between Java and COM revolve around the relationship


between COM interfaces and the Java


interface

keyword.


This is a near-perfect match because:

  • A
    COM object exposes interfaces (and only interfaces).
  • A
    COM interface has no implementation; the COM object exposing an interface is
    responsible for its implementation.
  • A
    COM interface is a description of a group of functions semantically related; no
    data is exposed.
  • A
    COM class groups together COM interfaces. A Java class can implement an
    arbitrary number of Java interfaces
  • COM
    has a reference object model; the programmer never “has” an object,
    just references to one or more of its interfaces. Java has a reference object
    model as well – a reference to an object can be cast to a reference to
    one of its interfaces.
  • The
    lifetime in memory of a COM object is determined by the number of clients using
    the object; when this count goes to zero, the object deletes itself from
    memory. In Java, the lifetime of an object is also determined by the number of
    clients. When there are no more references to that object, the object is a
    candidate to be released by the garbage collector.

This


tight mapping between Java and COM not only allows the Java programmer to


easily access COM features, but it also makes Java an interesting language for


writing COM code. COM is language-independent, but the de facto languages for


COM development are C++ and Visual Basic. Compared to Java, C++ is much more


powerful for COM development and generates much more efficient code, but


it’s hard to use. Visual Basic is much easier than Java, but it’s


too far from the underlying operating system, and its object model does not map


very well to COM. Java is an excellent compromise between the two.

Let’s


take a look at some of the keys points of COM development that you need to know


to write Java/COM clients and servers.


COM
Fundamentals

COM


is a binary specification for implementing interoperable objects. For example,


COM describes the binary layout an object should have to be able to call


services in another COM object. Since it’s a description of a binary


layout, COM objects can be implemented in any language that’s able to


produce such a layout. Usually the programmer is freed from these low level


details, since the compiler takes care of generating the correct layout. For


example, if you program in C++, most compilers generate a virtual function


table that is COM-compliant. With languages that do not produce executable


code, such as VB and Java, the runtime takes care of hooking into COM.

The


COM Library also supplies a few basic functions, such as the ones for creating


an object or locating a COM class registered in your system.

The


main goals of a component object model are:

  • Let
    objects call services into other objects.
  • Allow
    new types of objects, or upgrades to existing ones, to be seamlessly plugged
    into the environment.

The


first point is exactly what object-oriented programming is about: you have a


client object that makes requests to a server object. In this case, the terms


“client” and “server” are used in a generic way, and


not to refer to some particular hardware configuration. With any


object-oriented language, the first goal is easy to achieve if your application


is a monolithic piece of code that implements both the server object code and


the client object code. If you make changes to the way client and the server


objects interface with each other, you simply compile and link again. When you


restart your application, it uses a new version of the components.

The


situation is completely different when your application is made up of component


objects that are not under your control – you don’t control their


source code and they can evolve separately from your application. This is


exactly the case, for example, when you use a third-party ActiveX Control in


your application. The control is installed in your system, and your application


is able, at runtime, to locate the server code, activate the object, link to


it, and use it. Later, you can install a newer version of the control, and your


application should still be able to run; in the worst case, it should


gracefully report an error condition, such as “Control not found,”


without hanging up.

In


these scenarios, your components are implemented in separate executable code


files: DLLs or EXEs. If the server object is implemented in a separate


executable code file, you need a standard, operating system supplied method to


activate these objects. Of course, in your code you do not want to use the


physical name and location of the DLL or EXE, because these might change; you


want some identifier maintained by the operating system. Also, your application


needs a description of the services exposed by the server. This is exactly what


I’ll cover in the next two sections.


GUIDs
and the Registry

COM


uses structured integer numbers, 128 bits long, to unequivocally identify COM


entities registered in the system. These numbers, called

GUIDs
(Globally Unique IDentifiers) can be generated by specific utilities, and are
guaranteed to be unique “in space and in time,” to quote Kraig
Brockschmidt. In space, because the number is generator reads the id of your
network card, and in time because the system date and time are used as well. A
GUID can be used to identify a COM class (in which case it’s called a
CLSID) or a COM interface (IID). The names are different but the concept and
the binary structure are the same. GUIDs are also used in other situations that
I will not cover here.

GUIDs,


along with their associated information, are stored in the

Windows
Registry, or Registration Database. It’s a hierarchical database, built
into the operating system, which holds a great amount of information about the
hardware and software configuration of your system. For COM, the Registry keeps
track of the components installed in your system, such as their CLSIDs, the
name and location of the executable file that implement them, and a lot of
other details. One of these details is the ProgID of the component; a ProgID is
conceptually similar to a GUID in the sense that it identifies a COM component.
The difference is that a GUID is a binary, algorithmically-generated value,
whereas a
ProgID
is a programmer-defined string value. A ProgID is associated with a
CLSID.

A


COM component is said to be registered in the system when at least its CLSID


and its executable file location are present in the Registry (the ProgID is


usually present as well). Registering and using COM components is exactly what


we’ll do in the following examples.

One


of the effects of the Registry is as a decoupling layer between the client and


server objects. The client activates the server using some information that is


stored in the Registry; one piece of information is the physical location of


the server executables. If the location changes, the information in the


Registry is updated accordingly, but this is transparent to the client, which


just uses ProgIDs or CLSIDs. In other words, the Registry allows for location


transparency of the server code. With the introduction of DCOM (Distributed


COM), a server that was running on a local machine can even be moved to a


remote machine on the network, without the client even noticing it (well,


almost

).


Type
Libraries

Because


of COM’s dynamic linking and the independent evolution of client and


server code, the client always needs to dynamically detect the services that


are exposed by the server. These services are described in a binary,


language-independent way (as interfaces and method signatures) in the

type
library
.
This can be a separate file (usually with the .TLB extension), or a Win32
resource linked into the executable. At runtime, the client uses the
information in the type library to call functions in the server.

You


can generate a type library by writing a Microsoft Interface Definition


Language (MIDL) source file and compiling it with the MIDL compiler to generate


a .TLB file. MIDL is a language that describes COM classes, interfaces, and


methods. It resembles the OMG/CORBA IDL in name, syntax, and purpose. The Java


programmer has no need to use MIDL, though. A different Microsoft tool,


described later, reads a Java class file and generates a type library.


Function
return codes in COM: HRESULT

COM


functions exposed by a server return a value of the predefined type HRESULT. An

HRESULT
is an integer containing three fields. This allows for multiple failure and
success codes, along with additional information. Because a COM function
returns an HRESULT, you cannot use the return value to hand back ordinary data
from the function call. If you must return data, you pass a pointer to a memory
area that the function will fill. This is known as an
out
parameter
.
You don’t need to worry about this as a Java/COM programmer since the
virtual machine takes care of it for you. This is described in the following
sections.

MS
Java/COM Integration

The


Microsoft Java compiler, Virtual Machine, and tools make life a lot easier for


the Java/COM programmer than it is for the C++/COM programmer. The compiler has


special directives and packages for treating Java classes as COM classes, but


in most cases, you’ll just rely on the Microsoft JVM support for COM, and


on a couple of external tools.

The


Microsoft Java Virtual Machine acts as a bridge between COM and Java objects.


If you create a Java object as a COM server, your object will still be running


inside the JVM. The Microsoft JVM is implemented as a DLL, which exposes COM


interfaces to the operating system. Internally, the JVM maps function calls to


these COM interfaces to method calls in your Java objects. Of course, the JVM


must know which Java class file corresponds to the server executable; it can


discover this information because you previously registered the class file in


the Windows Registry using


Javareg

,


a utility in the Microsoft Java SDK.


Javareg

reads a Java class file, generates a corresponding type library and a GUID, and


registers the class in the system.

Javareg
can be used to register remote servers as well, for example, servers that run
on a different physical machine.

If


you want to write a Java/COM client, you must go through a different process. A


Java/COM client is Java code that wants to activate and use one of the COM


servers registered on your system. Again, the virtual machine interfaces with


the COM server and exposes its services as methods in a Java class. Another


Microsoft tool,

jactivex,
reads a type library and generates Java source files that contain special
compiler directives. The generated source files are part of a package named
after the type library you specified. The next step is to import that package
in your COM client Java source files.

Let’s


look at a couple of examples.


Advertisement

Developing
COM servers in Java

This


section shows the process you will apply to the development of ActiveX


Controls, Automation Servers, or any other COM-compliant server. The following


example implements a simple Automation server that adds integer numbers. You


set the value of the


addend

with the


setAddend( )

method, and each time you call the


sum( )

method the


addend

is added to the current


result

.


You retrieve the


result

with


getResult( )

and reset the values with


clear( )

.


The Java class that implements this behavior is straightforward:

public class Adder {
  private int addend;
  private int result;
  public void setAddend(int a) { addend = a; }
  public int getAddend() { return addend; }
  public int getResult() { return result; }
  public void sum() { result += addend;  }
  public void clear() {
    result = 0;
    addend = 0;
  }
}

To


use this Java class as a COM object, the


Javareg

tool is applied to the compiled


Adder.class

file. This tool has a number of options; in this case we specify the Java class


file name (“Adder”), the ProgID we want to put in the Registry for


this server (“JavaAdder.Adder.1”), and the name we want for the


type library that will be generated (”JavaAdder.tlb”). Since no


CLSID is given,


Javareg

will generate one; if we call


Javareg

again on the same server, the existing CLSID will be used.

javareg /register
/class:Adder /progid:JavaAdder.Adder.1
/typelib:JavaAdder.tlb
Javareg

also registers the new server in the Windows Registry. At this point, you must


remember to copy your


Adder.class

file into the WindowsJavatrustlib directory. For security reasons, related


mostly to the use of COM services by applets, your COM server will be activated


only if it is installed in the trustlib directory.

You


now have a new Automation server installed on your system. To test it, you need


an Automation controller, and “the” Automation Controller is

Visual
Basic (VB). Below, you can see a few lines of VB code. On the VB form, I put a
text box to input the value of the addend, a label to show the result, and two
push buttons to invoke the
sum( )
and
clear( )
methods. At the beginning, an object variable named
Adder
is declared. In the
Form_Load
subroutine, executed when the form is first displayed, a new instance of the
Adder
automation server is instantiated and the text fields on the form are
initialized. When the user presses the “Sum” or “Clear”
buttons, appropriate methods in the server are invoked.
Dim Adder As Object
 
Private Sub Form_Load()
    Set Adder = CreateObject("JavaAdder.Adder.1")
    Addend.Text = Adder.getAddend
    Result.Caption = Adder.getResult
End Sub
 
Private Sub SumBtn_Click()
    Adder.setAddend (Addend.Text)
    Adder.Sum
    Result.Caption = Adder.getResult
End Sub
 
Private Sub ClearBtn_Click()
    Adder.Clear
    Addend.Text = Adder.getAddend
    Result.Caption = Adder.getResult
End Sub

Note


that this code has no knowledge that the server was implemented in Java.

When


you run this program and the


CreateObject( )

function is called, the Windows Registry is searched for the specified ProgID.


Among the information related to the ProgID is the name of the Java class file,


so in response the Java Virtual Machine is started, and the Java object


instantiated inside the JVM. From then on, the JVM takes care of the


interaction between the client and server code.


Developing
COM clients in Java

Now


let’s jump to the other side and develop a COM client in Java. This


program will call services in a COM server that’s installed on your


system. The example is a client for the server we implemented in the previous


example. While the code will look familiar to a Java programmer, what happens


behind the scenes is quite unusual. This example uses a server that happens to


be written in Java but applies to any ActiveX Control, ActiveX Automation


server, or ActiveX component installed in your system for which you have a type


library.

First,


the


Jactivex

tool is applied to the server’s type library.


Jactivex

has a number of options and switches, but in its basic form it reads a type


library and generates Java source files, which it stores in your


windows/Java/trustlib

directory. In the example line below, it is applied to the type library that


was generated for out COM Automation server.

jactivex
/javatlb JavaAdder.tlb

If,


after


Jactivex

has finished, you take a look at your


windows/Java/trustlib

directory, you’ll find a new subdirectory called


javaadder

that contains the source files for a new package. This is the Java equivalent


of the type library. These files use compiler directives specific to the


Microsoft compiler: the


@com

directives. The reason


jactivex

generated more than one file is that COM uses more than one entity to describe


a COM server (and also because I did not fine-tune the use of MIDL files and


the Java/COM tools).

The


file named


Adder.java

is the equivalent of a


coclass

directive in a MIDL file: it’s the declaration of a COM class. The other


files are the Java equivalent of the COM interfaces exposed by the server.


These interfaces, such as


Adder_DispatchDefault.java

,


are dispatch interfaces, part of the mechanism of interaction between an


Automation controller and an Automation server. The Java/COM integration


feature also supports the implementation and use of dual interfaces. IDispatch


and dual interfaces are beyond the scope of this appendix.

Below,


you can see the client code. The first line just imports the package generated


by


jactivex

.


Then an instance of the COM Automation server is created and used, as if it was


an ordinary Java class. Notice the typecast on the line where the COM object is


instantiated. This is consistent with the COM object model. In COM, the


programmer never has a reference to the whole object; instead, the programmer


can only have references to one or more of the interfaces implemented in the


class.

Instantiating


a Java object of the Adder class tells COM to activate the server and to create


an instance of this COM object. But then we must specify which interface we


want to use, choosing among the ones implemented by the server. This is exactly


what the typecast does. The interface used here is the


default
dispatch interface

,


the standard interface that an Automation controller uses to communicate with


an Automation server (for details, see


Inside
COM

,


ibid.). Notice how simple it is to activate the server and select a COM


interface:

import javaadder.*;
 
public class JavaClient {
  public static void main(String [] args) {
    Adder_DispatchDefault iAdder =
         (Adder_DispatchDefault) new Adder();
    iAdder.setAddend(3);
    iAdder.sum();
    iAdder.sum();
    iAdder.sum();
    System.out.println(iAdder.getResult());
  }
}

Now


you can compile and run the code.


The
com.ms.com package

The


com.ms.com
package defines a number of classes for COM development. It supports the use of
GUIDs – the
Variant
and
SafeArray
Automation types – interfacing with ActiveX Controls at a deeper level
and handling COM exceptions.

I


cannot cover all of these topics here, but I want to point out something about


COM exceptions. By convention, virtually all COM functions return an HRESULT


value that tells you if the function invocation succeeded or not and why. But


if you look at the Java method signature in our server and client code, there


no HRESULT. Instead, we use the function return value to get data back from


some functions. The virtual machine is translating Java-style function calls


into COM-style function calls, even for the return parameter. But what happens


inside the virtual machine if one of the functions you call in the server fails


at the COM level? In this case, the JVM sees that the HRESULT value indicates a


failure and generates a native Java exception of class


com.ms.com.ComFailException

.


In this way, you can handle COM errors using Java exception handling instead of


checking function return values.

To


learn more about the classes in this package, please refer to the Microsoft


documentation.


Advertisement

ActiveX/Beans
integration

An


interesting result of Java/COM integration is the

ActiveX/Beans
integration, by which a Java Bean can be hosted by an ActiveX container such as
VB or any Microsoft Office product, and an ActiveX Control can be hosted by a
Beans container such as Sun’s BeanBox. The Microsoft JVM takes care of
the details. An ActiveX Control is just a COM server exposing predefined,
required interfaces. A Bean is just a Java class that is compliant with a
specific programming style. At the time this was written, however, the
integration was not perfect. For example, the virtual machine is not able to
map the JavaBeans event model to the COM event model. If you want to handle
events from a
Bean
inside an ActiveX container, the Bean must intercept system events such as
mouse actions via low-level techniques, not the standard JavaBeans delegation
event model.

Apart


from this, the ActiveX/Beans integration is extremely interesting. The concept


and tools are exactly the same as discussed above, so please consult


Microsoft’s documentation for more details.


A
note about native methods and applets

Native


methods face the security issue. When your Java code calls a native method, you


pass control outside of the virtual machine “sandbox.” The native


method has complete access to the operating system. Of course, this is exactly


what you want if you write native methods, but it is not acceptable for


applets, at least not implicitly. You don’t want an applet, downloaded


from a remote Internet server, to be free to play with the file system and


other critical areas of your machine unless you allow it to do so. To prevent


this situation with J/Direct, RNI, and COM integration, only trusted Java code


has permission to make native method calls. Different conditions must be met


depending on the feature the applet is trying to use. For example, an applet


that uses J/Direct must be digitally signed to indicate full trust. At the time


of this writing, not all of these security mechanisms are implemented (in the


Microsoft SDK for Java, beta 2), so keep an eye on the documentation as new


versions become available.


Contents

|

Prev

|

Next
CodeGuru Logo

CodeGuru covers topics related to Microsoft-related software development, mobile development, database management, and web application programming. In addition to tutorials and how-tos that teach programmers how to code in Microsoft-related languages and frameworks like C# and .Net, we also publish articles on software development tools, the latest in developer news, and advice for project managers. Cloud services such as Microsoft Azure and database options including SQL Server and MSSQL are also frequently covered.

Property of TechnologyAdvice. © 2026 TechnologyAdvice. All Rights Reserved

Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.