« Chris Foss tribute site | Main | Otto Frello »
July 12, 2004
JNI array parameter issues
According to Matthew Mead (author of the JNI port for Delphi), it is entirely possible that the helper function ArgsToJValues doesn't work correctly for some types and some JVMs. The solution is to use the JNI array handling functions. This article on starting a JVM from C shows how to do this from within C.
Here's some example Delphi code, with the relevant array handling bits in bold:
program JavaFromDelphi;
{$APPTYPE CONSOLE}
uses
SysUtils, JNI;
var
Options: array [0..4] of JavaVMOption;
VM_args: JavaVMInitArgs;
JavaVM: TJavaVM;
JNIEnv: TJNIEnv;
Cls: JClass;
Mid: JMethodID;
Errcode: Integer;
Obj: JObject;
DelphiIntArray: array [0..8] of Integer;
JavaIntArray: JIntArray;
Loop: Integer;
begin
try
// Create the JVM (using a wrapper class)
JavaVM := TJavaVM.Create;
// Set the options for the VM
Options[0].optionString := '-Djava.class.path=.';
Options[1].optionString := '-Xcheck:jni';
VM_args.version := JNI_VERSION_1_4;
VM_args.options := @Options;
VM_args.nOptions := 2;
// Load the VM
Errcode := JavaVM.LoadVM(VM_args);
if Errcode < 0 then
begin
WriteLn(Format('Error loading JavaVM, error code = %d', [Errcode]));
Exit;
end;
// Create a Java environment from the JVM's Env (another wrapper class)
JNIEnv := TJNIEnv.Create(JavaVM.Env);
// Create the Java array of integers
JavaIntArray := JNIEnv.NewIntArray(9);
// Quit if this fails
if JavaIntArray = nil then
begin
WriteLn('Can''t get int array');
Exit;
end;
// Fill the Delphi array with some values
for Loop:=0 to 8 do
begin
DelphiIntArray[Loop]:=(Loop*Loop);
end;
// Set the Java int array with the values in the Delphi int array
JNIEnv.SetIntArrayRegion(JavaIntArray,0,9,@DelphiIntArray);
// Find the class in the file system. This is why we added
// the current directory to the Java classpath above.
Cls := JNIEnv.FindClass('TestApp');
if Cls = nil then
begin
WriteLn('Can''t find class: TestApp');
Exit;
end;
// Get its default constructor
Mid := JNIEnv.GetMethodID(Cls, '', '()V');
if Mid = nil then
begin
WriteLn('Can''t get default constructor for class');
Exit;
end;
// Create the object
obj := JNIEnv.NewObjectA(Cls, Mid, nil);
// Fail if we can't
if Obj = nil then
begin
WriteLn('Can''t get get object');
Exit;
end;
// Get method
Mid := JNIEnv.GetMethodID(Cls, 'test', '([I)V');
if Mid = nil then
begin
WriteLn('Can''t find method: test');
Exit;
end;
// Finally, call the method with the Java int array ...
JNIEnv.CallObjectMethodA(obj, Mid, PJValue(@JavaIntArray));
except
on E : Exception do
WriteLn('Error: ' + E.Message);
end;
end.
The TestApp.java source is here:
public class TestApp
{
void test(int[] params)
{
System.out.println("params.length="+params.length);
for (int i=0; i<e;params.length; i++)
{
System.out.println("params["+i+"]="+params[i]);
}
}
}
Posted by daen at July 12, 2004 02:27 PM