(****************************************************************************
*
* Native.dpr
*
* This file implements the native routines declared in Native.java. The
* code is commented and fairly straight-forward. Note that there is
* almost no error checking in this code, however, a few functions do
* implement some error checks as a way of demonstrating how and where
* to check.
*
* This code was a port from Native.cpp, a C++ implementation, also
* developed by Matthew Mead.
*
* HISTORY
* 7-22-2000 Created.
* 10-14-2000 Modified to reflect JEDI standard of coding.
* 3-17-2002 Modified Java_Native_pass2DByteArray and
* Java_Native_initializeByteArray to call
* ReleaseByteArrayElements. This was causing the function
* to fail with J2SDK 1.4.0. The function was always incorrect
* but this wasn't apparent under older versions of the JRE.
*
*
*)
library Native;
uses
{$IFDEF WIN32}
Windows,
{$ENDIF}
SysUtils,
JNI;
(****************************************************************************
* Java declaration:
* native public void displayHelloWorld();
*
* The canonical first method.
*
* Class: Native
* Method: displayHelloWorld
* Signature: ()V
*)
procedure Java_Native_displayHelloWorld(PEnv: PJNIEnv; Obj: JObject); {$IFDEF WIN32} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
begin
Writeln('Hello world!');
end;
(****************************************************************************
* Java declaration:
* native public void initializeByteArray(byte[] byteArray, int count, byte value);
*
* Initializes an array 'Count' times with the Value 'Value'. This function
* is mainly used to test the performance of array accesses in native code.
*
* Class: Native
* Method: initializeByteArray
* Signature: ([BIB)V
*)
procedure Java_Native_initializeByteArray(PEnv: PJNIEnv; Obj: JObject; ByteArray: JByteArray; Count: JInt; Value: JByte); {$IFDEF WIN32} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF} overload;
var
Elements: PJByte;
PE: PJByte;
Len: JSize;
I, J: Longint;
IsCopy: JBoolean;
JVM: TJNIEnv;
begin
// Create an instance of the Java environment
JVM := TJNIEnv.Create(PEnv);
// Get elements of the array
Elements := JVM.GetByteArrayElements(ByteArray, IsCopy);
// Get length of the array
Len := JVM.GetArrayLength(ByteArray);
// Loop through the array 'Count' times, assigning 'Value' to each
// element.
for I := 0 to Count - 1 do
begin
PE := Elements;
for J := 0 to Len - 1 do
begin
PE^ := Value;
Inc(PE);
end;
end;
// Important! From Sun's documentation:
// Since the returned array may be a copy of the Java array, changes made
// to the returned array will not necessarily be reflected in the original
// array until Release<PrimitiveType>ArrayElements() is called.
JVM.ReleaseByteArrayElements(ByteArray, Elements, 0);
end;
(****************************************************************************
* Java declaration:
* native public String printLine(String text);
*
* Prints a Java string, and returns a Java string
*
* Class: Native
* Method: printLine
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*)
function Java_Native_printLine(PEnv: PJNIEnv; Obj: JObject; Value: JString): JString; {$IFDEF WIN32} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
var
Str: string;
JVM: TJNIEnv;
begin
// Create an instance of the Java environment
JVM := TJNIEnv.Create(PEnv);
// Convert the JString into a string
Str := JVM.JStringToString(Value);
// Print the string to the screen
Writeln('In Native code, string is: ', Str);
// Create a new string and return it
Result := JVM.NewStringUTF('String from Native code');
JVM.Free;
end;
(****************************************************************************
* Java declaration:
* native public void printWXYZ();
*
* Prints out four members of the Native object, w, x, y, and z. This
* function acts sort of like the traditional 'toString' method in Java.
* The members are declared in Native.java as such:
*
* public String w; // public Object
* public int x; // public
* private int y; // private (no protection here)
* public static int z; // public static
*
* The return Value from each GetFieldID call should be checked.
* I don't check because I'm trying to keep the focus on the calls.
*
* Class: Native
* Method: printWXYZ
* Signature: ()V
*)
procedure Java_Native_printWXYZ(PEnv: PJNIEnv; Obj: JObject); {$IFDEF WIN32} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
var
X, Y, Z: JInt;
W: JString;
FID: JFieldID;
Cls: JClass;
Str: string;
JVM: TJNIEnv;
begin
// Create an instance of the Java environment
JVM := TJNIEnv.Create(PEnv);
// Get the class associated with this object
Cls := JVM.GetObjectClass(Obj);
// w is a String
FID := JVM.GetFieldID(Cls, 'w', 'Ljava/lang/String;');
// Get the Object (String) w.
W := JVM.GetObjectField(Obj, FID);
// x is a non-static public field
FID := JVM.GetFieldID(Cls, 'x', 'I');
// Get the int
X := JVM.GetIntField(Obj, FID);
// y is a non-static private field, same as public here
FID := JVM.GetFieldID(Cls, 'y', 'I');
// Get the int
Y := JVM.GetIntField(Obj, FID);
// z is a _static_ public field, so call different method
FID := JVM.GetStaticFieldID(Cls, 'z', 'I');
// Get static int
Z := JVM.GetStaticIntField(Cls, FID);
// Convert Java string into Delphi string
Str := JVM.JStringToString(W);
// Sort of like the traditional 'toString' output
Writeln(Format('[w = %s, x = %d, y = %d, z = %d]', [Str, X, Y, Z]));
JVM.Free;
end;
{***********************************
Same as above but without the wrapper.
procedure Java_Native_printWXYZ(PEnv: PJNIEnv; Obj: JObject);
X, Y, Z: JInt;
W: JString;
FID: JFieldID;
Cls: JClass;
Str: string;
IsCopy: JBoolean; // added for GetStringChars
Chars: PJChar; // added for GetStringChars
begin
// Get the class associated with this object
Cls := PEnv^.GetObjectClass(PEnv, Obj);
// w is a String
FID := PEnv^.GetFieldID(PEnv, Cls, 'w', 'Ljava/lang/String;');
// Get the Object (String) w.
W := PEnv^.GetObjectField(PEnv, Obj, FID);
// x is a non-static public field
FID := PEnv^.GetFieldID(PEnv, Cls, 'x', 'I');
// Get the int
X := PEnv^.GetIntField(PEnv, Obj, FID);
// y is a non-static private field, same as public here
FID := PEnv^.GetFieldID(PEnv, Cls, 'y', 'I');
// Get the int
Y := PEnv^.GetIntField(PEnv, Obj, FID);
// z is a _static_ public field, so call different method
FID := PEnv^.GetStaticFieldID(PEnv, Cls, 'z', 'I');
// Get static int
Z := PEnv^.GetStaticIntField(PEnv, Cls, FID);
// Convert Java string into Delphi string
Chars := PEnv^.GetStringChars(PEnv, W, IsCopy);
Str := string(Chars);
PEnv^.ReleaseStringChars(PEnv, W, Chars);
// Sort of like the traditional 'toString' output
Writeln(Format('[w = %s, x = %d, y = %d, z = %d]', [Str, X, Y, Z]));
end;
}
(****************************************************************************
* Java declaration:
* native public String toStringWithPrint();
*
* This is the traditional 'toString' method with a twist. It calls back
* into Java to do the real work. There is a Native method called toString
* which formats the object's members for printing. This function simply
* calls it.
*
* The net effect is this: The Java object calls a native method which,
* in turn, calls back to the Java object. The Java could have simply
* made a call to it's own 'toString' method. This of course is for
* demonstration purposes only. Don't do this at work!!
*
* Class: Native
* Method: toStringWithPrint
* Signature: ()Ljava/lang/String;
*)
function Java_Native_toStringWithPrint(PEnv: PJNIEnv; Obj: JObject): JString; {$IFDEF WIN32} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
var
Cls: JClass;
Mid: JMethodID;
S: JString;
Str: string;
JVM: TJNIEnv;
begin
// Create an instance of the Java environment
JVM := TJNIEnv.Create(PEnv);
// This just simply tests the non-existence of ExceptionCheck in JDK 1.1
// Not used in this example for any "real" purpose.
{ TODO: Move this into a separate function }
try
JVM.ExceptionCheck;
except
on e: EJNIUnsupportedMethodError do
Writeln(e.Message);
end;
// Get the class associated with this object
Cls := JVM.GetObjectClass(Obj);
// Get the ID for its 'String toString()' method
Mid := JVM.GetMethodID(Cls, 'toString', '()Ljava/lang/String;');
// Call the method, which returns a String
S := JVM.CallObjectMethodA(Obj, Mid, nil);
// Convert the JString to a string and print it to the screen
Str := JVM.JStringToString(S);
Writeln(str);
// Create a JString and return it
Result := JVM.NewStringUTF(PAnsiChar(Str));
JVM.Free;
end;
(****************************************************************************
* Java declaration:
* native public void printObjectArray(Object[] array);
*
* Given an array of Objects, each element is printed using the
* 'toString' method of the Object.
*
* Class: Native
* Method: printObjectArray
* Signature: ([Ljava/lang/Object;Z)V
*)
procedure Java_Native_printObjectArray(PEnv: PJNIEnv; Obj: JObject; ObjArray: JObjectArray; Print: JBoolean); {$IFDEF WIN32} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
var
Cls: JClass;
Mid: JMethodID;
Ob: JObject;
Element: JObject;
S: JString;
Str: string;
Len, I: Integer;
JVM: TJNIEnv;
begin
// Create an instance of the Java environment
JVM := TJNIEnv.Create(PEnv);
// Get length of the array
len := JVM.GetArrayLength(ObjArray);
// Make sure we have at least one object in the array
if Len < 1 then
exit;
// Get an element of the array so we can get the right 'toString' method
Ob := JVM.GetObjectArrayElement(ObjArray, 0);
// Get the class associated with this object
Cls := JVM.GetObjectClass(Ob);
if Cls = nil then
begin
Writeln('Can''t GetObjectClass');
exit;
end;
// Get method ID for the 'toString' method of this object's class
Mid := JVM.GetMethodID(Cls, 'toString', '()Ljava/lang/String;');
// We will check this also
if Mid = nil then
begin
Writeln('Can''t GetMethodID for toString');
exit;
end;
// Loop the the array of objects and print out each one using
// the 'toString' method of its ancestor class Object
for I := 0 to Len - 1 do
begin
// Get the next element from the array
Element := JVM.GetObjectArrayElement(ObjArray, i);
// Call the 'toString' method, which returns a String representation
// of Rectangle object.
S := JVM.CallObjectMethodA(Element, Mid, nil);
// The actual printing can be turned on/off. This was useful during
// debugging when passing thousands of elements into the procedure.
if Print <> False then
begin
Str := JVM.JStringToString(S);
Writeln(Str);
end;
end;
JVM.Free;
end;
(****************************************************************************
* Java declaration:
* native public jobjectarray returnRectArray(int size);
*
* This function creates an array of 'size' Rectangles and returns them
* to the Java caller. First, the array is created, then each element
* is assigned a Rectangle object.
*
* Class: Native
* Method: returnRectArray
* Signature: (I)[Ljava/awt/Rectangle;
*)
function Java_Native_returnRectArray(PEnv: PJNIEnv; Obj: JObject; Size: JInt): JObjectArray; {$IFDEF WIN32} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
var
Cls: JClass;
Mid: JMethodID;
Element: JObject;
JOArray: JObjectArray;
I: Integer;
Args: array[0..3] of JValue;
JVM: TJNIEnv;
begin
// Create an instance of the Java environment
JVM := TJNIEnv.Create(PEnv);
// Find the Rectangle class
Cls := JVM.FindClass('java/awt/Rectangle');
if Cls = nil then
begin
Writeln('Can''t FindClass(java/awt/Rectangle');
Result := nil;
exit;
end;
// Get its constructor (the one that takes 4 integers)
Mid := JVM.GetMethodID(Cls, '<init>', '(IIII)V');
if Mid = nil then
begin
Writeln('Can''t get MethodID for Rectangle constructor');
Result := nil;
exit;
end;
// Allocate the array of Rectangles
JOArray := JVM.NewObjectArray(Size, Cls, nil);
// Now initialize each one to a Rectangle
for I := 0 to Size - 1 do
begin
// Create a new Rectangle object
Args[0].i := 0;
Args[1].i := 0;
Args[2].i := 5 * I;
Args[3].i := 10 * I;
Element := JVM.NewObjectA(Cls, Mid, @args);
// Assign the Rectangle to an element of the array
JVM.SetObjectArrayElement(JOArray, I, Element);
end;
// Return the array back to the Java client
Result := JOArray;
JVM.Free;
end;
(****************************************************************************
* Java declaration:
* native public void handleException();
*
* Causes an exception in the JVM, but detects it and supresses it
*
* Class: Native
* Method: handleException
* Signature: ()V
*)
procedure Java_Native_handleException(PEnv: PJNIEnv; Obj: JObject); {$IFDEF WIN32} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
var
Cls: JClass;
AException: JThrowable;
JVM: TJNIEnv;
begin
// Create an instance of the Java environment
JVM := TJNIEnv.Create(PEnv);
// Get the class to which this object belongs
Cls := JVM.GetObjectClass(Obj);
// Attempt to get the ID of the 'nonexistent' member, which, not by
// chance, doesn't exist!
JVM.GetFieldID(Cls, 'nonexistent', 'Ljava/lang/String;');
// Check for exception
AException := JVM.ExceptionOccurred;
// exception is non-zero if an exception occurred
if (AException <> nil) then
begin
//Writeln('Exception occurred in Native code and was handled. This was the exception:');
Writeln(Format('Exception handled in Main.cpp: %d', [Longint(AException)]));
// This call will print out a description of the exception
//JVM.ExceptionDescribe(PEnv);
// Clear the exception so the JVM doesn't react to it after we handled it
JVM.ExceptionClear;
end;
JVM.Free;
end;
(****************************************************************************
* Java declaration:
* native public void causeException();
*
* Causes an exception in the JVM, but fails to catch it. Thus, it is
* propagated back to the JVM.
*
* Class: Native
* Method: causeException
* Signature: ()V
*)
procedure Java_Native_causeException(PEnv: PJNIEnv; Obj: JObject); {$IFDEF WIN32} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
var
Cls: JClass;
JVM: TJNIEnv;
begin
// Create an instance of the Java environment
JVM := TJNIEnv.Create(PEnv);
// Get the class to which this object belongs
Cls := JVM.GetObjectClass(Obj);
// Attempt to get the ID of the 'nonexistent' member, which, not by
// chance, doesn't exist!
JVM.GetFieldID(Cls, 'nonexistent', 'Ljava/lang/String;');
// An exception has occurred, but it has not been suppressed.
// The JVM will detect it and catch it.
// Because we don't call this: JVM.ExceptionClear(PEnv),
// the JVM will react.
JVM.Free;
end;
(****************************************************************************
* Java declaration:
* native public void pass2DByteArray(byte[][] array);
*
* Pass a 2-D array of Bytes from Java. This method will retrieve each
* element from the arrays, print it, then multiply it by 10 and store
* the new Value back into the array. This is to show access/updating
* of 2-D arrays within native code. The process would be similar for
* 3-D arrays.
*
* Class: Native
* Method: pass2DByteArray
* Signature: ([[B)V
*)
procedure Java_Native_pass2DByteArray(PEnv: PJNIEnv; Obj: JObject; Array2D: JObjectArray); {$IFDEF WIN32} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
var
NumArrays: JSize;
Len: JSize;
I, J: Integer;
JBArray: JByteArray;
Elements, Walker: PJByte;
IsCopy: JBoolean;
JVM: TJNIEnv;
begin
// Create an instance of the Java environment
JVM := TJNIEnv.Create(PEnv);
// Get length of the array (number of arrays)
NumArrays := JVM.GetArrayLength(Array2D);
Writeln('In native method printing 2-D byte array.');
Writeln('Each element is then multiplied by 10 and updated.');
// Loop over each array
for I := 0 to NumArrays - 1 do
begin
// Get the object at the i'th position (it's an array of Bytes)
JBArray := JVM.GetObjectArrayElement(Array2D, i);
// Get the length of this array of Bytes
Len := JVM.GetArrayLength(JBArray);
// Get the elements from the Byte array
Elements := JVM.GetByteArrayElements(JBArray, IsCopy);
// We will "walk" the array with this pointer
Walker := Elements;
// Print each element, then multiply the Value by 10
// and put it back into the array. (This is to prove that
// the array elements have changed when this function returns
// to Java code.
for J := 0 to Len - 1 do
begin
Writeln(Format('%d,%d = %d', [I, J, Walker^]));
// Update the element (just multiply it by 10)
Walker^ := Walker^ * 10;
Inc(Walker);
end;
// Important! From Sun's documentation:
// Since the returned array may be a copy of the Java array, changes made
// to the returned array will not necessarily be reflected in the original
// array until Release<PrimitiveType>ArrayElements() is called.
JVM.ReleaseByteArrayElements(JBArray, Elements, 0);
end;
JVM.Free;
end;
(****************************************************************************
* This is a sample algorithm that I got from Microsoft's documentation.
* I used it as the initial test case. I may have modified it slightly.
*
* The interesting point in this example is that the function is declared
* as 'static' in the Java code. The only difference at the native level
* is that the second parameter is a 'JClass' instead of a 'JObject'.
* Most functions are non-static, and so require a handle to the object
* rather than the class.
*
* Java declaration:
* native public static int countPrimes(byte[] array);
*
* Class: Native
* Method: countPrimes
* Signature: ([B)I
*)
function Java_Native_countPrimes(PEnv: PJNIEnv; Cls: JClass; ByteArray: JByteArray): JInt; {$IFDEF WIN32} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
var
Count, Len: JSize;
I, J: JSize;
Body: PJByte;
IsCopy: JBoolean;
Ptr: PChar;
JVM: TJNIEnv;
begin
// Create an instance of the Java environment
JVM := TJNIEnv.Create(PEnv);
// Get the length of the array
Len := JVM.GetArrayLength(ByteArray);
// Get a pointer to the elements of the array. Only primitive elements
// can be accessed this way.
Body := JVM.GetByteArrayElements(ByteArray, IsCopy);
// Since body is not a Delphi array (Body is of type PJByte), we need to use
// a PChar (interchangeable with arrays) to access the java array using an
// index (e.g. Body[0] is illegal, but Ptr[0] is legal)
Ptr := PChar(Body);
// Initialize all elements
for I := 0 to Len - 1 do
Ptr[i] := #1;
Count := 0;
// Set each element at a non-prime index to 0
for I := 2 to Len - 1 do
begin
if Ptr[I] <> #0 then
begin
J := I + I;
while J < Len do
begin
Ptr[J] := #0;
Inc(J, I);
end;
Inc(Count);
end;
end;
// The number of primes between 1 and array.length
Result := Count;
end;
(****************************************************************************
* Java declaration:
* native public void VoidVoid();
*
* This function takes no arguments and returns nothing. Just used to
* demonstrate the most simplistic function call. Also used to time
* function call overhead in the simplest case.
*
* Class: Native
* Method: VoidVoid
* Signature: ()V
*)
procedure Java_Native_VoidVoid(PEnv: PJNIEnv; Obj: JObject); {$IFDEF WIN32} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
//var
//JVM: TJNIEnv;
begin
// These two lines of code take about 1 ms to execute on a PIII 450 MHz
//JVM := TJNIEnv.Create(PEnv);
//JVM.Free;
end;
(****************************************************************************
* A private native function that calls back into Java. Calls a void
* function just for timings.
*
* Class: Native
* Method: callbackVoid
* Signature: (I)V
*)
procedure Java_Native_callbackVoid(PEnv: PJNIEnv; Obj: JObject; Count: JInt); {$IFDEF WIN32} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
var
Cls: JClass;
Mid: JMethodID;
I: JInt;
JVM: TJNIEnv;
begin
// Create an instance of the Java environment
JVM := TJNIEnv.Create(PEnv);
// Get the class that this object belongs to
Cls := JVM.GetObjectClass(Obj);
// Get the method ID for 'void voidFunc()'
Mid := JVM.GetMethodID(Cls, 'voidFunc', '()V');
// If we can't find the ID, just return. This kind of check should be in all
// functions in this code, but it isn't (for brevity)
if (Mid = nil) then
exit;
// Perform the callbacks
for I := 0 to Count - 1 do
JVM.CallVoidMethodA(Obj, Mid, nil);
end;
(****************************************************************************
* Java declaration:
* native public void printVersion();
*
* Prints the version of the JDK being used.
*
* Class: Native
* Method: printVersion
* Signature: ()V
*)
procedure Java_Native_printVersion(PEnv: PJNIEnv; Obj: JObject); {$IFDEF WIN32} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
var
JVM: TJNIEnv;
Major, Minor: JInt;
begin
JVM := TJNIEnv.Create(PEnv);
Major := JVM.MajorVersion;
Minor := JVM.MinorVersion;
Writeln(Format('The Java version is %d.%d', [Major, Minor]));
end;
(****************************************************************************
* Java declaration:
* native public void testAllTypesD();
*
* Tests all data types. Shows how floats passed in open arrays to JNI
* methods are not handled correctly.
*
* Class: Native
* Method: testAllTypesD
* Signature: (ZBCIJFD)V
*)
procedure Java_Native_testAllTypesD(PEnv: PJNIEnv; Obj: JObject; Bool: JBoolean; B: JByte; C: JChar; I: JInt; L: JLong; F: jfloat; D: jdouble); {$IFDEF WIN32} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
var
Cls: JClass;
Mid: JMethodID;
JVM: TJNIEnv;
begin
// Create an instance of the Java environment
JVM := TJNIEnv.Create(PEnv);
// Get the class associated with this object
Cls := JVM.GetObjectClass(Obj);
// The ID for the testAllTypes method
Mid := JVM.GetMethodID(Cls, 'testAllTypes', '(ZBCIJFD)V');
// Call it
JVM.CallVoidMethod(Obj, Mid, [Bool, B, C, I, L, F, D]);
end;
(****************************************************************************
* Java declaration:
* native public void multiplyIntegers(int op1, int op2);
*
* Multiplies 2 integers and returns the result.
*
* Class: Native
* Method: multiplyIntegers
* Signature: (II)I
*)
function Java_Native_multiplyIntegers(PEnv: PJNIEnv; Obj: JObject; Op1: JInt; Op2: JInt): jint; {$IFDEF WIN32} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
begin
Result := Op1 * Op2;
end;
(****************************************************************************
* Java declaration:
* native public void initializeByteArrayOnce(byte[] byteArray, byte Value);
*
* Initializes each element of an array with the value 'Value'. This function
* is an overloaded version of the one used to test performance.
*
* Class: Native
* Method: initializeByteArrayOnce
* Signature: ([BB)V
*)
procedure Java_Native_initializeByteArray(PEnv: PJNIEnv; Obj: JObject; ByteArray: JByteArray; Value: JByte); {$IFDEF WIN32} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF} overload;
var
Elements: PJByte;
PE: PJByte;
Len: JSize;
I: Longint;
IsCopy: JBoolean;
JVM: TJNIEnv;
begin
// Create an instance of the Java environment
JVM := TJNIEnv.Create(PEnv);
// Get elements of the array.
elements := JVM.GetByteArrayElements(ByteArray, IsCopy);
// Get length of the array.
Len := JVM.GetArrayLength(ByteArray);
// Assign 'Value' to each element.
PE := Elements;
for I := 0 to Len - 1 do
begin
PE^ := Value;
Inc(PE);
end;
// Important! From Sun's documentation:
// Since the returned array may be a copy of the Java array, changes made
// to the returned array will not necessarily be reflected in the original
// array until Release<PrimitiveType>ArrayElements() is called.
JVM.ReleaseByteArrayElements(ByteArray, Elements, 0);
JVM.Free;
end;
(*******************************************************************************
Make these routines available to Java.
*******************************************************************************)
exports
Java_Native_initializeByteArray(PEnv: PJNIEnv; Obj: JObject; ByteArray: JByteArray; Count: JInt; Value: JByte) name 'Java_Native_initializeByteArray',
Java_Native_initializeByteArray(PEnv: PJNIEnv; Obj: JObject; ByteArray: JByteArray; Value: JByte) name 'Java_Native_initializeByteArrayOnce',
Java_Native_callbackVoid,
Java_Native_causeException,
Java_Native_countPrimes,
Java_Native_displayHelloWorld,
Java_Native_handleException,
Java_Native_multiplyIntegers,
Java_Native_pass2DByteArray,
Java_Native_printLine,
Java_Native_printObjectArray,
Java_Native_printVersion,
Java_Native_printWXYZ,
Java_Native_returnRectArray,
Java_Native_testAllTypesD,
Java_Native_toStringWithPrint,
Java_Native_VoidVoid;
begin
end.