有些時候,要寫一些程序,在 JAVA 里面好難實現(xiàn), 但如果使用其它編程語言卻又比較容易時,我們不妨通過 JNI 來讓不同語言的程序共同完成.
JNI 的教程, 網(wǎng)上 C 的比較多,Java 也提供了 javah.exe 為 C 語言的 JNI 程序生成頭文件, 如果你是一個 Delphi 編程員, 能否讓 JAVA 與 Delphi 程序交互呢? 答案是肯定的,今天我們就來看一下一個簡單的例子.
Helloworld. 主要是來認識一下, JAVA 怎樣調(diào)用 Delphi 程序的方法.
好的,我們先來創(chuàng)建一個類:
package alvinJNI;
class HelloWorld {
static {
System.loadLibrary("DelphiAction"); //等一下我們就用Delphi來編一個程序,編好之后生成的文件就是 DelphiAction.dll 這是一個動態(tài)鏈接庫文件,這個類里先在靜態(tài)語句塊中加載它
}
public native void printText(); //聲明一個 native 的本地代碼程序,我們使用的是 Delphi 來編寫.注意:這個方法在這里只是聲明,并沒有定義方法體,因為這個方法我們要用 Delphi 來實現(xiàn).
public static void main(String[] args) {
//創(chuàng)建對象并調(diào)用里面的 native 方法.
HelloWorld hw = new HelloWorld();
hw.printText();
}
}
類寫完編譯后,接下來的事情就由 Delphi 來解決了
我們運行 Delphi 后新建 DLL 工程: file->new->other,然后在 new 選項卡里面選擇 Dll Wizard 就創(chuàng)建了一個新的工程了,
我們選擇一個文件夾來保存工程
在保存工程后,我們需要下載 jni.pas 加入到我們的工程中,這是國外的高手寫的程序單元,它方便我們的 Delphi 程序與 JAVA 交互. 可從下面地址下載到:jni_pas.zip
解壓之后里面有兩個文件,將其存放在工程的目錄下
接下來我們編寫 Delphi 代碼:
library DelphiAction; //這里設置動態(tài)鏈接庫的名稱,因為我們剛才寫 JAVA 類時是用 DelphiAction,所以這里了要設置為 DelphiAction
{ Important note about DLL memory management: ShareMem must be the
first unit in your library's USES clause AND your project's (select
Project-View Source) USES clause if your DLL exports any procedures or
functions that pass strings as parameters or function results. This
applies to all strings passed to and from your DLL--even those that
are nested in records and classes. ShareMem is the interface unit to
the BORLNDMM.DLL shared memory manager, which must be deployed along
with your DLL. To avoid using BORLNDMM.DLL, pass string information
using PChar or ShortString parameters. 這里面都是注釋,是自動生成的,可以刪去 }
Uses
JNI; //注意了,我們剛才下載了 JNI.pas 放在工程目錄中,這里要在 Uses 里面聲明,才能使用.
//下面我們來寫一個函數(shù),就是為 剛才 JAVA 類實現(xiàn)一個簡單的方法
//因為要讓 JAVA 能夠調(diào)用到這個函數(shù),所以這個函數(shù)的命名是非常講究的,名稱各段的分隔符是 _ 下劃線
//本例的函數(shù)如下: 即 Java_包名_類名_類中的方法名
//函數(shù)必須設置為 stdcall
procedure Java_alvinJNI_HelloWorld_printText(PEnv: PJNIEnv; Obj: JObject); stdcall;
begin
//函數(shù)體非常簡單,因為我們只是了解一下如何調(diào)用 Delphi 的函數(shù).
Writeln('您好!看到效果了吧。');
end;
exports
Java_alvinJNI_HelloWorld_printText; //為函數(shù)做引出聲明,這樣才能真正的被調(diào)用到
end.
代碼完成,我們 Ctrl+F9 編譯 DLL
生成 DelphiAction.dll 后,我們把他復制到 Java 工程目錄
注意:上面的類是打包在 alvinJNI 包中
假如我們的 Java 工程是在 C:/test
那么剛才編譯后的類必須放在 c:/test/alvinJNI/HelloWorld.class
而剛剛編譯完成的 DelphiAction.dll就放在 c:/test/DelphiAction.dll
然后在 C:/test 目錄中執(zhí)行: java alvinJNI/HelloWorld
看看你的 Java 程序調(diào)用了 DelphiAction 是怎么樣的效果.
呵呵,爽吧! 今天我們才做了一點點,只學了一下如何在 JAVA 調(diào)用 Delphi 和程序,在接下來,我會貼出更多的教程,以學習一些高級一點點的 JNI 知識.
現(xiàn)在難得來看一下自己的博客,今天好不容易找了個代理,順便再繼續(xù)之前的話題,就是 JAVA 與 Delphi 的交互了.
在上一篇中,我們說了如何用 Java 調(diào)用 Delphi 程序的一個方法,今天我們再深入一點,就是怎樣提交參數(shù)個 Delphi 的方法,以動態(tài)的控制 Delphi 的方法.
下面,我們切入正題.
首先,我們定義如下的 Java 類:
//----------------------------------------------------------------------------------------------------------
package alvinJNI;
class HelloWorld {
static {
System.loadLibrary("DelphiAction");
}
public native void printText(String str);
public static void main(String[] args) {
HelloWorld hw = new HelloWorld();
hw.printText("您好!看到效果了吧。");
}
}
//----------------------------------------------------------------------------------------------------------
我們再像上次一樣在 Delphi 中建立 DLL 工程,寫下面的代碼(有注釋):
//----------------------------------------------------------------------------------------------------------
library DelphiAction;
uses
JNI;
//這一次我們要寫的這個方法因為要接收一個 Java 傳過來的參數(shù),所以我們來說一下這個參數(shù)列表的問題
//參數(shù)列表中的第一個參數(shù) PEnv 類型為 PJNIEnv, 它是 JNI.pas中定義的類型,我們好多工作要通過它來實現(xiàn),可以把它看成是一個幫你的程序與 Java 溝通的橋梁.
//參數(shù)列表中的第一個參數(shù) obj 類型為 JObject.前面這兩個參數(shù)是固定的,這第二個參數(shù)暫時我們還不會用到.
//今天,我們還要給這個方法多加一個參數(shù),用來接受 Java 傳過來的參數(shù). str: JString
procedure Java_alvinJNI_HelloWorld_printText(PEnv: PJNIEnv; Obj: JObject; str: JString); stdcall;
//這回我們需要用到一個 TJNIEnv 對象,我們來聲明
var
JVM: TJNIEnv;
tmpStr: String;
begin
//實例化 JVM, 這個對象可以看成是 Java 的虛擬機.(自己的理解)
JVM := TJNIEnv.Create(PEnv);
//參數(shù)提交過來的字符串,實際上是一個 JString 對象,我們在這里要用 JVM 來轉(zhuǎn)化它.
//我們調(diào)用 JVM 的 UnicodeJStringToString 函數(shù)就可以實現(xiàn) JString 到 String 的轉(zhuǎn)化了.
tmpStr := JVM.UnicodeJStringToString(str);
Writeln(tmpStr);
//我們使用完 JVM 后,要將其釋放.
JVM.Free;
end;
exports
Java_alvinJNI_HelloWorld_printText; //為函數(shù)做引出聲明,這樣才能真正的被調(diào)用到
end.
//----------------------------------------------------------------------------------------------------------
我們現(xiàn)在就可以生成 DelphiAction.dll 將其放在 Java 工程目錄下, 再執(zhí)行 alvinJNI.HelloWorld 看看效果了.
好了,我們今天主要就是實現(xiàn)了一下,如何在 Java 調(diào)用 Delphi 的方法時,給其提交一個參數(shù).
是不是很爽?
在上一篇中,我們說了如何用 Java 調(diào)用 Delphi 程序的一個方法并傳遞給其一個字符串參數(shù),現(xiàn)在我們再來看一下如果傳遞的參數(shù)是其它基本類型,又要怎么做.
首先,我們先看一下如何傳遞 int 型參數(shù),定義如下的 Java 類:
//----------------------------------------------------------------------------------------------------------
package alvinJNI;
class HelloWorld {
static {
System.loadLibrary("DelphiAction");
}
public native void printText(int i);
public static void main(String[] args) {
HelloWorld hw = new HelloWorld();
hw.printText(100);
}
}
//----------------------------------------------------------------------------------------------------------
我們再像上次一樣在 Delphi 中建立 DLL 工程,寫下面的代碼(有注釋):
//----------------------------------------------------------------------------------------------------------
library DelphiAction;
uses
JNI;
//我們給這個方法加的參數(shù)是: i: JInt
procedure Java_alvinJNI_HelloWorld_printText(PEnv: PJNIEnv; Obj: JObject; i: JInt); stdcall;
var
tmpInt: Integer;
begin
//參數(shù)提交過來的 int 型數(shù)據(jù),在這里是一個 JInt 數(shù)據(jù),它其實就是一個 Integer 數(shù)據(jù),它的使用更加方便
//它可以直接地參與 Interger 類型數(shù)據(jù)的運算,是不是很容易.
tmpInt := i + 100;
tmpInt := tmpInt - 100;
Writeln(tmpInt);
end;
exports
Java_alvinJNI_HelloWorld_printText;
end.
//----------------------------------------------------------------------------------------------------------
再看看效果吧,是不是成功了?
這里如果是 long 型參數(shù),接收時要設為 JLong 類型,它也可以跟對應的整型數(shù)運算,我們常用它跟 Int64 一起運算
如果參數(shù)類型是 float ,接收參數(shù)時要設為 JFloat 類型,它也可以跟跟 Single 一起運算
如果參數(shù)類型是 double ,接收參數(shù)時要設為 JDouble 類型,它也可以跟跟 Delphi 中的 Double 型數(shù)據(jù)一起運算
如果參數(shù)類型是 boolean ,接收參數(shù)時要設為 JBoolean 類型,它也可以跟跟 Delphi 中的布爾型數(shù)據(jù)一起運算
如果參數(shù)類型是 short ,接收參數(shù)時要設為 JShort 類型,它也可以跟跟 SmallInt 型數(shù)據(jù)一起運算
如果參數(shù)類型是 byte ,接收參數(shù)時要設為 JByte 類型,它也可以跟跟 ShortInt 型數(shù)據(jù)一起運算
如果參數(shù)類型是 Object 的 Java 對象,接收時要設為 JObject 類型,它的用法比較復雜(涉及到對 Java 類和對象的操作),我們在以后再來學習.
如果參數(shù)類型是 Type[] 數(shù)組,接收參數(shù)時要設為 JObject 類型,因為 Java 是把數(shù)組作為對象看待的.它要以以下的方式來使用:
例如: 我們要給 Delphi 的方法傳入一個 byte[] 型數(shù)組,在定義 Delphi 方法時參數(shù)聲明為 bytearray: JObject
在方法中:
var
PByteArr: PJByte //PJByte 是 JNI.pas 定義的, 里面還有 PJBoolean, PJObject, PJInt 等..
JVM: TJNIEnv;
isCopy: Boolean;
begin
JVM:= TJNIEnv.Create(PEnv);
isCopy := false;
PByteArr := JVM.GetByteArrayElements(bytearray, isCopy); //調(diào)用這個方法,可以將取得參數(shù) bytearray 的地址, isCopy 決定是否復制數(shù)組
//之后,我們可以通過 PByteArr 結(jié)合 inc(PByteArr) 這個指針來操作傳過來的數(shù)組.
end;
在上一篇中,我們說了如何用 Java 調(diào)用 Delphi 程序的一個方法并傳遞給其一個參數(shù)
現(xiàn)在我們再來看一下如果如果要調(diào)用的方法有返回值,又要怎么做.
首先,我們先定義如下的 Java 類:
//------------------------------------------------------------------------------
package alvinJNI;
class HelloWorld {
static {
System.loadLibrary("DelphiAction");
}
public native String printText(String arg);
public static void main(String[] args) {
HelloWorld hw = new HelloWorld();
System.out.println(hw.printText("你好"));
}
}
//-------------------------------------------------------------------------------
我們再像上次一樣在 Delphi 中建立 DLL 工程,寫下面的代碼(有注釋):
//-------------------------------------------------------------------------------
library DelphiAction;
uses
JNI;
//今天,因為這個方法有返回值,所以不再是 procedure 過程,我們要變成 function 函數(shù), 返回值類型為 JString
function Java_alvinJNI_HelloWorld_printText(PEnv: PJNIEnv; Obj: JObject; arg: JString): JString; stdcall;
var
tmpStr: String;
JVM: TJNIEnv;
tt: Boolean;
begin
JVM:= TJNIEnv.Create(PEnv);
//我們這里先把參數(shù)提交過來的 JString 轉(zhuǎn)換成 Delphi 中的 String 后就可以使用了
tmpStr := '你想輸出的字符串是: "' + JVM.UnicodeJStringToString(arg) + '"。';
//當字符串要轉(zhuǎn)換成 JString 我們需要先對字符串進行 UTF8 編碼后再轉(zhuǎn)換成 PChar 再轉(zhuǎn)換成 JString
//這樣才能保證返回的字符串在 JAVA 中不亂碼
Result := JVM.StringToJString(pchar(UTF8Encode(tmpStr)));
JVM.Free;
end;
exports
Java_alvinJNI_HelloWorld_printText;
end.
//--------------------------------------------------------------------------------
再看看效果吧,是不是成功了?
這里如果返回值的類型是其它的其本類型,比如 JLong,JInt,JFloat,JDouble,JBoolean,JShort,JByte
這些類型的數(shù)據(jù)可以直接與 Delphi 中的數(shù)據(jù)運算,對應 Int64,Integer,Single,Double,Boolean,SmallInt,ShortInt
返回時可以直接給 Result 賦 Delphi 中的數(shù)值. 如:
function Java_alvinJNI_HelloWorld_getInt(PEnv: PJNIEnv; Obj: JObject): JInt; stdcall;
var
tmp: Integer;
begin
tmp := 10;
Result := tmp;
end;
如果返回值的類型是 Object 的 Java 對象,返回 JObject 類型,它的用法我們在以后再來學習.
如果返回值的類型是 Type[] 數(shù)組,接收參數(shù)時要設為 JObject 類型,怎樣創(chuàng)建這樣的數(shù)組對象,我自己也還不知道,以后知道了我再來貼上
因為 Java 是把數(shù)組作為對象看待的.它要以以下的方式來使用:
例如: 我們要給 Delphi 的方法傳入一個 byte[] 型數(shù)組,在定義 Delphi 方法時參數(shù)聲明為 bytearray: JObject
在方法中:
var
PByteArr: PJByte //PJByte 是 JNI.pas 定義的, 里面還有 PJBoolean, PJObject, PJInt 等..
JVM: TJNIEnv;
isCopy: Boolean;
begin
JVM:= TJNIEnv.Create(PEnv);
isCopy := false;
PByteArr := JVM.GetByteArrayElements(bytearray, isCopy); //調(diào)用這個方法,可以將取得參數(shù) bytearray 的地址, isCopy 決定是否復制數(shù)組
//之后,我們可以通過 PByteArr 結(jié)合 inc(PByteArr) 這個指針來操作傳過來的數(shù)組.
end;
之前,我們學了如何用 Java 調(diào)用 Delphi 程序的一個方法
如果在Delphi 程序在適當時候需要調(diào)用 Java 程序,又要怎么做呢?
首先,我們先定義如下的 Java 類:
//------------------------------------------------------------------------------
package alvinJNI;
class HelloWorld {
static {
System.loadLibrary("DelphiAction");
}
String str = "你好";
public native void callPrintText(HelloWorld hw);
public void printText(String arg) {
System.out.println(arg);
}
public static void main(String[] args) {
HelloWorld hw = new HelloWorld();
hw.callPrintText(hw);
}
}
//-------------------------------------------------------------------------------
我們再像上次一樣在 Delphi 中建立 DLL 工程,寫下面的代碼(有注釋):
//-------------------------------------------------------------------------------
library DelphiAction;
uses
JNI;
//今天的這個程序稍微的復雜一點,因為要調(diào)用 Java 對象的方法,在這里可以學到對 JObject 的操作
procedure Java_alvinJNI_HelloWorld_callPrintText(PEnv: PJNIEnv; Obj: JObject; arg: JObject); stdcall;
var
JVM: TJNIEnv;
c: JClass; //類ID
fid: JFieldID; //屬性ID
mid: JMethodID; //方法ID
tmpStr: JString;
javaargs : array[0..0] of JValue; //調(diào)用方法時的參數(shù)
begin
JVM := TJNIEnv.Create(PEnv);
{我們先來看下如何獲得一個對象的某個屬性值}
{----------------------------------------}
{我們對 Java 對象的操作要選獲取這個對象的 ClassID,我們可以用下面的方法來取得.}
c := JVM.GetObjectClass(arg);
{我們先來獲取參數(shù) HelloWorld arg 對象的 String str 這個屬性的值
這里我們先要獲得這個屬性在它所在類中的屬性 ID }
fid := JVM.GetFieldID(c, 'str', 'Ljava/lang/String;');
{上面調(diào)用的這個方法中的參數(shù)分別是: 所屬類ID, 屬性名, 屬性類型簽名
關于屬性類型的簽名,將在下面 '說明1' 給出}
{下面,我們就可以根據(jù) 屬性ID 來獲取屬性值了, 這里我們會取得到 arg.str 這個字符串}
tmpStr := JVM.GetObjectField(arg, fid);
{上面的這個 JVM.GetObjectField(arg, fid) 用來獲取屬性值
參數(shù)分別是: 要取得其屬性的對象, 要取得的屬性的屬性ID
這里取得的是一個 Java 的 String 對象,是 JString,其實它也就是 JObject 類型的}
writeln('Delphi 輸出的: ' + JVM.UnicodeJStringToString(tmpStr));
{我們再來看下如何調(diào)用一個 JObject 的方法, 這里我們要調(diào)用的是 arg.printText() 這個方法}
{------------------------------------------------------------------------------------}
//我們還是要用到上面的那個 類ID: c.
//這一次我們要取得這個方法的 方法ID
mid := JVM.GetMethodID(c, 'printText', '(Ljava/lang/String;)V');
//上面調(diào)用的這個方法中的參數(shù)分別是: 所屬類ID, 方法名, 方法(參數(shù)+返回值)類型簽名
//關于方法(參數(shù)+返回值)類型的簽名,將在下面 '說明2' 給出
//有了 方法ID 后我們就可以用這個ID來調(diào)用這個方法了,我們這里要調(diào)用的方法是: arg.printText(參數(shù));
//因為我們要調(diào)用的這個方法有參數(shù), 調(diào)用 Java 方法的時候如果有參數(shù),要建立參數(shù)數(shù)組,這里我們就來建立數(shù)組
javaargs[0].l := tmpStr;
{這里這個 javaargs 是 JValue 類型. 它有點特殊,它的用法在下面 說明3 給出}
{有了 類象, 方法ID, 參數(shù). 下面我們就可以調(diào)用 arg.printText(javaargs) 這個方法了,使用下面這個方法就可實現(xiàn)}
JVM.CallObjectMethodA(arg, mid, @javaargs);
JVM.Free;
end;
exports
Java_alvinJNI_HelloWorld_callPrintText;
end.
//--------------------------------------------------------------------------------
到這里,我們已經(jīng)可以從 Delphi 中獲得 Java 對象的屬性了, 還可以調(diào)用一個 Java 對象的方法,是不是很酷呢?
你學到了沒?
###########################說明1###############################
現(xiàn)在,我們還要再了解一個獲取 "屬性ID" 時的那個簽名
上面例子中: fid := JVM.GetFieldID(c, 'str', 'Ljava/lang/String;'); 用的簽名是: 'Ljava/lang/String;'
因為剛剛要獲得的屬性是 java.lang.String 類型的,所以它的簽名是: 'Ljava/lang/String;'
如果,我們要獲得的屬性是其它類型,獲取 屬性ID 時又要怎樣簽名呢?下面給出一個對照表
byte -- B
char --- C
double -- D
float -- F
int -- I
long -- J (注意:是J不是L)
short -- S
void -- V
boolean - Z(注意:是Z不是B)
class(類對象類型) - 'L'+完整類名+';' (包路徑分隔符為: '/'. 如上面例子中的 String 對型, 簽名為: 'Ljava/lang/String;')
數(shù)組 type[] -- '['+type (例如 float[] 的簽名就是 '[float')
(如果是二維數(shù)組,如float[][],則簽名為 '[[float')
############################說明2###############################
現(xiàn)在,我們還要再了解一個獲取 "方法ID" 時的那個簽名
上面例子中: mid := JVM.GetMethodID(c, 'printText', '(Ljava/lang/String;)V'); 用的簽名是: '(Ljava/lang/String;)V'
方法ID 的簽名,分為兩部分
一部分是前面括號中的,是參數(shù)類型的簽名
另一部分是括號后的,是返回值類型的簽名
其中某個簽數(shù)與返回值的類型簽名與獲取屬性ID時的簽名是一樣的
上面要調(diào)用的方法只有一個參數(shù),如果有多個參數(shù)時又怎樣呢?
如: int getInt(long a, double b); 這樣的 Java 方法要這樣簽名: '(JD)I'
(注意:參數(shù)簽名是連續(xù)的,沒有分隔符, 這里第一個參數(shù) long 簽名為:J, 第二個參數(shù)簽名為: D, 返回值類型 int 簽名為: I)
說到這里,相信大家都會使用這個簽名了
############################說明3###############################
在調(diào)用一個 Java 方法時, 如果這個方法有參數(shù), 我們就要傳遞一個參數(shù)數(shù)組的地址給 Java
現(xiàn)在,我們還要再了解如何創(chuàng)建這樣的一個參數(shù)數(shù)組
傳遞給 Java 方法的參數(shù),類型均為 JValue. 它是一個packed record
如果,我們要調(diào)用的方法 void myMethod(int a, long b, String c); 有 3 個參數(shù)
那么
1.我們先要聲明如下數(shù)組:
var
args : array[0..1] of JValue;
2.給數(shù)組賦值
args[0].i := 100;
args[1].j := 100;
args[2].l := JVM.StringToJString(pchar(UTF8Encode('開源中國社區(qū) )));
3.調(diào)用
JVM.CallVoidMethodA(Java對象, 方法ID, @args);
JValue 是一個 packed record,它的定義如下:
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;
調(diào)用方法時,TJNIEnv 還有:
CallObjectMethodA: function(Env: PJNIEnv; Obj: JObject; MethodID: JMethodID; Args: PJValue): JObject; {$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}
CallByteMethodA: function(Env: PJNIEnv; Obj: JObject; MethodID: JMethodID; Args: PJValue): JByte; {$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}
CallShortMethodA: function(Env: PJNIEnv; Obj: JObject; MethodID: JMethodID; Args: PJValue): JShort; {$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}
CallLongMethodA: function(Env: PJNIEnv; Obj: JObject; MethodID: JMethodID; Args: PJValue): JLong; {$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}
CallDoubleMethodA: function(Env: PJNIEnv; Obj: JObject; MethodID: JMethodID; Args: PJValue): JDouble; {$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}
CallNonvirtualObjectMethodA: function(Env: PJNIEnv; Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: PJValue): JObject; {$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}
CallNonvirtualByteMethodA: function(Env: PJNIEnv; Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: PJValue): JByte; {$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}
CallNonvirtualShortMethodA: function(Env: PJNIEnv; Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: PJValue): JShort; {$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}
CallNonvirtualLongMethodA: function(Env: PJNIEnv; Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: PJValue): JLong; {$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}
CallNonvirtualDoubleMethodA: function(Env: PJNIEnv; Obj: JObject; AClass: JClass; MethodID: JMethodID; Args: PJValue): JDouble; {$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}
更多信息請查看IT技術專欄