&引用;无效内存访问“;从Java调用Delphi DLL时
我们有一个用Delphi编写的DLL,由Java应用程序调用。最初,我们在使用PChar或ShortString时遇到了问题,但我们将其改为PAnsiChar,所有问题似乎都得到了解决 然而,当我们开始将DLL部署到客户端时,大约50%的安装会出现以下错误:内存访问无效 DLL中的第一行是写入日志文件,但这并没有发生,这表明Delphi和Java数据类型之间存在问题。有没有人知道哪些Delphi和Java数据类型可以很好地协同工作 Delphi DLL代码:&引用;无效内存访问“;从Java调用Delphi DLL时,java,delphi,dll,Java,Delphi,Dll,我们有一个用Delphi编写的DLL,由Java应用程序调用。最初,我们在使用PChar或ShortString时遇到了问题,但我们将其改为PAnsiChar,所有问题似乎都得到了解决 然而,当我们开始将DLL部署到客户端时,大约50%的安装会出现以下错误:内存访问无效 DLL中的第一行是写入日志文件,但这并没有发生,这表明Delphi和Java数据类型之间存在问题。有没有人知道哪些Delphi和Java数据类型可以很好地协同工作 Delphi DLL代码: function HasCOMCon
function HasCOMConnection(COMServerName: PAnsiChar): Boolean; stdcall;
begin
WriteLog('HasCOMConnection: DLL entered');
Result := HasConnection(COMServerName);
end;
exports
HasCOMConnection;
从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;
}
}
根据,当传递到本机代码时,Java字符串
将转换为const char*
:
JavaString
s执行与本机类型const char*
和const wchar\u t*
相同的功能(NUL终止数组)。为了在调用本机函数时使用正确的类型,我们必须引入某种注释来确定javaString
应该如何转换JavaString
s通常转换为char*
,因为这是字符串最常见的用法。字符串在函数调用中自动转换为以NUL结尾的char
数组。如果方法签名返回String
(strdup
),则返回的char*
值将自动复制到字符串中
因此,当按原样传递字符串时,在Delphi端使用PAnsiChar
是正确的
但是,Delphi 2009+中的Delphi字符串与Java字符串一样,本机编码为UTF-16。因此,在Java端使用WString
会更有效(或者至少不会有数据丢失的风险):
WString
类用于标识宽字符串。Unicode值直接从Java字符数组复制到本机wchar\t
数组
并在Delphi端使用PWideChar
进行匹配,例如:
函数HasCOMConnection(COMServerName:PWideChar):布尔值;stdcall;
专用接口IPMOProcessLabResult扩展com.sun.jna.Library{
布尔HasCOMConnection(WString-COMServerName);
}
话虽如此,您的代码还有另外两个问题
根据相同的JNA文档,Javaboolean
映射到本机int
,而不是bool
,因此您的Delphi代码需要使用Integer
(或Int32
)或更好的LongBool
,例如:
函数HasCOMConnection(COMServerName:PAnsiChar{or PWideChar}):LongBool;stdcall;
更重要的是,如果本机库使用stdcall
调用约定,则必须从扩展IPMOProcessLabResult
,例如:
专用接口IPMOProcessLabResult扩展com.sun.jna.StdCallLibrary
否则,如果从com.sun.jna.Library
扩展,则需要在本机端使用cdecl
:
函数HasCOMConnection(COMServerName:PAnsiChar{or PWideChar}):LongBool;cdecl;
您是否阅读了上一个问题和我的答案下面的评论?从中我可以看出,Java字符串和Delphi PAnsiChar不兼容!PAnsiChar是一个指向C风格的每字符一字节数组/字符串的指针据我所知,Java字符串使用16位字符,就像Delphi字符串一样。所以乍一看,在Delphi端使用Char和PChar。只有非常旧的Delphi版本使用8位字符。您使用哪种Delphi版本?(编辑您的问题以添加详细信息)。@fpiette他使用Delphi 10.4确保您的本机代码不会引发任何未经处理的异常。这不只是stdcall vs cdecl吗?另外,我怀疑它应该是Delphi端的LongBool
,我会质疑boolean
映射。我希望它在Delphi中映射到一个4字节的Windows布尔值,LongBool
。@DavidHeffernan谢谢,已更新