java - 如何在Delphi中将String转换为PWideString以供JNA使用

标签 java string delphi dll jna

我正在Delphi中创建一个DLL,方法如下:

function teste3 : PWideString; stdcall;
  var
    _string : string;
  begin
    _string := 'teste';
    Result := PWideString(_string);
  end;

然后我尝试使用JAVA中的JNA lib来调用这个方法。 JAVA中调用该方法的代码如下:

System.out.println(TDLL.getInstance().teste3());

但是当调用的返回结果只有字符 t 时,文本的其余部分不会出现。

如何将 String 转换为 PWideString 而不丢失所有字符?

Obs:我也尝试返回 PWideChar 但结果是相同的。

最佳答案

Delphi 的 PWideString 类型是一个指向 WideString 的指针。如果你将这样一个指针返回给 Java,Java 将不知道如何处理它。您需要返回原始 PAnsiCharPWideChar (更喜欢后者,因为 Java 字符串是 Unicode),但是您需要处理一个问题 - 内存管理。

如果您返回一个指向静态分配字符串的指针,或者至少是一个比函数生命周期更长的动态分配字符串的指针,则可以直接返回指向字符数据的指针:

德尔福:

const
  _string : WideString = 'teste'; // or UnicodeString in D2009+

function teste3 : PWideChar; stdcall;
begin
  Result := PWideChar(_string);
end;

或者:

var
  _string : WideString; // or UnicodeString

function teste3 : PWideChar; stdcall;
begin
  _string = 'teste'
  Result := PWideChar(_string);
end;

Java:

public class TDLL extends Library {
  TDLL INSTANCE = (TDLL) Native.loadLibrary("myjnalib.dll", TDLL.class);
  public static TDLL getInstance() {
    return INSTANCE;
  }
  WString teste3();
}

System.out.println(TDLL.getInstance().teste3().toString());

但是,如果需要动态分配字符串,则必须释放同一 DLL 中的内存,否则将会泄漏。 Java 无法为您释放内存,因为它不知道内存是如何分配的。

要解决这个问题,您应该重新设计 DLL 函数以接受内存缓冲区作为输入,然后您可以使用 JNA 的 Memory Java 端的类。让DLL填充内存缓冲区,然后Java可以调用Memory.getString()将输出数据读入 native Java 字符串 的方法:

德尔福:

function teste3(buffer: PByte; bufsize: Integer) : Integer; stdcall;
var
  _string : WideString; // or UnicodeString
  MaxChars: Integer;
begin
  _string := 'teste';
  MaxChars := (bufsize div sizeof(WideChar)) - 1;
  StrLCopy(PWideChar(buffer), PWideChar(_string), MaxChars);
  Result := Min(Length(_string), MaxChars);
end;

Java:

public class TDLL extends Library {
  TDLL INSTANCE = (TDLL) Native.loadLibrary("myjnalib.dll", TDLL.class);
  public static TDLL getInstance() {
    return INSTANCE;
  }
  int teste3(Memory buf, int bufsize);
}

Memory buf = new Memory(10);
TDLL.getInstance().teste3(buf, buf.size());
System.out.println(buf.getString(0, true));

话虽这么说,您可能会考虑切换到 JNI(请参阅 Programming JNI with Delphi ),因为这样 DLL 就可以使用 Java 自己的内存管理器来动态分配和返回实际的 Java string 对象,并且然后Java可以根据需要正常释放它:

德尔福:

function Java_TDLL_test3(env: PJNIEnv; obj: JObject): JString; stdcall;
var
  _string : WideString; // or UnicodeString
begin
  _string := 'teste';
  Result := env^.NewString(env, PJChar(PWideChar(_string)), Length(_string));
end;

Java:

public class TDLL {
  static {
    System.loadLibrary("myjnalib");
  }

  public native string test3();
}

System.out.println(new TDLL().teste3());

关于java - 如何在Delphi中将String转换为PWideString以供JNA使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42964430/

相关文章:

regex - 获取包含给定子字符串的字符串的一部分

java - 如何等待 Java 中的多个任务完成?

java - 当您必须替换许多 fragment 时,保存 fragment 状态的最佳实践方法是什么?

java - 如何从G1 gc日志中提取关键信息

java - 将 JSON Builder 与集合结合使用

c - 为什么程序不读取第二个参数文件?

Swift 2 到 3 迁移 String.fromCString

德尔福线组件

Delphi注解+枚举集。不变的表达?

delphi - 通过编程方式更改子节点时,如何自动更新父节点的CheckState?