从 Java 调用用 Delphi 编写的 DLL
Call DLL written in Delphi from Java
我有一个用 Delphi 10.4 编写的简单 DLL。当我从另一个 Delphi 应用程序调用 DLL 时,一切正常 100%,但是当我从 Java 应用程序(使用 JNA)调用同一个 DLL 时,我得到了奇怪的结果。
我最初声明了 PChar 类型的 DLL 输入参数。当我从 Java 应用程序调用 DLL 时,我的 DLL 中出现了一些有趣的字符。我将其更改为 ShortString,但随后我在 DLL 中丢失了字符串的第一个字符。我可能需要在 Java 中进行一些数据类型转换,但我不知道是什么。有人可以帮忙吗?
下面是 Delphi 中的示例 DLL 来演示:
procedure TestDataTypes(PCharVar: PChar; ShortStringVar: ShortString); stdcall;
begin
ShowMessage('PChar: ' + PCharVar + #13#10 +
'ShortString: ' + ShortStringVar);
end;
exports
TestDataTypes;
从 Delphi:
调用 DLL 的代码
procedure TestDataTypes(PCharVar: PChar; ShortStringVar: ShortString); stdcall; external 'TestDataType.dll';
...
TestDataTypes(PChar('PChar Value'), 'ShortString Value');
从 Java 调用 DLL 的代码:
INSTANCE.TestDataTypes("Java PChar Value", "Java ShortString Value");
结果:顶部是从 Delphi 调用 DLL 时的情况,底部是从 Java 调用时的情况:
一些反馈:
我将 Delphi 中的数据类型更改为 PAnsiChar,它可以在我的本地电脑上运行。部署后,它可以在某些客户端计算机上运行,但不能在其他计算机上运行。
当我从我的 Java 应用程序调用 DLL 时得到的错误是“无效的内存访问”。我已经在我的 DLL 中添加了日志记录,它似乎甚至没有进入 DLL....
我还将 Java 数据类型更改为 WString 但这并没有什么不同。
Delphi代码:
function HasCOMConnection(COMServerName: PAnsiChar): Boolean; stdcall;
begin
WriteLog('HasCOMConnection: 64-Bit DLL entered');
Result := HasConnection(COMServerName);
end;
Java 通话:
private interface IPMOProcessLabResult extends com.sun.jna.Library {
boolean HasCOMConnection(String COMServerName);
}
private boolean canConnectToCOMServer() {
try {
IPMOProcessLabResult lib = (IPMOProcessLabResult) Native.loadLibrary(config.libraryName, IPMOProcessLabResult.class);
return lib.HasCOMConnection(config.comServerName);
}
catch (Exception ex) {
new AppendLog(new Date(), this.getClass() + "\t" + ex.getClass() + "\t" + "Exception while trying to connect to COMServer: " + ex.getMessage(), "debug");
return false;
}
}
PChar
只是一个别名,2009年Delphi改成了PWideChar
(这么说吧,标准字符串和字符类型改成了Unicode
) !所以每个字符现在确实使用 2 个字节。
因此,为了让您的 DLL 正常工作,您应该将 PChar
更改为 PAnsiChar
。
或者您必须对 Java 应用程序进行一些更改,以便它使用某些双字节字符类型。但是我没有 Java 经验,所以我无法帮助你。
忘记短字符串,这种类型与其他语言不兼容!
有关如何使用和不使用 DLL 的更多参考,请参阅 this 站点。
ShortString
是一个旧的 Delphi 类型,它保存一个 ANSI 字符串并将长度存储在第一个字节中。你不应该使用它。
PChar
,在 Delphi 的最新版本中,是 PWideChar
.
的别名
您正在使用 JNA 从 Java 调用本机代码。
A Java String
内部使用 UTF-16。
JNA 使用以下规则:
- 一个
String
转换为PAnsiChar
- 一个
WString
转换为PWideChar
因此,如果您想将 Unicode 字符串传递给 DLL,您应该像这样声明 Java 方法:
public void TestString(WString text);
在Delphi中:
procedure TestString(Text: PChar); stdcall;
begin
ShowMessage(Text);
end;
并像这样调用函数:
INSTANCE.TestString(new WString("A Unicode string"));
我有一个用 Delphi 10.4 编写的简单 DLL。当我从另一个 Delphi 应用程序调用 DLL 时,一切正常 100%,但是当我从 Java 应用程序(使用 JNA)调用同一个 DLL 时,我得到了奇怪的结果。
我最初声明了 PChar 类型的 DLL 输入参数。当我从 Java 应用程序调用 DLL 时,我的 DLL 中出现了一些有趣的字符。我将其更改为 ShortString,但随后我在 DLL 中丢失了字符串的第一个字符。我可能需要在 Java 中进行一些数据类型转换,但我不知道是什么。有人可以帮忙吗?
下面是 Delphi 中的示例 DLL 来演示:
procedure TestDataTypes(PCharVar: PChar; ShortStringVar: ShortString); stdcall;
begin
ShowMessage('PChar: ' + PCharVar + #13#10 +
'ShortString: ' + ShortStringVar);
end;
exports
TestDataTypes;
从 Delphi:
调用 DLL 的代码procedure TestDataTypes(PCharVar: PChar; ShortStringVar: ShortString); stdcall; external 'TestDataType.dll';
...
TestDataTypes(PChar('PChar Value'), 'ShortString Value');
从 Java 调用 DLL 的代码:
INSTANCE.TestDataTypes("Java PChar Value", "Java ShortString Value");
结果:顶部是从 Delphi 调用 DLL 时的情况,底部是从 Java 调用时的情况:
一些反馈: 我将 Delphi 中的数据类型更改为 PAnsiChar,它可以在我的本地电脑上运行。部署后,它可以在某些客户端计算机上运行,但不能在其他计算机上运行。 当我从我的 Java 应用程序调用 DLL 时得到的错误是“无效的内存访问”。我已经在我的 DLL 中添加了日志记录,它似乎甚至没有进入 DLL.... 我还将 Java 数据类型更改为 WString 但这并没有什么不同。
Delphi代码:
function HasCOMConnection(COMServerName: PAnsiChar): Boolean; stdcall;
begin
WriteLog('HasCOMConnection: 64-Bit DLL entered');
Result := HasConnection(COMServerName);
end;
Java 通话:
private interface IPMOProcessLabResult extends com.sun.jna.Library {
boolean HasCOMConnection(String COMServerName);
}
private boolean canConnectToCOMServer() {
try {
IPMOProcessLabResult lib = (IPMOProcessLabResult) Native.loadLibrary(config.libraryName, IPMOProcessLabResult.class);
return lib.HasCOMConnection(config.comServerName);
}
catch (Exception ex) {
new AppendLog(new Date(), this.getClass() + "\t" + ex.getClass() + "\t" + "Exception while trying to connect to COMServer: " + ex.getMessage(), "debug");
return false;
}
}
PChar
只是一个别名,2009年Delphi改成了PWideChar
(这么说吧,标准字符串和字符类型改成了Unicode
) !所以每个字符现在确实使用 2 个字节。
因此,为了让您的 DLL 正常工作,您应该将 PChar
更改为 PAnsiChar
。
或者您必须对 Java 应用程序进行一些更改,以便它使用某些双字节字符类型。但是我没有 Java 经验,所以我无法帮助你。
忘记短字符串,这种类型与其他语言不兼容!
有关如何使用和不使用 DLL 的更多参考,请参阅 this 站点。
ShortString
是一个旧的 Delphi 类型,它保存一个 ANSI 字符串并将长度存储在第一个字节中。你不应该使用它。
PChar
,在 Delphi 的最新版本中,是 PWideChar
.
您正在使用 JNA 从 Java 调用本机代码。
A Java String
内部使用 UTF-16。
JNA 使用以下规则:
- 一个
String
转换为PAnsiChar
- 一个
WString
转换为PWideChar
因此,如果您想将 Unicode 字符串传递给 DLL,您应该像这样声明 Java 方法:
public void TestString(WString text);
在Delphi中:
procedure TestString(Text: PChar); stdcall;
begin
ShowMessage(Text);
end;
并像这样调用函数:
INSTANCE.TestString(new WString("A Unicode string"));