Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs

Enhance your Java application with Java Native Interface (JNI)

How to compete with native applications without sacrificing cross-platform benefits

  • Print
  • Feedback

Page 5 of 7

The header file continues with prototypes of our entry point functions that are directly equivalent to the native Java methods:

extern "C" {
#endif
/*
 * Class:     DesktopIndicator
 * Method:    nativeDisable
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_DesktopIndicator_nativeDisable
  (JNIEnv *, jobject);


Although the functions assume C-calling conventions, the header files are C++-aware, and are easier to work with in C++, which, like Java, is an object-oriented member of the C family. We will use C++ for this example.

If required, you can develop your JNI library in languages other than C/C++, although you will have to do your own translation of entry points and arguments. In general, this is not recommended. You want your extension to be as small and independent as possible. Higher-level languages may require that various libraries be installed, which can complicate deployment considerably. Threading issues add even more difficulties.

Now that we have our prototypes to provide a skeleton, we need to fill in the meat. We'll be using Visual C++ 6.0 for this example, although any Win32 compiler with the system headers should work equally well. We will only be using Win32 API calls, and no features specific to Visual C++.

The meat

We'll start by creating an empty Win32 project and workspace, making sure that it has the JDK's include folder in its inclusion path. Because we want our application to work on Windows 95, we will use the ANSI (as opposed to Unicode) versions of Win32 calls. Fortunately, JNI has the facilities needed to do the transformations.

(We're going to jump into some advanced JNI work here, so I won't cover the basics. If you find yourself getting lost, please refer to the Resources section below for more information on JNI.)

Each DesktopIndicatorHandler instance will need its own invisible window that will receive events and send them up to the Java instance, which, in turn, will delegate to its listeners.

We must consider carefully how to handle threading in our library, so let's look at the Win32 event model. Messages are not sent directly to windows, but put on an event queue owned by a thread. The thread must occasionally check for messages on its queue, and choose to either deal with them or delegate them to other callbacks. Each class of windows owned by the thread has its own callback that handles events according to the class behavior.

Although we synchronized these methods in Java, and can be sure that no more than one thread will call us before we leave our callbacks, we are still being called in arbitrary threads, meaning that each call may come from a different context. We cannot be sure that the invisible windows created in these contexts will get messages, because we cannot be sure that these threads (which are owned by the VM process) check their Win32 message queues and delegate messages. In this case, in fact, they don't. Because of this, we will create our own thread, with our own message queue handling, and make sure all our windows are created within its context. It is simple to asynchronously delegate work to our worker thread by posting custom messages to its message queue.

  • Print
  • Feedback

Resources
  • JNI resources in JavaWorld: