如何在 Delphi 中将 String 转换为 PWideString 以供 JNA 使用
How to convert String to PWideString in Delphi for JNA consumption
我在Delphi中创建一个DLL,方法是这样的:
function teste3 : PWideString; stdcall;
var
_string : string;
begin
_string := 'teste';
Result := PWideString(_string);
end;
然后我尝试使用 JAVA 中的 JNA 库调用此方法。 JAVA中调用方法的代码是这样的:
System.out.println(TDLL.getInstance().teste3());
但是当调用的 return 只是字符 t
时,其余文本不会出现。
如何在不丢失所有字符的情况下将 String
转换为 PWideString
?
Obs: 我也尝试 returning PWideChar 但结果是一样的。
Delphi 的 PWideString
类型是指向 WideString
的指针。如果你 return 这样一个指向 Java 的指针,Java 将不知道如何处理它。您需要 return 一个原始的 PAnsiChar
或 PWideChar
(更喜欢后者,因为 Java 字符串是 Unicode),但是您有一个问题要处理 - 内存管理。
如果您 return 一个指向静态分配的字符串的指针,或者至少是一个比函数还长的动态分配的字符串,您可以 return 一个直接指向字符数据的指针:
Delphi:
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
class on the Java side. Have the DLL fill the memory buffer, and then Java can call the Memory.getString()
方法将输出数据读入本机 Java string
:
Delphi:
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 自己的内存管理器来动态分配和 return一个实际的 Java string
对象,然后 Java 可以根据需要正常释放它:
Delphi:
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());
我在Delphi中创建一个DLL,方法是这样的:
function teste3 : PWideString; stdcall;
var
_string : string;
begin
_string := 'teste';
Result := PWideString(_string);
end;
然后我尝试使用 JAVA 中的 JNA 库调用此方法。 JAVA中调用方法的代码是这样的:
System.out.println(TDLL.getInstance().teste3());
但是当调用的 return 只是字符 t
时,其余文本不会出现。
如何在不丢失所有字符的情况下将 String
转换为 PWideString
?
Obs: 我也尝试 returning PWideChar 但结果是一样的。
Delphi 的 PWideString
类型是指向 WideString
的指针。如果你 return 这样一个指向 Java 的指针,Java 将不知道如何处理它。您需要 return 一个原始的 PAnsiChar
或 PWideChar
(更喜欢后者,因为 Java 字符串是 Unicode),但是您有一个问题要处理 - 内存管理。
如果您 return 一个指向静态分配的字符串的指针,或者至少是一个比函数还长的动态分配的字符串,您可以 return 一个直接指向字符数据的指针:
Delphi:
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
class on the Java side. Have the DLL fill the memory buffer, and then Java can call the Memory.getString()
方法将输出数据读入本机 Java string
:
Delphi:
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 自己的内存管理器来动态分配和 return一个实际的 Java string
对象,然后 Java 可以根据需要正常释放它:
Delphi:
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());