Delphi-JNI-Java integration example


Downloads
Updated JNI.pas file
SimpleDemo.zip example
screenshot.zip example

official JNI.pas home page
JavaToDPR tool

Links
JNI specs
CodeGuru JNI tips
Turbo Delphi IDE

Java Native Interface is a standard programming interface for writing Java native methods. It is known to be a gray area not so many do and is perfectly fine not to develop .dll/.so libraries. After all, it's just one line away from the JVM crash if not done properly.

Most JNI developers use C/C++ environment, Sun releases header files only in C format. But Delphi (Object Pascal) has a very active community and JNI headers have been ported for us. Delphi JNI.pas home page hosts an excellent examples and JNI.pas file.

Use JavaToDPR tool to create MyDelphi.dpr project file from .java source code. It creates all necessary function declarations from native tagged java functions. It simplifies .dll process to automate tedious mandatory JNI function naming convention.

Enhanced JNI.pas
Updated JNI.pas file
Changes are very simple and does not modify anything from the earlier versions.

Enhanced version is not found from the official JNI.pas home page. I have contacted the owner of the version to discuss whether he sees any interest to update the official version.

Java has no problems using unicode strings because the internal format is unicode already. This is not so easy in native side where you have a choice of several string types. Old legacy string is ansistring and unicode-aware is widestring variable type. If you want to send strings back and fort you should keep values in widestring variable. Knowing characters are within the range of system-default encoding you may use ansistring. But doing things right at the year +2006, you should stick to widestring variables.

SimpleDemo example
SimpleDemo.zip example (uses enhanced JNI.pas)
My goal was a short and simple Delphi study.

Final conclusion is.....it's not anything magic or too complicated.

Test program calls several native functions and print results to UTF-8 formatted html file. Web browsers have a good unicode support, so character results can be see easily. Verify SimpleDemo.png image what you should see in SimpleDemo.html page generated by test program.

You need a good unicode font, some Windows has "Arial Unicode MS" which usually works fine. Its installed by some MS software (MSOffice, ...).

See more info in SimpleDemo.zip/readme.txt file about how to compile project.

ScreenShot example
screenshot.zip example (uses enhanced JNI.pas)
Use native code to take a screenshot from the desktop. Code is able to "see" alphablended windows unlike Java Robot sceenshot method. Example introduces the following technique.

Turbo Delphi
Turbo Delphi IDE
Turbo Delphi is a new release from Borland Delphi. Now you can get one of the best win32 development tool reasonable price....or even free of charge. Turbo Delphi Professional version provides a cutting edge version.
The free Turbo Delphi Explorer edition lets beginners and hobbyists learn win32 programming. But you can install only one Explorer version to the same machine, so be sure to take your favourite version. This page goes for Delphi release of course.


SimpleDemo example: Java and Delphi code
Java class has one or more native method declarations, that are implemented in .dll library. Java program may use functions just like any other pure Java functions.

You need three files in this example:
SimpleDemo.java, SimpleDemo.dpr, uSimpleDemo.pas

file: SimpleDemo.java
public class SimpleDemo {

  public static void main(String[] args) throws Exception {
    // call native Delphi method from Java
    SimpleDemo sd = new SimpleDemo();
    System.out.println( sd.getStringDelphiJ("Hello from Java") );
  }

  // declare native functions
  native public String getStringDelphiJ(String s);

  // load .dll library at startup
  static {
    System.loadLibrary("SimpleDemo");
  }
}

Native Delphi side few extra jumps to implement functions. Use JavaToDPR tool to create .dpr project file with all necessary function declarations, then implement function skeletons. Java uses unicode for internal strings, so you should convert string function arguments and/or function return values to WideString. If you don't, use risk losing 100% international aware programming. This example uses a helper methods to convert back and fort java strings and native widestrings.
file: SimpleDemo.dpr
library SimpleDemo;

// import JNI.pas file
uses
  SysUtils,
  uSimpleDemo in 'uSimpleDemo.pas',
  JNI in '..\..\JNI\JNI.pas';

{$R *.res}

function Java_SimpleDemo_getStringDelphiJ
  (PEnv: PJNIEnv; Obj: JObject; Arg1: JString): JString; stdcall;
begin
   // - convert JNI-JString to Widestring (unicode)
   // - call uSimpleDemo.getStringDelphiJ(s: Widestring) method
   // - convert widestring to JNI-JString
   // - return JNI-String back to java program
   // try-catch all exceptions and wrap it to
   // to java.lang.Exception
   try
      Result := JNI_WideStringToJString(PEnv,
         uSimpleDemo.getStringDelphiJ(
            JNI_JStringToWideString(PEnv, Arg1)
         )
      );
   except
      on E: Exception do begin
         Result := nil;
         JNI_ThrowException(PEnv, E);
      end;
   end;
end;

exports
  // export public JNI .dll functions
  Java_SimpleDemo_getStringDelphiJ;

end.

It's a good practice to write implementations to another unit file, and keep just necessary JNI interface stuff in SimpleDemo.dpr project file.
file: uSimpleDemo.pas
unit uSimpleDemo; interface // declare public functions function getStringDelphiJ(ws: WideString): WideString; forward; implementation uses SysUtils; // implement function function getStringDelphiJ(ws: WideString): WideString; var ws2: WideString; begin ws2 := WideUpperCase(ws); Result := 'Uppercased in dll: ' + ws2 + ' (len ' + IntToStr(Length(ws2)) + ')'; end; end.


Last update 2006-09-12 20:40