How can I call a Delphi function that returns a string using JNA?

I'm working on calling functions from a Delphi compiled *.so file from a Java program. After some research it seems like JNA is he way to go. Before diving into some complex Delphi code, I'm trying to play with some "Hello World" code but am having trouble getting a string returned by a Delphi function.

The Delphi code (helloworld.pp):

library HelloWorldLib;

function HelloWorld(const myString: string): string; stdcall;
begin
  WriteLn(myString);
  Result := myString;
end;

exports HelloWorld;

begin
end.

I compile it from the command line with " fpc -Mdelphi helloworld.pp ", which produces libhelloworld.so .

Now my Java class:

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"));
    }
}

However when I run this Java code I get:

# 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

Note that if I change my Delphi method (and the associated Java interface) to return a hardcoded integer, everything works great: the string I pass gets printed and I get the int back as expected.

Strangely enough, if the Delphi method returns a char, I have to write my JNA proxy as returning a byte and cast it to char manually (if I declare my interface as returning a char it prints out a garbage character).

Any idea what is going wrong here?

FYI, I'm on Ubuntu 12.04, 64bits, using Sun JDK 1.7.0_10-b18, JNA 3.5.1 and Free Pascal Compiler version 2.4.4-3.1.


A Delphi or FreePascal string is a managed type that cannot be used as a JNA type. The JNA documentation explains that Java String is mapped to a pointer to a null-terminated array of 8 bit characters. In Delphi terms that is PAnsiChar .

So you can change the input parameter in your Pascal code from string to PAnsiChar .

The return value is more problematic. You will need to decide who allocates the memory. And whoever allocates it must also free it.

If the native code is responsible for allocating it then you'd need to heap allocate the null-terminated string. And return a pointer to it. You'd also need to export a deallocator so that the Java code can ask the native code to deallocate the heap allocated block of memory.

It is usually more convenient to allocate a buffer in the Java code. Then pass that to the native code and let it fill out the content of the buffer. This Stack Overflow question illustrates the technique, using the Windows API function GetWindowText as its example: How can I read the window title with JNI or JNA?

An example of this using Pascal would be like so:

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;

On the Java side, I guess the code would look like this, bearing in mind that I know absolutely nothing about 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);

Besides that, using stdcall on 64-bit Linux is not entirely logical either. It probably works, since there usually is only one calling convention on a 64-bit target, but correct, it isn't. Use cdecl;

链接地址: http://www.djcxy.com/p/61496.html

上一篇: 在Delphi中将UnicodeString附加到WideString

下一篇: 我怎样才能调用一个使用JNA返回字符串的Delphi函数?