Introduction to Jawin

Introduction

The Java/Win32 integration project (Jawin) is a free, open source architecture for interoperation between Java and components exposed through Microsoft's Component Object Model (COM) or through Win32 Dynamic Link Libraries (DLLs). The current version of Jawin is 2.0-alpha1, build 2005-03-23. The most recent version of this document is located at the Jawin home, kindly hosted by SourceForge.net.

You can use Jawin to interact with scriptable applications such as the Microsoft Office suite. You can use Jawin to call scriptable logic components such as Microsoft's COM-based XML parsers and tools. You can also use Jawin to access Win32 API features such as the Windows registry, security APIs, and the event log. You can also use Jawin to make in-process interoperability with .NET code exposed as COM objects. In fact, Jawin allows your Java applications to call any legacy COM- and DLL-based code, without having to write any Java Native Interface (JNI) code. Using Jawin, you can call any component that can be scripted in the Windows environment. You can also call arbitrary COM components or DLL entry points.

Jawin includes a code generator, Jawin Type Browser, supporting generation of stub code for scriptable as well as non-scriptable COM components. The code generator reads one or more type libraries, and automatically emits the Java stubs needed to call the component(s). The Jawin Type Browser is not (yet) able to generate code for DLL entry points, and not all parameter types are supported for COM components.

Jawin was initiated by Stuart Halloway and Justin Gehtland of Relevance LLC and is an offspring from Stuarts book Component Development for the Java Platform freely available as PDF from the DevelopMentor downloadable books page. Stuart also previously maintained a list of other Java/COM and Java/Win32 interoperability technologies and products (as of spring 2005, this page seems to be unavailable, but can be found at the Internet Archive).

This set of documentation should provide everything you need to get started using Jawin. It is recommended that new users at least reads this document and Generating stubs. For more than the simplest usages, it is also recommended to make oneself familar with the Jawin Architecture (especially the details about error handling and threading issues).

If you have any questions, please subscribe and post them to the Jawin mailing list.

License

Use of Jawin is subject to the following LICENSE. Jawin includes Konstantin Boukreevs C++ Exception Handling classes. See LICENSE-CPP-Exception for license and copyright details. The Jawin Type Browser includes software developed by the Apache Software Foundation, specifically Xerces and Xalan. See LICENSE-Apache for license and copyright details.

Content

  1. Why Jawin? (JNI Is Not Enough)
  2. Getting started with Jawin
    1. Loading Jawin native code
    2. Jawin demos
    3. Multithreaded applications
    4. Java Security
  3. Calling a Scriptable COM component
  4. Calling a COM component using generated stubs
  5. Calling a VTable based COM component
  6. Calling a DLL Entry Point
  7. In-process interoperability with .NET
  8. Troubleshooting Jawin
    1. Diagnostic Output
  9. Additional Resources

1. Why Jawin? (JNI is not enough)

The Java Native Interface (JNI) is a standard way to access native code from the Java platform. JNI provides a set of low-level primitives that can be used to marshal arguments from Java into native code, and vice versa.

Note the choice of the word "primitive". JNI is a very low- level approach to calling native code. Examine the code fragment below, which shows using JNI to access the registry. Only the code in bold is relevant. All the rest of the code is devoted to managing parameters and resources, and is totally irrelevant to the task at hand.

JNIEXPORT jint JNICALL Java_NTRegistry_getDword
(JNIEnv *pEnv, jclass cls, jint hive, jstring key, jstring name)
{
  unsigned long dw = -1;
  unsigned long size;
  HKEY hkey = NULL; jchar* psName = NULL;
  jchar* psKey = NULL;
  if (!getString(pEnv, key, &psKey)) goto fail;
  if (!getString(pEnv, name, &psName)) goto fail;
  if (ERROR_SUCCESS != ::RegOpenKeyW((HKEY)hive, psKey, &hkey)) goto fail;
  size = sizeof(dw);
  if (ERROR_SUCCESS == ::RegQueryValueExW(hkey, psName, NULL, NULL, 
                       (BYTE*) &dw, &size)) goto cleanup;

fail:
  cls = pEnv->FindClass("java/lang/IllegalArgumentException");
  if (cls) pEnv->ThrowNew(cls, "Could not read registry key");
cleanup:
  if (hkey) ::RegCloseKey(hkey);
  if (psKey) free (psKey);
  if (psName) free (psName);
  return dw;
}

This is not the intended use for JNI. JNI is best when it is used to build a higher level marshalling layer that provides a transparent, or near transparent, mapping between Java objects and objects on a particular native platform. In order to access the very large number of COM components and Win32 DLLs, several companies and open-source projects have leveraged JNI to create more developer-friendly, Win32-specific solutions.

Jawin is one such project. I built Jawin because I was dissatisfied with JNI as a mechanism for interop. JNI requires that you write custom native code each time you want to add a new capability. With Jawin, all the native code is in Jawin.dll, and no additional native code needs to be written.

2. Getting started with Jawin

Jawin requires JDK 1.3 or higher and can (of course) only be used on Windows machines with COM-support (all versions since Windows 95 has some kind of COM-support, although Windows 95 and NT 4, might require installation of DCOM to get decent COM-support).

To use Jawin in your project(s), download the newest binary relase from the Jawin repository at SourceForge.net. Unzip the release to a directory of your choice. This will give you 5 folders:

FolderContent
bin Containing the native Jawin code. You must make sure that this is loaded as described in the Loading Jawin native code-section below. The debug subfolder contains the native code compiled with debug information together with debug symbols.
demos Containing Jawin demos. See the Jawin demos-section below.
docs Containing an offline version of this documentation together with the Javadoc for Jawin.
lib Containing the jawin.jar file, which contains the core Jawin classes. This jar-file should be put on the classpath for your project.
Together with the core Jawin classes, some user-donated stubs are included in the jawin-stubs.jar file. Not all users will need this jar-file.
typebrowser Containing the Jawin Type Browser, used for generating stubs for Jawin. Please consult the documentation for the Jawin Type Browser for how to launch and use this tool.

2.1. Loading Jawin native code

When you use Jawin to access native code, you need only load the single Jawin library. No other native code is necessary. However, Jawin itself is a standard JNI library. The first challenge in using Jawin is making sure that the Jawin library is visible to your application. You can set the standard java.library.path property to point to the location of jawin.dll on your system:

java -Djava.library.path=c:/jawin/bin SomeMainClass

The java.library.path can be both a full path as in the example, or a path relative to the working dir. Note that the working dir itself is always on the library path. The default behavior of the Jawin loading code is to load a library with the name jawin.dll, this can be overridden by setting the org.jawin.lib-property (note that this must not contain the file prefix, eg. .dll) as follows:

java -Djava.library.path=c:/jawin/bin -Dorg.jawin.lib=AnotherJawinName SomeMainClass

Jawin also includes a special flag that you can use to specify the full path and name of the Jawin library. This form is usually used to load the debug version of the Jawin native code, like so:

java -Dorg.jawin.hardlib=c:/jawin/bin/debug/jawind.dll SomeMainClass

The debug version of Jawin is located at bin/debug/jawind.dll in your Jawin installation. The purpose of the debug build is to help troubleshoot problems inside Jawin. The debug version of Jawin contains debug symbols and may sometimes ASSERT before throwing a COMException back to Java. This is by design, so that you can jump into the debugger to see what caused the exception. You should never deploy the debug version of Jawin.

You can also access the Jawin library by adding it to your Windows system directory, or by running your application from the directory where the library is located. These methods may seem simpler, but they can cause configuration headaches later. The explicit command-line flags listed above are the preferred way to locate the Jawin native library.

2.2. Jawin demos

The demos-folder contains demo code, showing how to use Jawin. Together with this is a simple Ant file for compiling and running these demos. You will need Ant 1.5 or newer to use this buildfile. The following table gives an overview of the available demos:

Ant targetSource fileDescription
ppt demos/CreatePpt Creates a simple PowerPoint Presentation (is explained in Calling a Scriptable COM component below). Requires that MS PowerPoint is installed.
word demos/CreateWord Launches Word. Requires that MS Word is installed.
dll-hello demos/HelloDll Demonstrates how to call a DLL entry point, calling the Win32 MessageBoxW method. See Calling a DLL Entry Point below for further explaination.
dllgeneric-hello demos/HelloDllGeneric Demonstrates how to call a DLL entry point using the generic FuncPtr invoke method.
dllstub-hello demos/HelloDllStub The same example as dll-hello, except it uses a strongly typed stub as explained in Calling a DLL Entry Point below.
registry demos/DemoRegistry Demonstrates accessing some of the Win32 Registry APIs. Reads the Java Runtime Enviroment version from the registry, and add and delete a Jawin-key to the HKEY_LOCAL_MACHINE/SOFTWARE registry hive. Please note that this demo modifies the registry.
eventlog demos/DemoEventLog Demonstrates accessing some of the Win32 eventlog APIs. Reads a number of entries from the Application eventlog and adds a new entry. Please note that this demo modifies the eventlog.
security demos/DemoSecurityAPIs Demonstrates accessing some of the Win32 security APIs. Reads process and user information.
event-handler demos/DemoConsoleEventHandler Demonstrates setting a Win32 console handler from Java. It also demonstrates providing a Java implementation of a Win32 callback function.
logoff-handler demos/RunRMIRegistry Sets a Win32 console handler like the event-handler-demo. The console handler ignores logoff events, which could be valuable for long running daemons like the RMI-registry.
petzold demos/petzold/chap03/HelloJava A Jawin port of Petzold's Hello World example. Demonstrates how to create a window and process window messages (eg. it demonstrates providing a Java implementation of a Win32 callback function).
net-hello demos/HelloNET A example showing how to call a .NET object exposed as a COM object. To run this example you need some .NET requirements as well as to make some manual steps. Please see the section on In-process interoperability with .NET.

2.3. Multithreaded applications

If Jawin is to be used in a multithreaded environment, one unfortunately has to know some of the groovy details of COM-threading. The COM Threading-section of the Jawin Architecture document gives the basic information about how Jawin handles the COM-threading issues, and how the programmer should behave in a multithreaded environment.

2.4. Java Security

If your application is running in a JVM with a SecurityManager the jawin.jar needs to be assigned the loadLibrary.<somepath>/jawin.dll java.lang.RuntimePermission to make it able to load the native Jawin code.

More permissions may be necessary, since we haven't yet met a real-world-example where Jawin is used in context of a SecurityManager. So we would be pleased to hear about any experience with this on the Jawin mailing list.

3. Calling a Scriptable COM component

Probably the most common use of Jawin is to call a scriptable COM component. The code fragment below (this is the ppt-demo from the Jawin demos-section) demonstrates using Jawin to instantiate PowerPoint and build a very simple slide show.

import org.jawin.DispatchPtr;
import org.jawin.win32.Ole32;
 .
 .
try {
  Ole32.CoInitialize();
  DispatchPtr app = new DispatchPtr("PowerPoint.Application");
  app.put("Visible", true);
  DispatchPtr preses = (DispatchPtr)app.get("Presentations");
  DispatchPtr pres = (DispatchPtr) preses.invoke("add", new Integer(-1));
  DispatchPtr slides = (DispatchPtr)pres.get("Slides");
  DispatchPtr slide = (DispatchPtr) slides.invoke("Add", new Integer(1), new Integer(2));
  DispatchPtr shapes = (DispatchPtr)slide.get("Shapes");
  DispatchPtr shape = (DispatchPtr) shapes.invoke("Item", new Integer(1));
  DispatchPtr frame = (DispatchPtr)shape.get("TextFrame");
  DispatchPtr range = (DispatchPtr)frame.get("TextRange");
  range.put("Text", "Use Jawin to call COM objects");
  Ole32.CoUninitialize();
} catch (Exception e) {
  e.printStackTrace();
}

The calls to Ole32.CoInitialize and Ole32.CoUninitialize setup and tear down the COM libraries on the current thread. You must make these calls on any thread that will be calling COM objects. The first DispatchPtr is created directly, using the ProgId for the COM class you want to use (the name DispatchPtr comes from the fact that scriptable COM components implement the IDispatch interface). Subsequent DispatchPtr instances are created by calling methods and accessors, working down the object hierarchy to finally place some text on a slide.

The Userguide - Calling a Scriptable COM Interface document, elaborates on the exact rules for calling a scriptable COM component from Jawin.

This code has one noteworthy advantage: It is simple. Code written in this style requires no compile-time knowledge of the COM component you are calling. You could attempt to invoke, put, or get any name you want - the Java compiler will not care.

This simplicity can also be seen as a disadvantage. Because it uses no type information to describe PowerPoint, the compiler will not tell you if this code represents a valid set of method calls and property accesses. Instead of always using DispatchPtr, it would be nice to have actual Java classes named Application, Presentation, and Slide, etc., with specific methods that can be verified by the Java compiler.

Jawin's code generation feature can create these helper classes, which are called stubs.

4. Calling a COM component using generated stubs

The following code fragment is identical in effect to the code sample above, except it uses generated java classes as stubs for the dispatch interfaces in the type library.

<stub imports>;
import org.jawin.win32.Ole32;
 .
 .
try {
  Ole32.CoInitialize();
  _Application app = new _Application("PowerPoint.Application");
  app.put("Visible", true);
  Presentations preses = app.getPresentations();
  _Presentation pres = preses.Add(-1);
  Slides slides = pres.getSlides();
  _Slide slide = slides.Add(1,2);
  Shapes shapes = slide.getShapes();
  Shape shape = shapes.Item(new Integer(1));
  TextFrame frame = shape.getTextFrame();
  TextRange range = frame.getTextRange();
  range.setText("Jawin to call COM objects");
  Ole32.CoUninitialize();
} catch (Exception e) {
  e.printStackTrace();
}

When using the generated stubs, you must still call Ole32.CoInitialize and Ole32.CoUninitialize in order to bootstrap the COM libraries. However, this code has the notable advantage of being strongly typed. In addition to strongly typed references, the methods exposed by the stubs contain strongly typed parameter lists. Using the generated stubs, you get compile-time protection against type misuse.

Jawin also provides a mechanism for generating a second type of file: interfaces which represent any COM enums found in the type library. These interfaces scope a list of named constants inside a namespace which matches the enum name from the library. This allows the Java developers the same ability to avoid "magic number" programming as is afforded to COM programmers using VB or C++.

Jawin contains a stub generator called the Jawin Type Browser, please consult the documentation for this tool for how to generate stubs for Jawin.

5. Calling a VTable based COM component

Some COM interfaces are not scriptable (ie. they do not implement the IDispatch-COM-interface). The Jawin Type Browser are able to generate stubs for these as well (although the support are not quite as good as for dispatch based COM components). The type label for these vtable based COM interfaces in the Jawin Type Browser is Interface.

If the Jawin Type Browser is not able to generate complete stub-code for a vtable based COM interface, the guidelines in the Userguide - Calling a VTable Based COM Interface document should be followed for manually writing the stub-code.

6. Calling a DLL Entry Point

Jawin also supports calling traditional old style DLL entry points, but at this time the Jawin Type Browser does not include an automatic stub generator for DLL entry points. So if you need to need to do this for a common DLL (eg. the Win32 API functions), you should check whether any Java wrapping code exists in the donated-stubs library. The donated library exists in the lib/jawin-stubs.jar and javadoc for it exists in the folder docs/api-donated-stubs.

If the donated library does not contain any stubs for the requested DLL entry points, the Userguide - Calling a DLL Entry Point should be consulted for information about how to use Jawin to call a DLL entry point.

7. In-process interoperability with .NET

Besides the COM and Win32 interoperability, Jawin can also be used for in-process interoperability with the Microsoft .NET platform. This can be accomplished because the .NET development tools makes it possible to export .NET objects as COM-objects.

If in-process interoperability is not strictly needed, the recommended (and buzzword compatible) way to communicate between .NET and Java services is probably to use webservices. There should be plenty of resources around the Internet and in books, that explains webservices. One starting resource could be WS-I - the Web Services Interoperability Organization.

The Userguide - Interoperability with .NET Classes document contains a walk through the simple prof-of-concept net-hello demo.

8. Troubleshooting Jawin

If you are getting an UnsatisfiedLinkError when loading Jawin, read the Loading Jawin native code-section. If some stubs or data types cause exceptions, you may be able to track the problem using Jawin's Diagnostic Output.

8.1. Diagnostic Output

Jawin includes several auditing flags that can be used to emit diagnostic output, as described in the table below. The diagnostic output will be enabled if these flags are set to any value.

Flag nameDiagnostic output
org.jawin.traceRefs COM object reference counting
org.jawin.traceWin32 Win32 marshal packets
org.jawin.traceCom COM marshal packets
org.jawin.traceDispatch scriptable COM object marshal packets

9. Additional Resources

This introduction to Jawin assumes the reader is already somewhat familiar with COM, Win32, and Java. For COM platform basics see [Box98]. For Win32, see [Ric99]. For Java platform basics see [Hal01], especially the appendix on Jawin.

Jawin is one of a large number of open-source and commerical products that integrate Java with COM and Win32. For a list of alternatives, see the Java/Win32/COM interoperation product list maintained by Stuart Halloway (as of spring 2005, this page seems to be unavailable, but can be found at the Internet Archive).

Additional Jawin resources

Referenced books