RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Converting Your Java App into a Windows Service : Page 2

Reusing a framework usually is a good idea, but sometimes developing your own code for a specific task is easier. Developing code to convert a Java application into a Windows service turns out to be one of those rare cases.

Mimicking Java.exe
Windows Task Manager will list all your Java applications as "Java" processes, so you have no way to identify an individual process. To assign specific names to your Java apps, you can mimic the Java runtime by using the JVM invocation API.

When you run java <your-class-name> on the command prompt, the java.exe in the system path loads several dynamically loadable libraries (DLLs). The following DLLs are of interest to this discussion:

  • Java\jdk1.6.0_01\jre\bin\client\jvm.dll—The Java JVM DLL that exposes the JVM invocation API. Once you create a JVM, jvm.dll in turn loads various support DLLs.
  • Java\jdk1.6.0_01\jre\bin\hpi.dll
  • Java\jdk1.6.0_01\jre\bin\verify.dll
  • Java\jdk1.6.0_01\jre\bin\java.dll
  • Java\jdk1.6.0_01\jre\bin\zip.dll

Here is how the java.exe processes the DLL:

  1. Loads the JVM DLL
  2. Creates a JVM
  3. Loads the class you specify
  4. Calls the main method that has the signature: public static void main (String[] args)

With the JNI_CreateJavaVM method defined in jni.h, you can create a JVM instance. You can find jni.h in the <JDK-install-folder>\include directory.

As an example, take a simple Java program based on the Visual Studio 2005 project HelloKNR (download it here), which says hello to Kernighan and Ritchie (KNR, for short):

package com.doorul;
public class HelloKNR {
    public static void main(String[] args) {
        System.out.println("Hello KNR!");

For simplicity, I have removed from the original HelloKNR project the parser code that deduces JVM options and command line parameters.

The following is the JNI code to mimic java.exe for the example program (download it here). Loading the jvm.dll dynamically instead of statically binding with jvm.lib enables the flexibility to choose the JVM version during deployment (see Listing 1):

int InvokeMain() {
	JavaVM *vm;
	JavaVMInitArgs vm_args;
	JavaVMOption options[1];
	jint res;
	JNIEnv *env;
	jclass cls;
	jmethodID mid;

	options[0].optionString = CLASS_PATH;
	vm_args.version = JNI_VERSION_1_4;
	vm_args.options = options;
	vm_args.nOptions = 1;
	vm_args.ignoreUnrecognized = JNI_FALSE;

	//load the JVM DLL
	HINSTANCE handle = LoadLibrary(RUNTIME_DLL);
	if( handle == 0) {
		printf("Failed to load jvm dll %s\n",
		return -1;
	//get the function pointer to JNI_CreateJVM
	createJVM = (CreateJavaVM)GetProcAddress(handle,

	res = createJVM(&vm, (void **)&env, &vm_args);
	if (res < 0)  {
		printf("Error creating JVM");
		return -1;

	//locate the class
	cls = env->FindClass(CLASS_NAME);
	if(cls == 0) {
		printf("Exception in thread \"main\"
			java.lang.NoClassDefFoundError: %s\n",
		return -1;
	//get the method id of main
	mid = env->GetStaticMethodID(cls, "main",
	if(mid == 0) {
		printf("Exception in thread \"main\"
			java.lang.NoSuchMethodError: main\n");
		return -1;

	//invoke the main method with no parameters
	env->CallStaticVoidMethod(cls, mid, 0);
	//if there is any exception, print the exception
	if(env->ExceptionCheck()) {
		return -1;
	return 0;

While loading the class com.doorul.HelloKNR, you have to use the "/" delimiter (i.e., com/doorul/HelloKNR). Also you need to understand the JNI signature format for invoking Java methods. For example, to call the void main(String[] args) method, the signature format is ([Ljava/lang/String;)V: "[" means array; "L<classname>;" represents a Java object; and V denotes that the method returns void. You can get more details from the JNI specification web site.

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date