从 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"));