繁体   English   中英

从 Java 调用 Delphi DLL 时出现“memory 访问无效”

[英]"Invalid memory access" when calling Delphi DLL from Java

我们有一个 DLL,写在 Delphi 中,被 Java 应用程序调用。 最初我们在使用 PChar 或 ShortString 时遇到问题,但我们将它们更改为 PAnsiChar,所有问题似乎都已解决。

但是,当我们开始将 DLL 部署到我们的客户端时,大约 50% 的安装会出现以下错误:memory 访问无效。

DLL 中的第一行是写入我们的日志文件,但这并没有发生,这表明 Delphi 和 Java 数据类型之间存在问题。 有没有人知道 Delphi 和 Java 数据类型可以很好地协同工作?

Delphi DLL 代码:

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 JNA 文档,Java String在传递给本机代码时转换为const char*

Java String执行与本机类型const char*const wchar_t* (NUL 终止数组)相同的 function。 为了在调用本机 function 时使用正确的类型,我们必须引入某种注释来标识 java String应如何转换。 Java String通常会转换为char* ,因为这是字符串最常见的用法。 在 function 调用中,字符串会自动转换为以 NUL 结尾的char数组。 如果方法签名返回String (例如strdup ),则返回的char*值会自动复制到String中。

因此,按原样传递String时,在 Delphi 端使用PAnsiChar是正确的。

但是,Delphi 中的 Delphi 2009+ 字符串与 Java 字符串一样以 UTF-16 进行本地编码。 因此,在 Java 端使用WString会更有效(或者至少没有数据丢失的风险):

WString class 用于标识宽字符串。 Unicode 值直接从 Java char 数组复制到本机wchar_t数组。

并在Delphi端使用PWideChar进行匹配,eg:

function HasCOMConnection(COMServerName: PWideChar): Boolean; stdcall;
private interface IPMOProcessLabResult extends com.sun.jna.Library {
    boolean HasCOMConnection(WString COMServerName);
}

话虽如此,您的代码还有另外两个问题。

根据相同的 JNA 文档,a Java boolean映射到本机int ,而不是bool ,因此您的 Delphi 代码需要使用Integer (或Int32 )或更好的LongBool ,例如:

function HasCOMConnection(COMServerName: PAnsiChar{or PWideChar}): LongBool; stdcall;

更重要的是,如果本机库使用stdcall调用约定,则必须从com.sun.jna.win32.StdCallLibrary扩展IPMOProcessLabResult ,例如:

private interface IPMOProcessLabResult extends com.sun.jna.StdCallLibrary

否则,如果您从com.sun.jna.Library扩展,那么您需要在本机端使用cdecl

function HasCOMConnection(COMServerName: PAnsiChar{or PWideChar}): LongBool; cdecl;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM