{******************************************************************}
{                                                                  }
{       Borland Delphi Runtime Library                             }
{       Java Native Interface Unit                                 }
{                                                                  }
{ Portions created by Sun are                                      }
{ Copyright (C) 1996-1999 Sun Microsystems, Inc.,                  }
{ 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.       }
{ All Rights Reserved.                                             }
{                                                                  }
{ The original file is: jni.h, released 22 Apr 1999.               }
{ The original Pascal code is: jni.pas, released 01 Sep 2000.      }
{                                                                  }
{ Portions created by Matthew Mead are                             }
{ Copyright (C) 2000-2002 MMG and Associates                       }
{                                                                  }
{ Obtained through:                                                }
{ Joint Endeavour of Delphi Innovators (Project JEDI)              }
{                                                                  }
{ You may retrieve the latest version of this file at the Project  }
{ JEDI home page, located at http://delphi-jedi.org                }
{                                                                  }
{ The contents of this file are used with permission, subject to   }
{ the Mozilla Public License Version 1.1 (the "License"); you may  }
{ not use this file except in compliance with the License. You may }
{ obtain a copy of the License at                                  }
{ http://www.mozilla.org/NPL/NPL-1_1Final.html                     }
{                                                                  }
{ Software distributed under the License is distributed on an      }
{ "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or   }
{ implied. See the License for the specific language governing     }
{ rights and limitations under the License.                        }
{                                                                  }
{ History:                                                         }
{   03 Dec 2000 - Fixed parameters for DestroyJavaVM, GetEnv,      }
{                 AttachCurrentThread, and DetachCurrentThread     }
{   02 Jan 2001 - Fix in TJNIEnv.ArgsToJValues. Cast AnsiString    }
{                 to JString.                                      }
{   13 Mar 2002 - In the TJavaVM wrapper class, made the JavaVM    }
{                 and Env properties read/write. Previously, both  }
{                 were set as read-only.                           }
{   16 Mar 2002 - Added support for J2SDK v 1.4                    }
{   02 Apr 2002 - Changed WIN32 directive to MSWINDOWS             }
{                                                                  }
{******************************************************************}

unit JNI;

interface

uses
  {$IFDEF MSWINDOWS}
  Windows,
  {$ENDIF}
  {$IFDEF LINUX}
  Types, Libc,
  {$ENDIF}
  SysUtils;

{ Note:
  It is possible to include the defintions from JNI_MD.INC directly
  in this file. However, the idea behind separating platform-specific
  definitions is to keep this file as generic as possible. Some time
  ago, this would not have been important, since Delphi *was* a
  Windows-only tool. Now, with Kylix approaching, it will be important
  to keep the platform-specific types separate.
}

// JNI_MD.INC contains the machine-dependent typedefs for JByte, JInt and JLong

{$INCLUDE JNI_MD.INC}

{$IFDEF LINUX}
type
  va_list = PChar;
{$ENDIF}

const
  JNI_VERSION_1_1 = JInt($00010001);
  {$EXTERNALSYM JNI_VERSION_1_1}
  JNI_VERSION_1_2 = JInt($00010002);
  {$EXTERNALSYM JNI_VERSION_1_2}
  JNI_VERSION_1_4 = JInt($00010004);
  {$EXTERNALSYM JNI_VERSION_1_4}

  // JBoolean constants
  JNI_TRUE  = True;
  {$EXTERNALSYM JNI_TRUE}
  JNI_FALSE = False;
  {$EXTERNALSYM JNI_FALSE}

  // possible return values for JNI functions.
  JNI_OK        =  0;  // success
  {$EXTERNALSYM JNI_OK}
  JNI_ERR       = -1;  // unknown error
  {$EXTERNALSYM JNI_ERR}
  JNI_EDETACHED = -2;  // thread detached from the VM
  {$EXTERNALSYM JNI_EDETACHED}
  JNI_EVERSION  = -3;  // JNI version error
  {$EXTERNALSYM JNI_EVERSION}
  JNI_ENOMEM    = -4;  // not enough memory
  {$EXTERNALSYM JNI_ENOMEM}
  JNI_EEXIST    = -5;  // VM already created
  {$EXTERNALSYM JNI_EEXIST}
  JNI_EINVAL    = -6;  // invalid arguments
  {$EXTERNALSYM JNI_EINVAL}

  JNI_ENOJAVA   = -101; // local error for not finding the DLL

  // used in ReleaseScalarArrayElements
  JNI_COMMIT = 1;
  {$EXTERNALSYM JNI_COMMIT}
  JNI_ABORT  = 2;
  {$EXTERNALSYM JNI_ABORT}

type
  // JNI Types
  JBoolean = Boolean;
  JChar    = WideChar;
  JShort   = Smallint;
  JFloat   = Single;
  JDouble  = Double;
  JSize    = JInt;

  _JObject = record
  end;

  JObject       = ^_JObject;
  JClass        = JObject;
  JThrowable    = JObject;
  JString       = JObject;
  JArray        = JObject;
  JBooleanArray = JArray;
  JByteArray    = JArray;
  JCharArray    = JArray;
  JShortArray   = JArray;
  JIntArray     = JArray;
  JLongArray    = JArray;
  JFloatArray   = JArray;
  JDoubleArray  = JArray;
  JObjectArray  = JArray;

  JWeak = JObject;
  JRef  = JObject;

  JValue = packed record
  case Integer of
    0: (z: JBoolean);
    1: (b: JByte   );
    2: (c: JChar   );
    3: (s: JShort  );
    4: (i: JInt    );
    5: (j: JLong   );
    6: (f: JFloat  );
    7: (d: JDouble );
    8: (l: JObject );
  end;

  JFieldID = ^_JFieldID;
  _JFieldID = record
  end;

  JMethodID = ^_JMethodID;
  _JMethodID = record
  end;

  PPointer       = ^Pointer;
  PJByte         = ^JByte;
  PJBoolean      = ^JBoolean;
  PJChar         = ^JChar;
  PJShort        = ^JShort;
  PJInt          = ^JInt;
  PJLong         = ^JLong;
  PJFloat        = ^JFloat;
  PJDouble       = ^JDouble;
  PJString       = ^JString;
  PJSize         = ^JSize;
  PJClass        = ^JClass;
  PJObject       = ^JObject;
  PJThrowable    = ^JThrowable;
  PJArray        = ^JArray;
  PJByteArray    = ^JByteArray;
  PJBooleanArray = ^JBooleanArray;
  PJCharArray    = ^JCharArray;
  PJShortArray   = ^JShortArray;
  PJIntArray     = ^JIntArray;
  PJLongArray    = ^JLongArray;
  PJFloatArray   = ^JFloatArray;
  PJDoubleArray  = ^JDoubleArray;
  PJObjectArray  = ^JObjectArray;
  PJFieldID      = ^JFieldID;
  PJMethodID     = ^JMethodID;
  PJValue        = ^JValue;
  PJWeak         = ^JWeak;
  PJRef          = ^JRef;

  // used in RegisterNatives to describe native method name, signature,
  // and function pointer.
  PJNINativeMethod = ^JNINativeMethod;
  JNINativeMethod = packed record
    name: PAnsiChar;
    signature: PAnsiChar;
    fnPtr: Pointer;
  end;
  {$EXTERNALSYM JNINativeMethod}

  // JNI Native Method Interface.
  JNIEnv              = ^JNINativeInterface_;
  {$EXTERNALSYM JNIEnv}
  PJNIEnv             = ^JNIEnv;
  PPJNIEnv            = ^PJNIEnv;
  PJNINativeInterface = ^JNINativeInterface_;

  // JNI Invocation Interface.
  JavaVM              = ^JNIInvokeInterface_;
  {$EXTERNALSYM JavaVM}
  PJNIInvokeInterface = ^JNIInvokeInterface_;
  PJavaVM             = ^JavaVM;

  JNINativeInterface_ = packed record
    reserved0: Pointer;
    reserved1: Pointer;
    reserved2: Pointer;
    reserved3: Pointer;

    GetVersion: function(Env: PJNIEnv): JInt; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    DefineClass: function(Env: PJNIEnv; const Name: PAnsiChar; Loader: JObject; const Buf: PJByte; Len: JSize): JClass; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    FindClass: function(Env: PJNIEnv; const Name: PAnsiChar): JClass; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    // Reflection Support
    FromReflectedMethod: function(Env: PJNIEnv; Method: JObject): JMethodID; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    FromReflectedField: function(Env: PJNIEnv; Field: JObject): JFieldID; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    ToReflectedMethod: function(Env: PJNIEnv; AClass: JClass; MethodID: JMethodID; IsStatic: JBoolean): JObject; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    GetSuperclass: function(Env: PJNIEnv; Sub: JClass): JClass; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    IsAssignableFrom: function(Env: PJNIEnv; Sub: JClass; Sup: JClass): JBoolean; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    // Reflection Support
    ToReflectedField: function(Env: PJNIEnv; AClass: JClass; FieldID: JFieldID; IsStatic: JBoolean): JObject; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    Throw: function(Env: PJNIEnv; Obj: JThrowable): JInt; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    ThrowNew: function(Env: PJNIEnv; AClass: JClass; const Msg: PAnsiChar): JInt; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    ExceptionOccurred: function(Env: PJNIEnv): JThrowable; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    ExceptionDescribe: procedure(Env: PJNIEnv); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    ExceptionClear: procedure(Env: PJNIEnv); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    FatalError: procedure(Env: PJNIEnv; const Msg: PAnsiChar); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    // Local Reference Management
    PushLocalFrame: function(Env: PJNIEnv; Capacity: JInt): JInt; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    PopLocalFrame: function(Env: PJNIEnv; Result: JObject): JObject; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    NewGlobalRef: function(Env: PJNIEnv; LObj: JObject): JObject; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    DeleteGlobalRef: procedure(Env: PJNIEnv; GRef: JObject); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    DeleteLocalRef: procedure(Env: PJNIEnv; Obj: JObject); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    IsSameObject: function(Env: PJNIEnv; Obj1: JObject; Obj2: JObject): JBoolean; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    // Local Reference Management
    NewLocalRef: function(Env: PJNIEnv; Ref: JObject): JObject; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    EnsureLocalCapacity: function(Env: PJNIEnv; Capacity: JInt): JObject; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    AllocObject: function(Env: PJNIEnv; AClass: JClass): JObject; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    NewObject: function(Env: PJNIEnv; AClass: JClass; MethodID: JMethodID): JObject; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    NewObjectV: function(Env: PJNIEnv; AClass: JClass; MethodID: JMethodID; Args: va_list): JObject; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    NewObjectA: function(Env: PJNIEnv; AClass: JClass; MethodID: JMethodID; Args: PJValue): JObject; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    GetObjectClass: function(Env: PJNIEnv; Obj: JObject): JClass; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    IsInstanceOf: function(Env: PJNIEnv; Obj: JObject; AClass: JClass): JBoolean; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    GetMethodID: function(Env: PJNIEnv; AClass: JClass; const Name: PAnsiChar; const Sig: PAnsiChar): JMethodID; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    CallObjectMethod: function(Env: PJNIEnv; Obj: JObject; MethodID: JMethodID): JObject; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallObjectMethodV: function(Env: PJNIEnv; Obj: JObject; MethodID: JMethodID; Args: va_list): JObject; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallObjectMethodA: function(Env: PJNIEnv; Obj: JObject; MethodID: JMethodID; Args: PJValue): JObject; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    CallBooleanMethod: function(Env: PJNIEnv; Obj: JObject; MethodID: JMethodID): JBoolean; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallBooleanMethodV: function(Env: PJNIEnv; Obj: JObject; MethodID: JMethodID; Args: va_list): JBoolean; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallBooleanMethodA: function(Env: PJNIEnv; Obj: JObject; MethodID: JMethodID; Args: PJValue): JBoolean; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    CallByteMethod: function(Env: PJNIEnv; Obj: JObject; MethodID: JMethodID): JByte; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallByteMethodV: function(Env: PJNIEnv; Obj: JObject; MethodID: JMethodID; Args: va_list): JByte; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallByteMethodA: function(Env: PJNIEnv; Obj: JObject; MethodID: JMethodID; Args: PJValue): JByte; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    CallCharMethod: function(Env: PJNIEnv; Obj: JObject; MethodID: JMethodID): JChar; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallCharMethodV: function(Env: PJNIEnv; Obj: JObject; MethodID: JMethodID; Args: va_list): JChar; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallCharMethodA: function(Env: PJNIEnv; Obj: JObject; MethodID: JMethodID; Args: PJValue): JChar; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    CallShortMethod: function(Env: PJNIEnv; Obj: JObject; MethodID: JMethodID): JShort; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallShortMethodV: function(Env: PJNIEnv; Obj: JObject; MethodID: JMethodID; Args: va_list): JShort; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallShortMethodA: function(Env: PJNIEnv; Obj: JObject; MethodID: JMethodID; Args: PJValue): JShort; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    CallIntMethod: function(Env: PJNIEnv; Obj: JObject; MethodID: JMethodID): JInt; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallIntMethodV: function(Env: PJNIEnv; Obj: JObject; MethodID: JMethodID; Args: va_list): JInt; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallIntMethodA: function(Env: PJNIEnv; Obj: JObject; MethodID: JMethodID; Args: PJValue): JInt; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    CallLongMethod: function(Env: PJNIEnv; Obj: JObject; MethodID: JMethodID): JLong; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallLongMethodV: function(Env: PJNIEnv; Obj: JObject; MethodID: JMethodID; Args: va_list): JLong; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallLongMethodA: function(Env: PJNIEnv; Obj: JObject; MethodID: JMethodID; Args: PJValue): JLong; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    CallFloatMethod: function(Env: PJNIEnv; Obj: JObject; MethodID: JMethodID): JFloat; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallFloatMethodV: function(Env: PJNIEnv; Obj: JObject; MethodID: JMethodID; Args: va_list): JFloat; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallFloatMethodA: function(Env: PJNIEnv; Obj: JObject; MethodID: JMethodID; Args: PJValue): JFloat; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    CallDoubleMethod: function(Env: PJNIEnv; Obj: JObject; MethodID: JMethodID): JDouble; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallDoubleMethodV: function(Env: PJNIEnv; Obj: JObject; MethodID: JMethodID; Args: va_list): JDouble; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallDoubleMethodA: function(Env: PJNIEnv; Obj: JObject; MethodID: JMethodID; Args: PJValue): JDouble; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    CallVoidMethod: procedure(Env: PJNIEnv; Obj: JObject; MethodID: JMethodID); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallVoidMethodV: procedure(Env: PJNIEnv; Obj: JObject; MethodID: JMethodID; Args: va_list); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallVoidMethodA: procedure(Env: PJNIEnv; Obj: JObject; MethodID: JMethodID; Args: PJValue); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    CallNonvirtualObjectMethod: function(Env: PJNIEnv; Obj: JObject; AClass: JClass; MethodID: JMethodID): JObject; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallNonvirtualObjectMethodV: function(Env: PJNIEnv; Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: va_list): JObject; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallNonvirtualObjectMethodA: function(Env: PJNIEnv; Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: PJValue): JObject; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    CallNonvirtualBooleanMethod: function(Env: PJNIEnv; Obj: JObject; AClass: JClass; MethodID: JMethodID): JBoolean; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallNonvirtualBooleanMethodV: function(Env: PJNIEnv; Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: va_list): JBoolean; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallNonvirtualBooleanMethodA: function(Env: PJNIEnv; Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: PJValue): JBoolean; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    CallNonvirtualByteMethod: function(Env: PJNIEnv; Obj: JObject; AClass: JClass; MethodID: JMethodID): JByte; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallNonvirtualByteMethodV: function(Env: PJNIEnv; Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: va_list): JByte; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallNonvirtualByteMethodA: function(Env: PJNIEnv; Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: PJValue): JByte; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    CallNonvirtualCharMethod: function(Env: PJNIEnv; Obj: JObject; AClass: JClass; MethodID: JMethodID): JChar; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallNonvirtualCharMethodV: function(Env: PJNIEnv; Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: va_list): JChar; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallNonvirtualCharMethodA: function(Env: PJNIEnv; Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: PJValue): JChar; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    CallNonvirtualShortMethod: function(Env: PJNIEnv; Obj: JObject; AClass: JClass; MethodID: JMethodID): JShort; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallNonvirtualShortMethodV: function(Env: PJNIEnv; Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: va_list): JShort; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallNonvirtualShortMethodA: function(Env: PJNIEnv; Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: PJValue): JShort; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    CallNonvirtualIntMethod: function(Env: PJNIEnv; Obj: JObject; AClass: JClass; MethodID: JMethodID): JInt; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallNonvirtualIntMethodV: function(Env: PJNIEnv; Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: va_list): JInt; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallNonvirtualIntMethodA: function(Env: PJNIEnv; Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: PJValue): JInt; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    CallNonvirtualLongMethod: function(Env: PJNIEnv; Obj: JObject; AClass: JClass; MethodID: JMethodID): JLong; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallNonvirtualLongMethodV: function(Env: PJNIEnv; Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: va_list): JLong; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallNonvirtualLongMethodA: function(Env: PJNIEnv; Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: PJValue): JLong; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    CallNonvirtualFloatMethod: function(Env: PJNIEnv; Obj: JObject; AClass: JClass; MethodID: JMethodID): JFloat; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallNonvirtualFloatMethodV: function(Env: PJNIEnv; Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: va_list): JFloat; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallNonvirtualFloatMethodA: function(Env: PJNIEnv; Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: PJValue): JFloat; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    CallNonvirtualDoubleMethod: function(Env: PJNIEnv; Obj: JObject; AClass: JClass; MethodID: JMethodID): JDouble; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallNonvirtualDoubleMethodV: function(Env: PJNIEnv; Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: va_list): JDouble; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallNonvirtualDoubleMethodA: function(Env: PJNIEnv; Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: PJValue): JDouble; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    CallNonvirtualVoidMethod: procedure(Env: PJNIEnv; Obj: JObject; AClass: JClass; MethodID: JMethodID); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallNonvirtualVoidMethodV: procedure(Env: PJNIEnv; Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: va_list); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallNonvirtualVoidMethodA: procedure(Env: PJNIEnv; Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: PJValue); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    GetFieldID: function(Env: PJNIEnv; AClass: JClass; const Name: PAnsiChar; const Sig: PAnsiChar): JFieldID; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    GetObjectField: function(Env: PJNIEnv; Obj: JObject; FieldID: JFieldID): JObject; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    GetBooleanField: function(Env: PJNIEnv; Obj: JObject; FieldID: JFieldID): JBoolean; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    GetByteField: function(Env: PJNIEnv; Obj: JObject; FieldID: JFieldID): JByte; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    GetCharField: function(Env: PJNIEnv; Obj: JObject; FieldID: JFieldID): JChar; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    GetShortField: function(Env: PJNIEnv; Obj: JObject; FieldID: JFieldID): JShort; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    GetIntField: function(Env: PJNIEnv; Obj: JObject; FieldID: JFieldID): JInt; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    GetLongField: function(Env: PJNIEnv; Obj: JObject; FieldID: JFieldID): JLong; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    GetFloatField: function(Env: PJNIEnv; Obj: JObject; FieldID: JFieldID): JFloat; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    GetDoubleField: function(Env: PJNIEnv; Obj: JObject; FieldID: JFieldID): JDouble; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    SetObjectField: procedure(Env: PJNIEnv; Obj: JObject; FieldID: JFieldID; Val: JObject); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    SetBooleanField: procedure(Env: PJNIEnv; Obj: JObject; FieldID: JFieldID; Val: JBoolean); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    SetByteField: procedure(Env: PJNIEnv; Obj: JObject; FieldID: JFieldID; Val: JByte); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    SetCharField: procedure(Env: PJNIEnv; Obj: JObject; FieldID: JFieldID; Val: JChar); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    SetShortField: procedure(Env: PJNIEnv; Obj: JObject; FieldID: JFieldID; Val: JShort); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    SetIntField: procedure(Env: PJNIEnv; Obj: JObject; FieldID: JFieldID; Val: JInt); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    SetLongField: procedure(Env: PJNIEnv; Obj: JObject; FieldID: JFieldID; Val: JLong); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    SetFloatField: procedure(Env: PJNIEnv; Obj: JObject; FieldID: JFieldID; Val: JFloat); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    SetDoubleField: procedure(Env: PJNIEnv; Obj: JObject; FieldID: JFieldID; Val: JDouble); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    GetStaticMethodID: function(Env: PJNIEnv; AClass: JClass; const Name: PAnsiChar; const Sig: PAnsiChar): JMethodID; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    CallStaticObjectMethod: function(Env: PJNIEnv; AClass: JClass; MethodID: JMethodID): JObject; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallStaticObjectMethodV: function(Env: PJNIEnv; AClass: JClass; MethodID: JMethodID; Args: va_list): JObject; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallStaticObjectMethodA: function(Env: PJNIEnv; AClass: JClass; MethodID: JMethodID; Args: PJValue): JObject; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    CallStaticBooleanMethod: function(Env: PJNIEnv; AClass: JClass; MethodID: JMethodID): JBoolean; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallStaticBooleanMethodV: function(Env: PJNIEnv; AClass: JClass; MethodID: JMethodID; Args: va_list): JBoolean; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallStaticBooleanMethodA: function(Env: PJNIEnv; AClass: JClass; MethodID: JMethodID; Args: PJValue): JBoolean; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    CallStaticByteMethod: function(Env: PJNIEnv; AClass: JClass; MethodID: JMethodID): JByte; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallStaticByteMethodV: function(Env: PJNIEnv; AClass: JClass; MethodID: JMethodID; Args: va_list): JByte; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallStaticByteMethodA: function(Env: PJNIEnv; AClass: JClass; MethodID: JMethodID; Args: PJValue): JByte; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    CallStaticCharMethod: function(Env: PJNIEnv; AClass: JClass; MethodID: JMethodID): JChar; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallStaticCharMethodV: function(Env: PJNIEnv; AClass: JClass; MethodID: JMethodID; Args: va_list): JChar; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallStaticCharMethodA: function(Env: PJNIEnv; AClass: JClass; MethodID: JMethodID; Args: PJValue): JChar; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    CallStaticShortMethod: function(Env: PJNIEnv; AClass: JClass; MethodID: JMethodID): JShort; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallStaticShortMethodV: function(Env: PJNIEnv; AClass: JClass; MethodID: JMethodID; Args: va_list): JShort; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallStaticShortMethodA: function(Env: PJNIEnv; AClass: JClass; MethodID: JMethodID; Args: PJValue): JShort; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    CallStaticIntMethod: function(Env: PJNIEnv; AClass: JClass; MethodID: JMethodID): JInt; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallStaticIntMethodV: function(Env: PJNIEnv; AClass: JClass; MethodID: JMethodID; Args: va_list): JInt; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallStaticIntMethodA: function(Env: PJNIEnv; AClass: JClass; MethodID: JMethodID; Args: PJValue): JInt; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    CallStaticLongMethod: function(Env: PJNIEnv; AClass: JClass; MethodID: JMethodID): JLong; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallStaticLongMethodV: function(Env: PJNIEnv; AClass: JClass; MethodID: JMethodID; Args: va_list): JLong; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallStaticLongMethodA: function(Env: PJNIEnv; AClass: JClass; MethodID: JMethodID; Args: PJValue): JLong; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    CallStaticFloatMethod: function(Env: PJNIEnv; AClass: JClass; MethodID: JMethodID): JFloat; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallStaticFloatMethodV: function(Env: PJNIEnv; AClass: JClass; MethodID: JMethodID; Args: va_list): JFloat; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallStaticFloatMethodA: function(Env: PJNIEnv; AClass: JClass; MethodID: JMethodID; Args: PJValue): JFloat; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    CallStaticDoubleMethod: function(Env: PJNIEnv; AClass: JClass; MethodID: JMethodID): JDouble; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallStaticDoubleMethodV: function(Env: PJNIEnv; AClass: JClass; MethodID: JMethodID; Args: va_list): JDouble; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallStaticDoubleMethodA: function(Env: PJNIEnv; AClass: JClass; MethodID: JMethodID; Args: PJValue): JDouble; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    CallStaticVoidMethod: procedure(Env: PJNIEnv; AClass: JClass; MethodID: JMethodID); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallStaticVoidMethodV: procedure(Env: PJNIEnv; AClass: JClass; MethodID: JMethodID; Args: va_list); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    CallStaticVoidMethodA: procedure(Env: PJNIEnv; AClass: JClass; MethodID: JMethodID; Args: PJValue); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    GetStaticFieldID: function(Env: PJNIEnv; AClass: JClass; const Name: PAnsiChar; const Sig: PAnsiChar): JFieldID; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    GetStaticObjectField: function(Env: PJNIEnv; AClass: JClass; FieldID: JFieldID): JObject; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    GetStaticBooleanField: function(Env: PJNIEnv; AClass: JClass; FieldID: JFieldID): JBoolean; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    GetStaticByteField: function(Env: PJNIEnv; AClass: JClass; FieldID: JFieldID): JByte; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    GetStaticCharField: function(Env: PJNIEnv; AClass: JClass; FieldID: JFieldID): JChar; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    GetStaticShortField: function(Env: PJNIEnv; AClass: JClass; FieldID: JFieldID): JShort; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    GetStaticIntField: function(Env: PJNIEnv; AClass: JClass; FieldID: JFieldID): JInt; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    GetStaticLongField: function(Env: PJNIEnv; AClass: JClass; FieldID: JFieldID): JLong; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    GetStaticFloatField: function(Env: PJNIEnv; AClass: JClass; FieldID: JFieldID): JFloat; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    GetStaticDoubleField: function(Env: PJNIEnv; AClass: JClass; FieldID: JFieldID): JDouble; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    SetStaticObjectField: procedure(Env: PJNIEnv; AClass: JClass; FieldID: JFieldID; Val: JObject); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    SetStaticBooleanField: procedure(Env: PJNIEnv; AClass: JClass; FieldID: JFieldID; Val: JBoolean); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    SetStaticByteField: procedure(Env: PJNIEnv; AClass: JClass; FieldID: JFieldID; Val: JByte); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    SetStaticCharField: procedure(Env: PJNIEnv; AClass: JClass; FieldID: JFieldID; Val: JChar); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    SetStaticShortField: procedure(Env: PJNIEnv; AClass: JClass; FieldID: JFieldID; Val: JShort); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    SetStaticIntField: procedure(Env: PJNIEnv; AClass: JClass; FieldID: JFieldID; Val: JInt); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    SetStaticLongField: procedure(Env: PJNIEnv; AClass: JClass; FieldID: JFieldID; Val: JLong); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    SetStaticFloatField: procedure(Env: PJNIEnv; AClass: JClass; FieldID: JFieldID; Val: JFloat); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    SetStaticDoubleField: procedure(Env: PJNIEnv; AClass: JClass; FieldID: JFieldID; Val: JDouble); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    NewString: function(Env: PJNIEnv; const Unicode: PJChar; Len: JSize): JString; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    GetStringLength: function(Env: PJNIEnv; Str: JString): JSize; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    GetStringChars: function(Env: PJNIEnv; Str: JString; var IsCopy: JBoolean): PJChar; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    ReleaseStringChars: procedure(Env: PJNIEnv; Str: JString; const Chars: PJChar); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    NewStringUTF: function(Env: PJNIEnv; const UTF: PAnsiChar): JString; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    GetStringUTFLength: function(Env: PJNIEnv; Str: JString): JSize; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    GetStringUTFChars: function(Env: PJNIEnv; Str: JString; var IsCopy: JBoolean): PAnsiChar; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    ReleaseStringUTFChars: procedure(Env: PJNIEnv; Str: JString; const Chars: PAnsiChar); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    GetArrayLength: function(Env: PJNIEnv; AArray: JArray): JSize; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    NewObjectArray: function(Env: PJNIEnv; Len: JSize; AClass: JClass; Init: JObject): JObjectArray; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    GetObjectArrayElement: function(Env: PJNIEnv; AArray: JObjectArray; Index: JSize): JObject; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    SetObjectArrayElement: procedure(Env: PJNIEnv; AArray: JObjectArray; Index: JSize; Val: JObject); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    NewBooleanArray: function(Env: PJNIEnv; Len: JSize): JBooleanArray; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    NewByteArray: function(Env: PJNIEnv; Len: JSize): JByteArray; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    NewCharArray: function(Env: PJNIEnv; Len: JSize): JCharArray; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    NewShortArray: function(Env: PJNIEnv; Len: JSize): JShortArray; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    NewIntArray: function(Env: PJNIEnv; Len: JSize): JIntArray; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    NewLongArray: function(Env: PJNIEnv; Len: JSize): JLongArray; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    NewFloatArray: function(Env: PJNIEnv; Len: JSize): JFloatArray; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    NewDoubleArray: function(Env: PJNIEnv; Len: JSize): JDoubleArray; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    GetBooleanArrayElements: function(Env: PJNIEnv; AArray: JBooleanArray; var IsCopy: JBoolean): PJBoolean; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    GetByteArrayElements: function(Env: PJNIEnv; AArray: JByteArray; var IsCopy: JBoolean): PJByte; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    GetCharArrayElements: function(Env: PJNIEnv; AArray: JCharArray; var IsCopy: JBoolean): PJChar; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    GetShortArrayElements: function(Env: PJNIEnv; AArray: JShortArray; var IsCopy: JBoolean): PJShort; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    GetIntArrayElements: function(Env: PJNIEnv; AArray: JIntArray; var IsCopy: JBoolean): PJInt; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    GetLongArrayElements: function(Env: PJNIEnv; AArray: JLongArray; var IsCopy: JBoolean): PJLong; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    GetFloatArrayElements: function(Env: PJNIEnv; AArray: JFloatArray; var IsCopy: JBoolean): PJFloat; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    GetDoubleArrayElements: function(Env: PJNIEnv; AArray: JDoubleArray; var IsCopy: JBoolean): PJDouble; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    ReleaseBooleanArrayElements: procedure(Env: PJNIEnv; AArray: JBooleanArray; Elems: PJBoolean; Mode: JInt); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    ReleaseByteArrayElements: procedure(Env: PJNIEnv; AArray: JByteArray; Elems: PJByte; Mode: JInt); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    ReleaseCharArrayElements: procedure(Env: PJNIEnv; AArray: JCharArray; Elems: PJChar; Mode: JInt); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    ReleaseShortArrayElements: procedure(Env: PJNIEnv; AArray: JShortArray; Elems: PJShort; Mode: JInt); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    ReleaseIntArrayElements: procedure(Env: PJNIEnv; AArray: JIntArray; Elems: PJInt; Mode: JInt); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    ReleaseLongArrayElements: procedure(Env: PJNIEnv; AArray: JLongArray; Elems: PJLong; Mode: JInt); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    ReleaseFloatArrayElements: procedure(Env: PJNIEnv; AArray: JFloatArray; Elems: PJFloat; Mode: JInt); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    ReleaseDoubleArrayElements: procedure(Env: PJNIEnv; AArray: JDoubleArray; Elems: PJDouble; Mode: JInt); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    GetBooleanArrayRegion: procedure(Env: PJNIEnv; AArray: JBooleanArray; Start: JSize; Len: JSize; Buf: PJBoolean); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    GetByteArrayRegion: procedure(Env: PJNIEnv; AArray: JByteArray; Start: JSize; Len: JSize; Buf: PJByte); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    GetCharArrayRegion: procedure(Env: PJNIEnv; AArray: JCharArray; Start: JSize; Len: JSize; Buf: PJChar); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    GetShortArrayRegion: procedure(Env: PJNIEnv; AArray: JShortArray; Start: JSize; Len: JSize; Buf: PJShort); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    GetIntArrayRegion: procedure(Env: PJNIEnv; AArray: JIntArray; Start: JSize; Len: JSize; Buf: PJInt); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    GetLongArrayRegion: procedure(Env: PJNIEnv; AArray: JLongArray; Start: JSize; Len: JSize; Buf: PJLong); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    GetFloatArrayRegion: procedure(Env: PJNIEnv; AArray: JFloatArray; Start: JSize; Len: JSize; Buf: PJFloat); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    GetDoubleArrayRegion: procedure(Env: PJNIEnv; AArray: JDoubleArray; Start: JSize; Len: JSize; Buf: PJDouble); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    SetBooleanArrayRegion: procedure(Env: PJNIEnv; AArray: JBooleanArray; Start: JSize; Len: JSize; Buf: PJBoolean); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    SetByteArrayRegion: procedure(Env: PJNIEnv; AArray: JByteArray; Start: JSize; Len: JSize; Buf: PJByte); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    SetCharArrayRegion: procedure(Env: PJNIEnv; AArray: JCharArray; Start: JSize; Len: JSize; Buf: PJChar); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    SetShortArrayRegion: procedure(Env: PJNIEnv; AArray: JShortArray; Start: JSize; Len: JSize; Buf: PJShort); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    SetIntArrayRegion: procedure(Env: PJNIEnv; AArray: JIntArray; Start: JSize; Len: JSize; Buf: PJInt); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    SetLongArrayRegion: procedure(Env: PJNIEnv; AArray: JLongArray; Start: JSize; Len: JSize; Buf: PJLong); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    SetFloatArrayRegion: procedure(Env: PJNIEnv; AArray: JFloatArray; Start: JSize; Len: JSize; Buf: PJFloat); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    SetDoubleArrayRegion: procedure(Env: PJNIEnv; AArray: JDoubleArray; Start: JSize; Len: JSize; Buf: PJDouble); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    RegisterNatives: function(Env: PJNIEnv; AClass: JClass; const Methods: PJNINativeMethod; NMethods: JInt): JInt; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    UnregisterNatives: function(Env: PJNIEnv; AClass: JClass): JInt; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    MonitorEnter: function(Env: PJNIEnv; Obj: JObject): JInt; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    MonitorExit: function(Env: PJNIEnv; Obj: JObject): JInt; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    GetJavaVM: function(Env: PJNIEnv; var VM: JavaVM): JInt; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    // String Operations
    GetStringRegion: procedure(Env: PJNIEnv; Str: JString; Start: JSize; Len: JSize; Buf: PJChar); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    GetStringUTFRegion: procedure(Env: PJNIEnv; Str: JString; Start: JSize; Len: JSize; Buf: PAnsiChar); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    // Array Operations
    GetPrimitiveArrayCritical: function(Env: PJNIEnv; AArray: JArray; var IsCopy: JBoolean): Pointer; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    ReleasePrimitiveArrayCritical: procedure(Env: PJNIEnv; AArray: JArray; CArray: Pointer; Mode: JInt); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    // String Operations
    GetStringCritical: function(Env: PJNIEnv; Str: JString; var IsCopy: JBoolean): PJChar; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    ReleaseStringCritical: procedure(Env: PJNIEnv; Str: JString; CString: PJChar); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    // Weak Global References
    NewWeakGlobalRef: function(Env: PJNIEnv; Obj: JObject): JWeak; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    DeleteWeakGlobalRef: procedure(Env: PJNIEnv; Ref: JWeak); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    // Exceptions
    ExceptionCheck: function(Env: PJNIEnv): JBoolean; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    // J2SDK1_4
   NewDirectByteBuffer: function(Env: PJNIEnv; Address: Pointer; Capacity: JLong): JObject; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
   GetDirectBufferAddress: function(Env: PJNIEnv; Buf: JObject): Pointer; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
   GetDirectBufferCapacity: function(Env: PJNIEnv; Buf: JObject): JLong; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

  end;
  {$EXTERNALSYM JNINativeInterface_}

  // Invocation API

  PJavaVMOption = ^JavaVMOption;
  JavaVMOption = packed record
    optionString: PAnsiChar;
    extraInfo: Pointer;
  end;
  {$EXTERNALSYM JavaVMOption}

  PJavaVMInitArgs = ^JavaVMInitArgs;
  JavaVMInitArgs = packed record
    version: JInt;
    nOptions: JInt;
    options: PJavaVMOption;
    ignoreUnrecognized: JBoolean;
  end;
  {$EXTERNALSYM JavaVMInitArgs}

  PJavaVMAttachArgs = ^JavaVMAttachArgs;
  JavaVMAttachArgs = packed record
    version: JInt;
    name: PAnsiChar;
    group: JObject;
  end;
  {$EXTERNALSYM JavaVMAttachArgs}

  {$IFDEF MSWINDOWS}
  TIOFile = Pointer; // (rom) for Kylix compatibility
  {$ENDIF}

  // These structures will be VM-specific.
  PJDK1_1InitArgs = ^JDK1_1InitArgs;
  JDK1_1InitArgs = packed record
    version: JInt;
    properties: ^PAnsiChar;
    checkSource: JInt;
    nativeStackSize: JInt;
    javaStackSize: JInt;
    minHeapSize: JInt;
    maxHeapSize: JInt;
    verifyMode: JInt;
    classpath: PAnsiChar;

    vfprintf: function(FP: TIOFile; const Format: PAnsiChar; Args: va_list): JInt; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    exit: procedure(Code: JInt); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    abort: procedure; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    enableClassGC: JInt;
    enableVerboseGC: JInt;
    disableAsyncGC: JInt;
    verbose: JInt;
    debugging: JBoolean;
    debugPort: JInt;
  end;
  {$EXTERNALSYM JDK1_1InitArgs}

  JDK1_1AttachArgs = packed record
    __padding: Pointer;
  end;
  {$EXTERNALSYM JDK1_1AttachArgs}

  // End VM-specific.

  JNIInvokeInterface_ = packed record
    reserved0: Pointer;
    reserved1: Pointer;
    reserved2: Pointer;

    DestroyJavaVM: function(PVM: PJavaVM): JInt; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    AttachCurrentThread: function(PVM: PJavaVM; PEnv: PPJNIEnv; Args: Pointer): JInt; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
    DetachCurrentThread: function(PVM: PJavaVM): JInt; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    GetEnv: function(PVM: PJavaVM; PEnv: PPointer; Version: JInt): JInt; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

    // J2SDK1_4
    AttachCurrentThreadAsDaemon: function(PVM: PJavaVM; PEnv: PPJNIEnv; Args: Pointer): JInt; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

  end;
  {$EXTERNALSYM JNIInvokeInterface_}

  // Defined by native libraries.
  TJNI_OnLoad = function(PVM: PJavaVM; Reserved: Pointer): JInt; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
  TJNI_OnUnload = procedure(PVM: PJavaVM; Reserved: Pointer); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

{$IFDEF DYNAMIC_LINKING}
function JNI_GetDefaultJavaVMInitArgs(Args: PJDK1_1InitArgs; const JVMDLLFile: string): JInt;
{$EXTERNALSYM JNI_GetDefaultJavaVMInitArgs}
function JNI_CreateJavaVM(PJVM: PJavaVM; PEnv: PPointer; Args: Pointer; const JVMDLLFile: string): JInt;
{$EXTERNALSYM JNI_CreateJavaVM}
function JNI_GetCreatedJavaVMs(PJVM: PJavaVM; JSize1: JSize; var JSize2: JSize; const JVMDLLFile: string): JInt;
{$EXTERNALSYM JNI_GetCreatedJavaVMs}
{$ELSE}
function JNI_GetDefaultJavaVMInitArgs(Args: Pointer): JInt; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
{$EXTERNALSYM JNI_GetDefaultJavaVMInitArgs}
function JNI_CreateJavaVM(PJVM: PJavaVM; PEnv: PPointer; Args: Pointer): JInt; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
{$EXTERNALSYM JNI_CreateJavaVM}
function JNI_GetCreatedJavaVMs(PJVM: PJavaVM; JSize1: JSize; var JSize2: JSize): JInt; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
{$EXTERNALSYM JNI_GetCreatedJavaVMs}
{$ENDIF}

// Wrapper stuff
type
  TJValueArray = array of JValue;

  EJVMError = class(Exception);
  EJNIError = class(Exception);
  EJNIUnsupportedMethodError = class(EJNIError);

  TJNI_GetDefaultJavaVMInitArgs = function(Args: Pointer): JInt; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
  TJNI_CreateJavaVM = function(PJVM: PJavaVM; PEnv: PPointer; Args: Pointer): JInt; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
  TJNI_GetCreatedJavaVMs = function(PJVM: PJavaVM; JSize1: JSize; var JSize2: JSize): JInt; {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}

  TJavaVM = class(TObject)
  private
    FJavaVM: PJavaVM;
    FEnv: PJNIEnv;
    FJavaVMInitArgs: JavaVMInitArgs;
    FJDK1_1InitArgs: JDK1_1InitArgs;
    FJVMDLLFile: string;

    FVersion: JInt;
    {$IFDEF MSWINDOWS}
    FDLLHandle: THandle;
    {$ENDIF}
    {$IFDEF LINUX}
    FDLLHandle: Pointer;
    {$ENDIF}
    FIsInitialized: Boolean;

    // DLL functions
    FJNI_GetDefaultJavaVMInitArgs: TJNI_GetDefaultJavaVMInitArgs;
    FJNI_CreateJavaVM:             TJNI_CreateJavaVM;
    FJNI_GetCreatedJavaVMs:        TJNI_GetCreatedJavaVMs;

    procedure SetVersion(const Value: JInt);
  public
    property JavaVM: PJavaVM read FJavaVM write FJavaVM;
    property Env: PJNIEnv read FEnv write FEnv;
    property JDK1_1InitArgs: JDK1_1InitArgs read FJDK1_1InitArgs;
    property JDK1_2InitArgs: JavaVMInitArgs read FJavaVMInitArgs;
    property Version: JInt read FVersion write SetVersion;

    // Constructors
    constructor Create; overload;
    constructor Create(JDKVersion: Integer); overload;
    constructor Create(JDKVersion: Integer; const JVMDLLFilename: string); overload;

    destructor Destroy; override;
    function LoadVM(const Options: JDK1_1InitArgs): JInt; overload;
    function LoadVM(const Options: JavaVMInitArgs): JInt; overload;
    function GetDefaultJavaVMInitArgs(Args: PJDK1_1InitArgs): JInt;
    function GetCreatedJavaVMs(PJVM: PJavaVM; JSize1: JSize; var JSize2: JSize): JInt;
  end;

  TJNIEnv = class(TObject)
  private
    FEnv: PJNIEnv;
    FMajorVersion: JInt;
    FMinorVersion: JInt;
    FVersion: JInt;
    FConvertedArgs: TJValueArray;
    function GetMajorVersion: JInt;
    function GetMinorVersion: JInt;
    procedure VersionCheck(const FuncName: string; RequiredVersion: JInt);
  public
    // Properties
    property Env: PJNIEnv read FEnv;
    property MajorVersion: JInt read FMajorVersion;
    property MinorVersion: JInt read FMinorVersion;
    property Version: JInt read FVersion;

    // Constructors
    constructor Create(AEnv: PJNIEnv);

    // Support methods
    function ArgsToJValues(const Args: array of const): PJValue;
    function JStringToString(JStr: JString): string;
    function StringToJString(const AString: PAnsiChar): JString;
    function UnicodeJStringToString(JStr: JString): string;
    function StringToUnicodeJString(const AString: PAnsiChar): JString;

    // JNIEnv methods
    function GetVersion: JInt;
    function DefineClass(const Name: PAnsiChar; Loader: JObject; const Buf: PJByte; Len: JSize): JClass;
    function FindClass(const Name: PAnsiChar): JClass;

    // Reflection Support
    function FromReflectedMethod(Method: JObject): JMethodID;
    function FromReflectedField(Field: JObject): JFieldID;
    function ToReflectedMethod(AClass: JClass; MethodID: JMethodID; IsStatic: JBoolean): JObject;

    function GetSuperclass(Sub: JClass): JClass;
    function IsAssignableFrom(Sub: JClass; Sup: JClass): JBoolean;

    // Reflection Support
    function ToReflectedField(AClass: JClass; FieldID: JFieldID; IsStatic: JBoolean): JObject;

    function Throw(Obj: JThrowable): JInt;
    function ThrowNew(AClass: JClass; const Msg: PAnsiChar): JInt;
    function ExceptionOccurred: JThrowable;
    procedure ExceptionDescribe;
    procedure ExceptionClear;
    procedure FatalError(const Msg: PAnsiChar);

    // Local Reference Management
    function PushLocalFrame(Capacity: JInt): JInt;
    function PopLocalFrame(AResult: JObject): JObject;

    function NewGlobalRef(LObj: JObject): JObject;
    procedure DeleteGlobalRef(GRef: JObject);
    procedure DeleteLocalRef(Obj: JObject);
    function IsSameObject(Obj1: JObject; Obj2: JObject): JBoolean;

    // Local Reference Management
    function NewLocalRef(Ref: JObject): JObject;
    function EnsureLocalCapacity(Capacity: JInt): JObject;

    function AllocObject(AClass: JClass): JObject;
    function NewObject(AClass: JClass; MethodID: JMethodID; const Args: array of const): JObject;
    function NewObjectV(AClass: JClass; MethodID: JMethodID; Args: va_list): JObject;
    function NewObjectA(AClass: JClass; MethodID: JMethodID; Args: PJValue): JObject;

    function GetObjectClass(Obj: JObject): JClass;
    function IsInstanceOf(Obj: JObject; AClass: JClass): JBoolean;

    function GetMethodID(AClass: JClass; const Name: PAnsiChar; const Sig: PAnsiChar): JMethodID;

    function CallObjectMethod(Obj: JObject; MethodID: JMethodID; const Args: array of const): JObject;
    function CallObjectMethodV(Obj: JObject; MethodID: JMethodID; Args: va_list): JObject;
    function CallObjectMethodA(Obj: JObject; MethodID: JMethodID; Args: PJValue): JObject;

    function CallBooleanMethod(Obj: JObject; MethodID: JMethodID; const Args: array of const): JBoolean;
    function CallBooleanMethodV(Obj: JObject; MethodID: JMethodID; Args: va_list): JBoolean;
    function CallBooleanMethodA(Obj: JObject; MethodID: JMethodID; Args: PJValue): JBoolean;

    function CallByteMethod(Obj: JObject; MethodID: JMethodID; const Args: array of const): JByte;
    function CallByteMethodV(Obj: JObject; MethodID: JMethodID; Args: va_list): JByte;
    function CallByteMethodA(Obj: JObject; MethodID: JMethodID; Args: PJValue): JByte;

    function CallCharMethod(Obj: JObject; MethodID: JMethodID; const Args: array of const): JChar;
    function CallCharMethodV(Obj: JObject; MethodID: JMethodID; Args: va_list): JChar;
    function CallCharMethodA(Obj: JObject; MethodID: JMethodID; Args: PJValue): JChar;

    function CallShortMethod(Obj: JObject; MethodID: JMethodID; const Args: array of const): JShort;
    function CallShortMethodV(Obj: JObject; MethodID: JMethodID; Args: va_list): JShort;
    function CallShortMethodA(Obj: JObject; MethodID: JMethodID; Args: PJValue): JShort;

    function CallIntMethod(Obj: JObject; MethodID: JMethodID; const Args: array of const): JInt;
    function CallIntMethodV(Obj: JObject; MethodID: JMethodID; Args: va_list): JInt;
    function CallIntMethodA(Obj: JObject; MethodID: JMethodID; Args: PJValue): JInt;

    function CallLongMethod(Obj: JObject; MethodID: JMethodID; const Args: array of const): JLong;
    function CallLongMethodV(Obj: JObject; MethodID: JMethodID; Args: va_list): JLong;
    function CallLongMethodA(Obj: JObject; MethodID: JMethodID; Args: PJValue): JLong;

    function CallFloatMethod(Obj: JObject; MethodID: JMethodID; const Args: array of const): JFloat;
    function CallFloatMethodV(Obj: JObject; MethodID: JMethodID; Args: va_list): JFloat;
    function CallFloatMethodA(Obj: JObject; MethodID: JMethodID; Args: PJValue): JFloat;

    function CallDoubleMethod(Obj: JObject; MethodID: JMethodID; const Args: array of const): JDouble;
    function CallDoubleMethodV(Obj: JObject; MethodID: JMethodID; Args: va_list): JDouble;
    function CallDoubleMethodA(Obj: JObject; MethodID: JMethodID; Args: PJValue): JDouble;

    procedure CallVoidMethod(Obj: JObject; MethodID: JMethodID; const Args: array of const);
    procedure CallVoidMethodV(Obj: JObject; MethodID: JMethodID; Args: va_list);
    procedure CallVoidMethodA(Obj: JObject; MethodID: JMethodID; Args: PJValue);

    function CallNonvirtualObjectMethod(Obj: JObject; AClass: JClass; MethodID: JMethodID; const Args: array of const): JObject;
    function CallNonvirtualObjectMethodV(Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: va_list): JObject;
    function CallNonvirtualObjectMethodA(Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: PJValue): JObject;

    function CallNonvirtualBooleanMethod(Obj: JObject; AClass: JClass; MethodID: JMethodID; const Args: array of const): JBoolean;
    function CallNonvirtualBooleanMethodV(Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: va_list): JBoolean;
    function CallNonvirtualBooleanMethodA(Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: PJValue): JBoolean;

    function CallNonvirtualByteMethod(Obj: JObject; AClass: JClass; MethodID: JMethodID; const Args: array of const): JByte;
    function CallNonvirtualByteMethodV(Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: va_list): JByte;
    function CallNonvirtualByteMethodA(Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: PJValue): JByte;

    function CallNonvirtualCharMethod(Obj: JObject; AClass: JClass; MethodID: JMethodID; const Args: array of const): JChar;
    function CallNonvirtualCharMethodV(Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: va_list): JChar;
    function CallNonvirtualCharMethodA(Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: PJValue): JChar;

    function CallNonvirtualShortMethod(Obj: JObject; AClass: JClass; MethodID: JMethodID; const Args: array of const): JShort;
    function CallNonvirtualShortMethodV(Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: va_list): JShort;
    function CallNonvirtualShortMethodA(Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: PJValue): JShort;

    function CallNonvirtualIntMethod(Obj: JObject; AClass: JClass; MethodID: JMethodID; const Args: array of const): JInt;
    function CallNonvirtualIntMethodV(Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: va_list): JInt;
    function CallNonvirtualIntMethodA(Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: PJValue): JInt;

    function CallNonvirtualLongMethod(Obj: JObject; AClass: JClass; MethodID: JMethodID; const Args: array of const): JLong;
    function CallNonvirtualLongMethodV(Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: va_list): JLong;
    function CallNonvirtualLongMethodA(Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: PJValue): JLong;

    function CallNonvirtualFloatMethod(Obj: JObject; AClass: JClass; MethodID: JMethodID; const Args: array of const): JFloat;
    function CallNonvirtualFloatMethodV(Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: va_list): JFloat;
    function CallNonvirtualFloatMethodA(Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: PJValue): JFloat;

    function CallNonvirtualDoubleMethod(Obj: JObject; AClass: JClass; MethodID: JMethodID; const Args: array of const): JDouble;
    function CallNonvirtualDoubleMethodV(Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: va_list): JDouble;
    function CallNonvirtualDoubleMethodA(Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: PJValue): JDouble;

    procedure CallNonvirtualVoidMethod(Obj: JObject; AClass: JClass; MethodID: JMethodID; const Args: array of const);
    procedure CallNonvirtualVoidMethodV(Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: va_list);
    procedure CallNonvirtualVoidMethodA(Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: PJValue);

    function GetFieldID(AClass: JClass; const Name: PAnsiChar; const Sig: PAnsiChar): JFieldID;

    function GetObjectField(Obj: JObject; FieldID: JFieldID): JObject;
    function GetBooleanField(Obj: JObject; FieldID: JFieldID): JBoolean;
    function GetByteField(Obj: JObject; FieldID: JFieldID): JByte;
    function GetCharField(Obj: JObject; FieldID: JFieldID): JChar;
    function GetShortField(Obj: JObject; FieldID: JFieldID): JShort;
    function GetIntField(Obj: JObject; FieldID: JFieldID): JInt;
    function GetLongField(Obj: JObject; FieldID: JFieldID): JLong;
    function GetFloatField(Obj: JObject; FieldID: JFieldID): JFloat;
    function GetDoubleField(Obj: JObject; FieldID: JFieldID): JDouble;

    procedure SetObjectField(Obj: JObject; FieldID: JFieldID; Val: JObject);
    procedure SetBooleanField(Obj: JObject; FieldID: JFieldID; Val: JBoolean);
    procedure SetByteField(Obj: JObject; FieldID: JFieldID; Val: JByte);
    procedure SetCharField(Obj: JObject; FieldID: JFieldID; Val: JChar);
    procedure SetShortField(Obj: JObject; FieldID: JFieldID; Val: JShort);
    procedure SetIntField(Obj: JObject; FieldID: JFieldID; Val: JInt);
    procedure SetLongField(Obj: JObject; FieldID: JFieldID; Val: JLong);
    procedure SetFloatField(Obj: JObject; FieldID: JFieldID; Val: JFloat);
    procedure SetDoubleField(Obj: JObject; FieldID: JFieldID; Val: JDouble);

    function GetStaticMethodID(AClass: JClass; const Name: PAnsiChar; const Sig: PAnsiChar): JMethodID;

    function CallStaticObjectMethod(AClass: JClass; MethodID: JMethodID; const Args: array of const): JObject;
    function CallStaticObjectMethodV(AClass: JClass; MethodID: JMethodID; Args: va_list): JObject;
    function CallStaticObjectMethodA(AClass: JClass; MethodID: JMethodID; Args: PJValue): JObject;

    function CallStaticBooleanMethod(AClass: JClass; MethodID: JMethodID; const Args: array of const): JBoolean;
    function CallStaticBooleanMethodV(AClass: JClass; MethodID: JMethodID; Args: va_list): JBoolean;
    function CallStaticBooleanMethodA(AClass: JClass; MethodID: JMethodID; Args: PJValue): JBoolean;

    function CallStaticByteMethod(AClass: JClass; MethodID: JMethodID; const Args: array of const): JByte;
    function CallStaticByteMethodV(AClass: JClass; MethodID: JMethodID; Args: va_list): JByte;
    function CallStaticByteMethodA(AClass: JClass; MethodID: JMethodID; Args: PJValue): JByte;

    function CallStaticCharMethod(AClass: JClass; MethodID: JMethodID; const Args: array of const): JChar;
    function CallStaticCharMethodV(AClass: JClass; MethodID: JMethodID; Args: va_list): JChar;
    function CallStaticCharMethodA(AClass: JClass; MethodID: JMethodID; Args: PJValue): JChar;

    function CallStaticShortMethod(AClass: JClass; MethodID: JMethodID; const Args: array of const): JShort;
    function CallStaticShortMethodV(AClass: JClass; MethodID: JMethodID; Args: va_list): JShort;
    function CallStaticShortMethodA(AClass: JClass; MethodID: JMethodID; Args: PJValue): JShort;

    function CallStaticIntMethod(AClass: JClass; MethodID: JMethodID; const Args: array of const): JInt;
    function CallStaticIntMethodV(AClass: JClass; MethodID: JMethodID; Args: va_list): JInt;
    function CallStaticIntMethodA(AClass: JClass; MethodID: JMethodID; Args: PJValue): JInt;

    function CallStaticLongMethod(AClass: JClass; MethodID: JMethodID; const Args: array of const): JLong;
    function CallStaticLongMethodV(AClass: JClass; MethodID: JMethodID; Args: va_list): JLong;
    function CallStaticLongMethodA(AClass: JClass; MethodID: JMethodID; Args: PJValue): JLong;

    function CallStaticFloatMethod(AClass: JClass; MethodID: JMethodID; const Args: array of const): JFloat;
    function CallStaticFloatMethodV(AClass: JClass; MethodID: JMethodID; Args: va_list): JFloat;
    function CallStaticFloatMethodA(AClass: JClass; MethodID: JMethodID; Args: PJValue): JFloat;

    function CallStaticDoubleMethod(AClass: JClass; MethodID: JMethodID; const Args: array of const): JDouble;
    function CallStaticDoubleMethodV(AClass: JClass; MethodID: JMethodID; Args: va_list): JDouble;
    function CallStaticDoubleMethodA(AClass: JClass; MethodID: JMethodID; Args: PJValue): JDouble;

    procedure CallStaticVoidMethod(AClass: JClass; MethodID: JMethodID; const Args: array of const);
    procedure CallStaticVoidMethodV(AClass: JClass; MethodID: JMethodID; Args: va_list);
    procedure CallStaticVoidMethodA(AClass: JClass; MethodID: JMethodID; Args: PJValue);

    function GetStaticFieldID(AClass: JClass; const Name: PAnsiChar; const Sig: PAnsiChar): JFieldID;
    function GetStaticObjectField(AClass: JClass; FieldID: JFieldID): JObject;
    function GetStaticBooleanField(AClass: JClass; FieldID: JFieldID): JBoolean;
    function GetStaticByteField(AClass: JClass; FieldID: JFieldID): JByte;
    function GetStaticCharField(AClass: JClass; FieldID: JFieldID): JChar;
    function GetStaticShortField(AClass: JClass; FieldID: JFieldID): JShort;
    function GetStaticIntField(AClass: JClass; FieldID: JFieldID): JInt;
    function GetStaticLongField(AClass: JClass; FieldID: JFieldID): JLong;
    function GetStaticFloatField(AClass: JClass; FieldID: JFieldID): JFloat;
    function GetStaticDoubleField(AClass: JClass; FieldID: JFieldID): JDouble;

    procedure SetStaticObjectField(AClass: JClass; FieldID: JFieldID; Val: JObject);
    procedure SetStaticBooleanField(AClass: JClass; FieldID: JFieldID; Val: JBoolean);
    procedure SetStaticByteField(AClass: JClass; FieldID: JFieldID; Val: JByte);
    procedure SetStaticCharField(AClass: JClass; FieldID: JFieldID; Val: JChar);
    procedure SetStaticShortField(AClass: JClass; FieldID: JFieldID; Val: JShort);
    procedure SetStaticIntField(AClass: JClass; FieldID: JFieldID; Val: JInt);
    procedure SetStaticLongField(AClass: JClass; FieldID: JFieldID; Val: JLong);
    procedure SetStaticFloatField(AClass: JClass; FieldID: JFieldID; Val: JFloat);
    procedure SetStaticDoubleField(AClass: JClass; FieldID: JFieldID; Val: JDouble);

    function NewString(const Unicode: PJChar; Len: JSize): JString;
    function GetStringLength(Str: JString): JSize;
    function GetStringChars(Str: JString; var IsCopy: JBoolean): PJChar;
    procedure ReleaseStringChars(Str: JString; const Chars: PJChar);

    function NewStringUTF(const UTF: PAnsiChar): JString;
    function GetStringUTFLength(Str: JString): JSize;
    function GetStringUTFChars(Str: JString; var IsCopy: JBoolean): PAnsiChar;
    procedure ReleaseStringUTFChars(Str: JString; const Chars: PAnsiChar);

    function GetArrayLength(AArray: JArray): JSize;

    function NewObjectArray(Len: JSize; AClass: JClass; Init: JObject): JObjectArray;
    function GetObjectArrayElement(AArray: JObjectArray; Index: JSize): JObject;
    procedure SetObjectArrayElement(AArray: JObjectArray; Index: JSize; Val: JObject);

    function NewBooleanArray(Len: JSize): JBooleanArray;
    function NewByteArray(Len: JSize): JByteArray;
    function NewCharArray(Len: JSize): JCharArray;
    function NewShortArray(Len: JSize): JShortArray;
    function NewIntArray(Len: JSize): JIntArray;
    function NewLongArray(Len: JSize): JLongArray;
    function NewFloatArray(Len: JSize): JFloatArray;
    function NewDoubleArray(Len: JSize): JDoubleArray;

    function GetBooleanArrayElements(AArray: JBooleanArray; var IsCopy: JBoolean): PJBoolean;
    function GetByteArrayElements(AArray: JByteArray; var IsCopy: JBoolean): PJByte;
    function GetCharArrayElements(AArray: JCharArray; var IsCopy: JBoolean): PJChar;
    function GetShortArrayElements(AArray: JShortArray; var IsCopy: JBoolean): PJShort;
    function GetIntArrayElements(AArray: JIntArray; var IsCopy: JBoolean): PJInt;
    function GetLongArrayElements(AArray: JLongArray; var IsCopy: JBoolean): PJLong;
    function GetFloatArrayElements(AArray: JFloatArray; var IsCopy: JBoolean): PJFloat;
    function GetDoubleArrayElements(AArray: JDoubleArray; var IsCopy: JBoolean): PJDouble;

    procedure ReleaseBooleanArrayElements(AArray: JBooleanArray; Elems: PJBoolean; Mode: JInt);
    procedure ReleaseByteArrayElements(AArray: JByteArray; Elems: PJByte; Mode: JInt);
    procedure ReleaseCharArrayElements(AArray: JCharArray; Elems: PJChar; Mode: JInt);
    procedure ReleaseShortArrayElements(AArray: JShortArray; Elems: PJShort; Mode: JInt);
    procedure ReleaseIntArrayElements(AArray: JIntArray; Elems: PJInt; Mode: JInt);
    procedure ReleaseLongArrayElements(AArray: JLongArray; Elems: PJLong; Mode: JInt);
    procedure ReleaseFloatArrayElements(AArray: JFloatArray; Elems: PJFloat; Mode: JInt);
    procedure ReleaseDoubleArrayElements(AArray: JDoubleArray; Elems: PJDouble; Mode: JInt);

    procedure GetBooleanArrayRegion(AArray: JBooleanArray; Start: JSize; Len: JSize; Buf: PJBoolean);
    procedure GetByteArrayRegion(AArray: JByteArray; Start: JSize; Len: JSize; Buf: PJByte);
    procedure GetCharArrayRegion(AArray: JCharArray; Start: JSize; Len: JSize; Buf: PJChar);
    procedure GetShortArrayRegion(AArray: JShortArray; Start: JSize; Len: JSize; Buf: PJShort);
    procedure GetIntArrayRegion(AArray: JIntArray; Start: JSize; Len: JSize; Buf: PJInt);
    procedure GetLongArrayRegion(AArray: JLongArray; Start: JSize; Len: JSize; Buf: PJLong);
    procedure GetFloatArrayRegion(AArray: JFloatArray; Start: JSize; Len: JSize; Buf: PJFloat);
    procedure GetDoubleArrayRegion(AArray: JDoubleArray; Start: JSize; Len: JSize; Buf: PJDouble);

    procedure SetBooleanArrayRegion(AArray: JBooleanArray; Start: JSize; Len: JSize; Buf: PJBoolean);
    procedure SetByteArrayRegion(AArray: JByteArray; Start: JSize; Len: JSize; Buf: PJByte);
    procedure SetCharArrayRegion(AArray: JCharArray; Start: JSize; Len: JSize; Buf: PJChar);
    procedure SetShortArrayRegion(AArray: JShortArray; Start: JSize; Len: JSize; Buf: PJShort);
    procedure SetIntArrayRegion(AArray: JIntArray; Start: JSize; Len: JSize; Buf: PJInt);
    procedure SetLongArrayRegion(AArray: JLongArray; Start: JSize; Len: JSize; Buf: PJLong);
    procedure SetFloatArrayRegion(AArray: JFloatArray; Start: JSize; Len: JSize; Buf: PJFloat);
    procedure SetDoubleArrayRegion(AArray: JDoubleArray; Start: JSize; Len: JSize; Buf: PJDouble);

    function RegisterNatives(AClass: JClass; const Methods: PJNINativeMethod; NMethods: JInt): JInt;
    function UnregisterNatives(AClass: JClass): JInt;

    function MonitorEnter(Obj: JObject): JInt;
    function MonitorExit(Obj: JObject): JInt;

    function GetJavaVM(var VM: JavaVM): JInt;

    // String Operations
    procedure GetStringRegion(Str: JString; Start: JSize; Len: JSize; Buf: PJChar);
    procedure GetStringUTFRegion(Str: JString; Start: JSize; Len: JSize; Buf: PAnsiChar);

    // Array Operations
    function GetPrimitiveArrayCritical(AArray: JArray; var IsCopy: JBoolean): Pointer;
    procedure ReleasePrimitiveArrayCritical(AArray: JArray; CArray: Pointer; Mode: JInt);

    // String Operations
    function GetStringCritical(Str: JString; var IsCopy: JBoolean): PJChar;
    procedure ReleaseStringCritical(Str: JString; CString: PJChar);

    // Weak Global References
    function NewWeakGlobalRef(Obj: JObject): JWeak;
    procedure DeleteWeakGlobalRef(Ref: JWeak);

    // Exceptions
    function ExceptionCheck: JBoolean;

    // J2SDK1_4
    function NewDirectByteBuffer(Address: Pointer; Capacity: JLong): JObject;
    function GetDirectBufferAddress(Buf: JObject): Pointer;
    function GetDirectBufferCapacity(Buf: JObject): JLong;
  end;

{$IFDEF DYNAMIC_LINKING}
function LoadJVM(const Filename: string): Boolean;
function UnloadJVM: Boolean;
function JVMIsLoaded: Boolean;
{$ENDIF}

implementation

{$IFNDEF DYNAMIC_LINKING}
const
  {$IFDEF MSWINDOWS}
    {$IFDEF JDK1_1}
    JvmModuleName = 'javai.dll';
    {$ELSE}
    JvmModuleName = 'jvm.dll';
    {$ENDIF}
  {$ENDIF}
  {$IFDEF LINUX}
  JvmModuleName = 'libjvm.so';
  {$ENDIF}

function JNI_CreateJavaVM; external JvmModuleName name 'JNI_CreateJavaVM';
function JNI_GetDefaultJavaVMInitArgs; external JvmModuleName name 'JNI_GetDefaultJavaVMInitArgs';
function JNI_GetCreatedJavaVMs; external JvmModuleName name 'JNI_GetCreatedJavaVMs';

{$ELSE}

var
  {$IFDEF MSWINDOWS}
  JVMHandle: THandle;
  {$ENDIF}
  {$IFDEF LINUX}
  JVMHandle: Pointer;
  {$ENDIF}
  CreateJavaVM: TJNI_CreateJavaVM;
  GetCreatedJavaVMs: TJNI_GetCreatedJavaVMs;
  GetDefaultJavaVMInitArgs: TJNI_GetDefaultJavaVMInitArgs;

{$IFDEF MSWINDOWS}

function JVMIsLoaded: Boolean;
begin
  Result := JVMHandle <> 0;
end;

function UnloadJVM: Boolean;
begin
  Result := True;
  if JVMIsLoaded then
    Result := FreeLibrary(JVMHandle);
  JVMHandle := 0;
  CreateJavaVM := nil;
  GetCreatedJavaVMs := nil;
  GetDefaultJavaVMInitArgs := nil;
end;

function LoadJVM(const Filename: string): Boolean;
begin
  Result := JVMIsLoaded;
  if not Result then
  begin
    JVMHandle := LoadLibrary(PChar(Filename));
    if JVMIsLoaded then
    begin
      @CreateJavaVM := GetProcAddress(JVMHandle, 'JNI_CreateJavaVM');
      @GetCreatedJavaVMs := GetProcAddress(JVMHandle, 'JNI_GetCreatedJavaVMs');
      @GetDefaultJavaVMInitArgs := GetProcAddress(JVMHandle, 'JNI_GetDefaultJavaVMInitArgs');
      Result := Assigned(CreateJavaVM) and Assigned(GetCreatedJavaVMs) and Assigned(GetDefaultJavaVMInitArgs);
      if not Result then
      begin
        UnloadJVM;
        raise EJVMError.CreateFmt('"%s" is not a valid JVM library', [Filename]);
      end;
    end;
  end;
end;

{$ENDIF} // MSWINDOWS

{$IFDEF LINUX}

function JVMIsLoaded: Boolean;
begin
  Result := JVMHandle <> nil;
end;

function UnloadJVM: Boolean;
begin
  Result := True;
  if JVMIsLoaded then
    dlclose(JVMHandle);
  JVMHandle := nil;
  CreateJavaVM := nil;
  GetCreatedJavaVMs := nil;
  GetDefaultJavaVMInitArgs := nil;
end;

function LoadJVM(const Filename: string): Boolean;
begin
  Result := JVMIsLoaded;
  if not Result then
  begin
    JVMHandle := dlopen(PChar(Filename), RTLD_NOW);
    if JVMIsLoaded then
    begin
      @CreateJavaVM := dlsym(JVMHandle, 'JNI_CreateJavaVM');
      @GetCreatedJavaVMs := dlsym(JVMHandle, 'JNI_GetCreatedJavaVMs');
      @GetDefaultJavaVMInitArgs := dlsym(JVMHandle, 'JNI_GetDefaultJavaVMInitArgs');
      Result := Assigned(CreateJavaVM) and Assigned(GetCreatedJavaVMs) and Assigned(GetDefaultJavaVMInitArgs);
      if not Result then
      begin
        UnloadJVM;
        raise EJVMError.CreateFmt('"%s" is not a valid JVM library', [Filename]);
      end;
    end;
  end;
end;

{$ENDIF} // LINUX

function JNI_CreateJavaVM(PJVM: PJavaVM; PEnv: PPointer; Args: Pointer; const JVMDLLFile: string): JInt;
begin
  if not JVMIsLoaded then
    LoadJVM(JVMDLLFile);

  if JVMIsLoaded then
    Result := CreateJavaVM(PJVM, PEnv, Args)
  else
    Result := JNI_ENOJAVA;
end;

function JNI_GetCreatedJavaVMs(PJVM: PJavaVM; JSize1: JSize; var JSize2: JSize; const JVMDLLFile: string): JInt;
begin
  if not JVMIsLoaded then
    LoadJVM(JVMDLLFile);

  if JVMIsLoaded then
    Result := GetCreatedJavaVMs(PJVM, JSize1, JSize2)
  else
    Result := JNI_ENOJAVA;
end;

function JNI_GetDefaultJavaVMInitArgs(Args: PJDK1_1InitArgs; const JVMDLLFile: string): JInt;
begin
  if not JVMIsLoaded then
    LoadJVM(JVMDLLFile);

  if JVMIsLoaded then
    Result := GetDefaultJavaVMInitArgs(Args)
  else
    Result := JNI_ENOJAVA;
end;

{$ENDIF} // DYNAMIC_LINKING defined

function TJNIEnv.ArgsToJValues(const Args: array of const): PJValue;
var
  I: Integer;
begin
  if Length(Args) <> Length(FConvertedArgs) then
    SetLength(FConvertedArgs, Length(Args));
  for I := 0 to High(Args) do
    case Args[I].VType of
      vtInteger:
        FConvertedArgs[I].i := Args[I].VInteger;
      vtBoolean:
        FConvertedArgs[I].z := Args[I].VBoolean;
      vtWideChar:
        FConvertedArgs[I].c := Args[I].VWideChar;
      vtInt64:
        FConvertedArgs[I].j := Args[I].VInt64^;
      vtPointer, vtObject:
        FConvertedArgs[I].l := JObject(Args[I].VObject);
      vtAnsiString:
        FConvertedArgs[I].l := StringToJString(Args[I].VAnsiString);
      vtExtended:
        FConvertedArgs[I].d := Args[I].VExtended^; // Extended to Double (we lose Floats here)
    else
      raise EJNIError.Create('Unsupported variant argument');
    end;
  Result := PJValue(FConvertedArgs);
end;

constructor TJNIEnv.Create(AEnv: PJNIEnv);
begin
  inherited Create;
  FConvertedArgs := nil;
  FEnv := AEnv;
  FMajorVersion := GetMajorVersion;
  FMinorVersion := GetMinorVersion;
  FVersion      := GetVersion;
end;

function TJNIEnv.StringToJString(const AString: PAnsiChar): JString;
begin
  Result := Env^.NewStringUTF(Env, PChar(AString));
end;

function TJNIEnv.StringToUnicodeJString(const AString: PAnsiChar): JString;
begin
  Result := Env^.NewString(Env, PJChar(AString), Length(AString));
end;

function TJNIEnv.JStringToString(JStr: JString): string;
var
  IsCopy: JBoolean;
  Chars: PChar;
begin
  if JStr = nil then
  begin
    Result := '';
    Exit;
  end;

  Chars := Env^.GetStringUTFChars(Env, JStr, IsCopy);
  if Chars = nil then
    Result := ''
  else
  begin
    Result := string(Chars);
    Env^.ReleaseStringUTFChars(Env, JStr, Chars);
  end;
end;

function TJNIEnv.UnicodeJStringToString(JStr: JString): string;
var
  IsCopy: JBoolean;
  Chars: PJChar;
begin
  if JStr = nil then
  begin
    Result := '';
    Exit;
  end;

  Chars := Env^.GetStringChars(Env, JStr, IsCopy);
  if Chars = nil then
    Result := ''
  else
  begin
    Result := string(Chars);
    Env^.ReleaseStringChars(Env, JStr, Chars);
  end;
end;

function TJNIEnv.GetMajorVersion: JInt;
begin
  Result := GetVersion shr 16;
end;

function TJNIEnv.GetMinorVersion: JInt;
begin
  Result := GetVersion mod 65536;
end;

function TJNIEnv.GetVersion: JInt;
begin
  Result := Env^.GetVersion(Env);
end;

procedure TJNIEnv.VersionCheck(const FuncName: string; RequiredVersion: JInt);
begin
  if Version < RequiredVersion then
    raise EJNIUnsupportedMethodError.CreateFmt('Method "%s" not supported in JDK %d.%d', [FuncName, MajorVersion, MinorVersion]);
end;

procedure TJNIEnv.CallVoidMethod(Obj: JObject; MethodID: JMethodID; const Args: array of const);
begin
  Env^.CallVoidMethodA(Env, Obj, MethodID, ArgsToJValues(Args));
end;

function TJNIEnv.AllocObject(AClass: JClass): JObject;
begin
  Result := Env^.AllocObject(Env, AClass);
end;

function TJNIEnv.CallBooleanMethod(Obj: JObject; MethodID: JMethodID; con