calling from a .dll using Java and JNI

By: Luke Dickman

Abstract: Basic JNI example: making a Win32 API call

Making Native Windows API calls from within a Java Application
 

One of the main points of Java is to be completely platform independent.  However, sometimes it will occur that the developer of an application will know that his or her application is only going to be run on a specific platform, for example, Win32.

NOTE:  This example assumes that you are using JDK 1.2 or later.

Below are the steps for writing a Java application that makes a Win32 API call.  The application generates a Swing Jframe and makes it system modal, or gives it the Always On Top functionality, similar to that of the Windows NT Task Manager.
-----

Steps to follow:

1.  Write the Java code for the application

2. Run javah.exe on your .class file to generate a C header file

3. write the implementation of your native methods

4. create the shared library

5. run the application
-----
 

1.  Write the Java code for the application
 
 

import java.awt.*;
import sun.awt.*;
import sun.awt.windows.*;
import javax.swing.*;
import java.awt.event.*;
 

public class Frame1 extends JFrame {

  int windowHWND = 0;
  JButton jButton1 = new JButton();

  public Frame1() {

    //windowHWND = this.getHwnd();
    try  {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }

 

  }
 

  public int getHwnd() {

  DrawingSurfaceInfo w = (DrawingSurfaceInfo) ((DrawingSurface) getPeer()).getDrawingSurfaceInfo();
  w.lock();
  WDrawingSurfaceInfo win32 = (WDrawingSurfaceInfo) w;
  int hwnd = win32.getHWnd();
  w.unlock();

  return hwnd;

  }

    static {
      System.loadLibrary("windowOnTop");
    }

  public static native void WindowAlwaysOnTop(int hwnd, boolean flag);
 
 
 

  public static void main(String[] args) {
    Frame1 frame11 = new Frame1();

    frame11.setSize(400,400);

    frame11.setVisible(true);

  }

  private void jbInit() throws Exception {

 
    jButton1.setText("jButton1");
 

    this.addWindowListener(new java.awt.event.WindowAdapter() {

      public void windowOpened(WindowEvent e) {
        this_windowOpened(e);
      }

      public void windowClosing(WindowEvent e) {
        this_windowClosing(e);
      }
    });
    this.getContentPane().add(jButton1, BorderLayout.NORTH);
  }

 
 

  void this_windowOpened(WindowEvent e) {

     windowHWND = this.getHwnd();
     System.out.println("the value is: " + this.getHwnd());
     this.WindowAlwaysOnTop(windowHWND, true);
 
  }
 
 

  void this_windowClosing(WindowEvent e) {

    System.exit(0);

  }
 

}


Once the code is written, compile it with Jbuilder or the command line javac.exe tool which will result in a generated .class file.  You will use this .class file in the next step.
-----
 

2. Run javah.exe on your .class file to generate a C header file

The following line represents the basic syntax for running javah.exe:

javah Frame1

where Frame1 is the name of the argument class.

When you run javah.exe, it will generate a header file by the same name as your implementation but with a .h file extension.  For this example the .h file that was generated from the above Java code will be emitted being that it is quite large.

NOTE:  Make sure that when you run javah.exe, it is the javah.exe that came with the same JDK that you will be compiling with as there may be some issues with using a version of javah.exe that is different from that of the JDK you are using to compile.
-----
 

3. write the implementation of your native methods

Now that you have your Java source and your C header file, it is time to write the implementation of your native methods.

Following is the C code that corresponds to the native methods declared in the Java code listed in step 1:

#include "jni.h"
#include "Frame1.h"
#include <stdio.h>
#include<windows.h>

JNIEXPORT void JNICALL Java_Frame1_WindowAlwaysOnTop(JNIEnv *env, jclass obj, jint hwnd, jboolean flag)
{
 if (flag)
  SetWindowPos((HWND) hwnd,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);
 else
  SetWindowPos((HWND) hwnd,HWND_NOTOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);

 return;
}

You will notice several things: one is that the function signature has Java_Frame1_ preceeding the name of the function.  If there was a package statement in the Java source, it would appear after Frame1_ in the function signature.

Second, you will notice the #include jni.h.  Normally this would be #include<jni.h>, depending on how you have your libraries set up within your C compiler.
-----
 

4. create the shared library

Now you are ready to create the shared library.  Using your C compiler, create a .dll file with the code from the C implementation file.  Refer to the doccumentation of the C compiler for details on creating a .dll file.

---------------------------------------------------------------------
For those interested in using Borland C++ Builder:

If you have got it installed, you could use Borland C++ Builder 3 or C++ Builder 4 to create your DLL file.  If this is the case, you would use File | New... | DLL  C++ Builder will then generate some code for you, and you will just need to add your implementation code to the code which was generated.
---------------------------------------------------------------------

Remember in the Java code in step one there is a line:

static {
       System.loadLibrary("windowOnTop");
         }

windowOnTop is the name of the .dll file.  You can name it whatever you want, just make sure that you specify the appropriate name when loading the library.
-----
 

5. run the application

Finally you are ready to run the application.  From the command line use java.exe and as the argument specify the name of the class that you compiled in step one.  Once the system loads your DLL, the window that the VM creates should mimic the Always On Top functionality.
-----


Server Response from: ETNASC03