Information for this writeup came from the following sources:
Using COM Objects from Java by Chad Verbowski
Integrating Java and COM by Chad Verbowski
The On-Line Help Documentation in the Microsoft SDK for Java 3.1
Section Links
Back to Section Introduction
References and Links
Introduction:
Thanks to the Microsoft Virtual Machine and the Micosoft SDK for Java we now have the ability to turn Java objects into COM objects, and represent COM objects written in other languages like C, C++ or Visual Basic as Java classes that can be used in Java applications and applets. This allows Java programmers to utilize Microsoft resources and other 3rd party resources not written in Java with their applications. This section will focus on:
Representing Java objects as COM objects
Representing COM objects as Java objects
Using JDirect to call system functions or user defined functions in DLL's
Representing Java objects as COM objects:
To represent a Java object as a COM object - The virtual machine creates a COM wrapper for the class, referred to as a CCW(COM Callable Wrapper). This CCW can be used in other Microsoft programs as on object. This provides a very powerful intergration of Java objects with applications like: Internet Explorer, Microsoft Excel, Word, and Powerpoint, ActiveX controls, etc. Basically any program that supports OLE automation.
This CCW is really a COM object. This generic object has a vtable(virtual function table) that contains the 3 functions of the IUnknown interface:
QueryInterface
AddRef
Release
The CCW that wraps the Java object will contain these functions, and then any additional functions defined in the Java class/interface are added to the vtable after the 3 functions from IUnknown.
The CCW contains other interfaces besides IUnknown, and the VM provides default implementations for them. The interfaces are:
IDispatch
IDispatchEx
IProvideClassInfo
IProvideClassInfo2
ISupportErrorInfo
IMarshal
IConnectionPointContainer
IExternalConnection
The user can override the implmentation of any interface except for the following:
IUnknown
IExternalConnection
ISupportErrorInfo
Representing COM objects as Java objects:
A COM object can be represented as Java classes and interfaces so that it can be used directly in Java applications and applets. The COM object is exposed to the VM through a JCW(Java Callable Wrapper). This JCW contains information(like clsid) about the COM object that the corresponding Java class/interface maps to.
We can make JCW's for any COM object using the JActiveX tool provided with the Microsoft SDK for Java 3.1. This is exactly how the Java representations of the COM objects used in example 1 and example 2 were created. The tool takes the .tbl file assocated with the COM object and creates the JCW. The .tbl file is a binary file that defines the object, the interfaces that it implements and the methods in those interfaces. A sample JCW is below:
package theserver;
import com.ms.com.*;
import com.ms.com.IUnknown;
import com.ms.com.Variant;
// Dual interface IMySinkID
/** @com.interface(iid=81323871-BCBA-11D2-8902-000000000000, thread=AUTO, type=DUAL) */
public interface IMySinkID extends IUnknown
{
/** @com.method(vtoffset=4, dispid=1610743808, type=METHOD, name="RecieveNewData")
@com.parameters([in,type=I4] lNewValue) */
public void RecieveNewData(int lNewValue);
public static final com.ms.com._Guid iid = new com.ms.com._Guid((int)0x81323871, (short)0xbcba, (short)0x11d2,
(byte)0x89, (byte)0x2, (byte)0x0, (byte)0x0, (byte)0x0, (byte)0x0, (byte)0x0, (byte)0x0);
}
Directives are included in the JCW to identify it to the compiler and the VM. Since they are in the comments, only compilers and VM's that understand the directives will utilize them. This is the main point of contention in the Sun lawsuit against Microsoft(See below for more info). Some of the most common directives are below:
@com.class - The Java class represents a COM coclass
@com.interface - The Java interface represents a COM interface
@com.method - The Java methods represents a COM method defined in the interface or coclass
@com.parameters - Here we specify IN, OUT and retvalues, plus if we are using custom marshalling, it is noted in this directive
When we create an instance of the JCW in our Java program, The VM automatically creates an instance of the corresponding COM object either by calling CoCreateInstance if the object does not already exist, or QueryInterface and AddRef on the existing object. The VM handles all mapping between the COM object and the JCW. It is important to note that even though we call the new operator on the COM coclass JCW for the object, we must cast the resulting reference to be of type defined by the JCW for the interface. We are not allowed to call any of the methods through the coclass JCW, instead they must be called through the interface JCW.
Marshalling
The Microsoft VM provides marshalling between the native COM types like BSTR, int, and so on, to the corresponding Java types. You can provide your own marshalling code instead. This is required if you want to pass types other then the standard types. You must tell the VM to use you custom marshalling class instead.
Using J/Direct to access Library Functions from Java Programs
J/Direct is a method for access functions in DLL's in your Java applets and applications. Let's start with an example:
Example
Suppose you want to call the Win32API for copying a file. The function is: bool CopyFile(LPCTSTR fileToCopy, LPCTSTR newFileName, bool failIfNotExist). This function is in the library kernel32.dll. To use this function in your Java class, you would need to declare it with a @dll.import directive, it would look like this:
/** @dll.import("KERNEL32") */
public native static boolean CopyFile(String fileToCopy, String newFileName, boolean failIfNotExist)
The compiler regonizes the @dll.import directive. The VM will load the appropriate library(in this case Kernel32.dll) and call the procedure CopyFile in that library. The Vm also handles the Marshalling of the parameters and return types, but once again you can implement you own marshalling if you desire.
@dll.import is specified differently, depending on what kind of dll to load and how we specify the function we are calling. This is summarized below:
Call Win32 dll's - /** @dll.import("Library Name") */
Call OLE API's - /** @dll.import("Library Name, ole) */
By alias - /** @dll.import("Library Name, entryPoint="dllFunctionName") */
By ordinal - /** @dll.import("Library Name, ordinal="#ordinal") */
If you want to use dll's other than the Win32, OLE or system dll's, they must be in the directory that the Virtual Machine is launched from, in a directory in the Path environment variable or in the TrustedLibDirectory. You can set the TrustedLibDirectory in the registry, it's found at the following location: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Java VM.
The Java VM will take care of Loading and Linking the Library if you use the @dll.import directive, but what if you don't want to use that or don't know which function you will use until runtime? You can use the functions LoadLibrary, FreeLibrary and GetProcAddress. These are in the Kernel32 dll, to use them, include the package com.ms.Win32. You can control the entire process.
Security
A class that wants to call library functions using J/Direct or use COM objects must be fully trusted. There are 3 ways in which a class can be trusted:
It is on the trusted classpath for the virtual machine
It has been digitally signed - for Applets
It's running as part of a Java Application, outside of the browser
In the case of library functions security is checked at the following times:
When the Library is loaded
When the Library is linked
Before every invocation of the method
Sun v Microsoft - The Lawsuits
The technology described here is at the heart of the lawsuit between Sun and Microsoft. Sun maintains that the extensions that Microsoft added for COM support are not part of the standard Java language specification, therfore Microsoft can't say it's Java. I have provided links to each company's position below.
Sun's position
Microsoft's position