Recommended: Sing it, brah! 5 fabulous songs for developers
JW's Top 5
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
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++.
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.