java - 如何使用 JNA 调用返回字符串的 Delphi 函数?

标签 java string delphi jna freepascal

我正在研究从 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 接口(interface))以返回一个硬编码的整数,一切都会很好:打印我传递的字符串并按预期返回 int。

奇怪的是,如果 Delphi 方法返回一个 char,我必须将我的 JNA 代理编写为返回一个字节并手动将其转换为 char(如果我将我的接口(interface)声明为返回一个 char,它会打印出一个垃圾字符)。

知道这里出了什么问题吗?

仅供引用,我在 Ubuntu 12.04 64 位上使用 Sun JDK 1.7.0_10-b18、JNA 3.5.1 和 Free Pascal 编译器版本 2.4.4-3.1。

最佳答案

Delphi 或 FreePascal string 是一种托管类型,不能用作 JNA 类型。 JNA documentation解释了 Java String 被映射到指向一个以 null 结尾的 8 位字符数组的指针。在 Delphi 中,它是 PAnsiChar

因此,您可以将 Pascal 代码中的输入参数从 string 更改为 PAnsiChar

返回值比较有问题。您将需要决定谁分配内存。分配它的人也必须释放它。

如果 native 代码负责分配它,那么您需要堆分配以 null 结尾的字符串。并返回指向它的指针。您还需要导出一个解除分配器,以便 Java 代码可以要求 native 代码解除分配堆分配的内存块。

在 Java 代码中分配缓冲区通常更方便。然后将其传递给 native 代码并让它填充缓冲区的内容。这个 Stack Overflow 问题以 Windows API 函数 GetWindowText 为例说明了该技术:How can I read the window title with JNI or 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);

关于java - 如何使用 JNA 调用返回字符串的 Delphi 函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14057226/

相关文章:

delphi - TApplication.MainFormOnTaskbar 版本要求

java - 什么是NullPointerException,我该如何解决?

java - 如何将 glassfish 4 eclipse 项目与 glassfish 运行时重新关联?

java - 安装 Parquet 工具

c++ - 如何在 C/C++ 中(取消)转义字符串?

delphi - SetWindowsHookEx WH_MOUSE 在 Win7 中断点卡住

Java GUI DiceRoll 应用程序

java - 在java中连接2个二维数组?

javascript string exec奇怪的行为

windows - 应用程序如何在 Delphi 中关闭后启动自己的服务?