我怎样才能调用一个使用JNA返回字符串的Delphi函数?
我正在从Java程序的Delphi编译* .so文件中调用函数。 经过一番研究,看起来JNA是他的出路。 在深入研究一些复杂的Delphi代码之前,我正在尝试使用一些“Hello World”代码,但无法获得由Delphi函数返回的字符串。
Delphi代码(helloworld.pp):
library HelloWorldLib;
function HelloWorld(const myString: string): string; stdcall;
begin
WriteLn(myString);
Result := myString;
end;
exports HelloWorld;
begin
end.
我使用“ fpc -Mdelphi helloworld.pp ”从命令行编译它,它生成libhelloworld.so 。
现在我的Java类:
import com.sun.jna.Library;
import com.sun.jna.Native;
public class HelloWorld {
public interface HelloWorldLibrary extends Library {
HelloWorldLibrary INSTANCE = (HelloWorldLibrary) Native.loadLibrary("/full/path/to/libhelloworld.so", HelloWorldLibrary.class);
String HelloWorld(String test);
}
public static void main(String[] args) {
System.out.println(HelloWorldLibrary.INSTANCE.HelloWorld("QWERTYUIOP"));
}
}
但是,当我运行这个Java代码时,我得到:
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x00007f810318add2, pid=4088, tid=140192489072384
#
# JRE version: 7.0_10-b18
# Java VM: Java HotSpot(TM) 64-Bit Server VM (23.6-b04 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# C [libhelloworld.so+0xbdd2] HelloWorld+0x6fea
请注意,如果我更改我的Delphi方法(以及相关的Java接口)以返回硬编码整数,那么所有工作都很好:我传递的字符串被打印出来,并按照预期返回int。
奇怪的是,如果Delphi方法返回一个字符,我必须编写我的JNA代理作为返回一个字节,并手动将其强制转换为字符(如果我声明我的接口返回一个字符它打印出一个垃圾字符)。
任何想法在这里出了什么问题?
仅供参考,我在Ubuntu 12.04,64位上使用Sun JDK 1.7.0_10-b18,JNA 3.5.1和Free Pascal Compiler 2.4.4-3.1版。
Delphi或FreePascal string
是一种不能用作JNA类型的托管类型。 JNA文档解释说Java String
被映射到一个指向以8位字符为空的终止数组的指针。 德尔福的条款是PAnsiChar
。
因此,您可以将Pascal代码中的输入参数从string
更改为PAnsiChar
。
返回值更成问题。 您需要决定谁分配内存。 分配它的人也必须释放它。
如果本机代码负责分配它,那么你需要堆分配空终止的字符串。 并返回一个指针。 您还需要导出释放器,以便Java代码可以请求本机代码释放分配给堆的内存块。
在Java代码中分配缓冲区通常更方便。 然后将其传递给本机代码,并让它填写缓冲区的内容。 这个堆栈溢出问题说明了使用Windows API函数GetWindowText
作为示例的技术:如何使用JNI或JNA读取窗口标题?
这种使用Pascal的例子会是这样的:
function GetText(Text: PAnsiChar; Len: Integer): Integer; stdcall;
const
S: AnsiString = 'Some text value';
begin
Result := Length(S)+1;//include null-terminator
if Len>0 then
StrPLCopy(Text, S, Len-1);
end;
在Java方面,我猜这个代码看起来像这样,记住我对Java一无所知。
public interface MyLib extends StdCallLibrary {
MyLib INSTANCE = (MyLib) Native.loadLibrary("MyLib", MyLib.class);
int GetText(byte[] lpText, int len);
}
....
int len = User32.INSTANCE.GetText(null);
byte[] arr = new byte[len];
User32.INSTANCE.GetText(arr, len);
String Text = Native.toString(arr);
除此之外,在64位Linux上使用stdcall也不完全合乎逻辑。 它可能有效,因为在64位目标上通常只有一个调用约定,但是正确的,不是。 使用cdecl;
链接地址: http://www.djcxy.com/p/61495.html上一篇: How can I call a Delphi function that returns a string using JNA?