简体   繁体   English

从 Java 调用 DLL 写在 Delphi

[英]Call DLL written in Delphi from Java

I have a simple DLL written in Delphi 10.4.我有一个用 Delphi 10.4 编写的简单 DLL。 When I call the DLL from another Delphi application, everything works 100%, but when I call the same DLL from a Java application (using JNA) I get strange results. When I call the DLL from another Delphi application, everything works 100%, but when I call the same DLL from a Java application (using JNA) I get strange results.

I initially declared my DLL input parameters of type PChar.我最初声明了 PChar 类型的 DLL 输入参数。 When I call the DLL from the Java app, I get funny characters inside my DLL.当我从 Java 应用程序调用 DLL 时,我的 DLL 中出现了有趣的字符。 I changed it to ShortString, but then I loose the first character of the string in my DLL.我将其更改为 ShortString,但随后我丢失了 DLL 中字符串的第一个字符。 I probably need to do some datatype casting in Java but I cannot find out what.我可能需要在 Java 中进行一些数据类型转换,但我不知道是什么。 Can somebody perhaps help?有人可以帮忙吗?

Here is a sample DLL in Delphi to demonstrate:这是 Delphi 中的示例 DLL 来演示:

procedure TestDataTypes(PCharVar: PChar; ShortStringVar: ShortString); stdcall;
begin
  ShowMessage('PChar: ' + PCharVar + #13#10 +
              'ShortString: ' + ShortStringVar);
end;

exports
  TestDataTypes;

Code to call DLL from Delphi:从 Delphi 调用 DLL 的代码:

procedure TestDataTypes(PCharVar: PChar; ShortStringVar: ShortString); stdcall; external 'TestDataType.dll';
...
TestDataTypes(PChar('PChar Value'), 'ShortString Value');

Code to call DLL from Java:从 Java 调用 DLL 的代码:

INSTANCE.TestDataTypes("Java PChar Value", "Java ShortString Value");

Results: Top is when DLL is called from Delphi and bottom when it is called from Java:结果:顶部是从 Delphi 调用 DLL 时,底部是从 Java 调用时: 在此处输入图像描述

Some Feedback: I changed the datatype in Delphi to PAnsiChar and it works on my local pc.一些反馈:我将 Delphi 中的数据类型更改为 PAnsiChar,它可以在我的本地电脑上运行。 When deployed, it worked on some client machines but not others.部署后,它可以在某些客户端机器上工作,但不能在其他机器上工作。 The error I get when I call the DLL from my Java app is "Invalid memory access".当我从我的 Java 应用程序调用 DLL 时得到的错误是“无效的 memory 访问”。 I have added logging in my DLL and it seems it does not even enter the DLL.... I have also changed the Java datatype to WString but that did not make a difference.我已经在我的 DLL 中添加了日志记录,它似乎甚至没有进入 DLL....

Delphi code: Delphi 代码:

function HasCOMConnection(COMServerName: PAnsiChar): Boolean; stdcall;
begin
  WriteLog('HasCOMConnection: 64-Bit DLL entered');
  Result := HasConnection(COMServerName);
end;

Java Call: 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 is only an alias, which was changed to PWideChar with Delphi 2009 (let's just say, standard string and character types were changed to Unicode ). PChar只是一个别名,在 2009 年使用 Delphi 更改为PWideChar (假设标准字符串和字符类型更改为Unicode )。 So every character does now use 2 Bytes.所以现在每个字符都使用 2 个字节。

So in order to make your DLL working as it should, you should change PChar to PAnsiChar .因此,为了使您的 DLL 正常工作,您应该将PChar更改为PAnsiChar
Or you have to make some changes to your Java app so it does use some two-byte-character type.或者您必须对您的 Java 应用程序进行一些更改,以便它使用一些两字节字符类型。 But I have no Java experience, so I can't help you with that.但是我没有 Java 的经验,所以我帮不了你。

And forget about shortstring, this type is not compatible to other languages!忘记短字符串,这种类型与其他语言不兼容!

See this site for more references about how to use and not to use DLLs.有关如何使用和不使用 DLL 的更多参考信息,请参阅站点。

ShortString is an old Delphi type that holds an ANSI string and stores the length in the first byte. ShortString是一个旧的 Delphi 类型,它包含一个 ANSI 字符串并将长度存储在第一个字节中。 You shouldn't use it.你不应该使用它。

PChar , in recent versions of Delphi, is an alias for PWideChar . PChar在最新版本的 Delphi 中是PWideChar的别名。

You are using JNA to call native code from Java.您正在使用JNA从 Java 调用本机代码。

A Java String internally uses UTF-16. Java String在内部使用 UTF-16。

JNA uses the following rules: JNA 使用以下规则:

  • A String is converted to PAnsiCharString转换为PAnsiChar
  • A WString is converted to PWideChar WString被转换为PWideChar

So, if you want to pass a Unicode string to the DLL, you should declare the Java method like this:因此,如果您想将 Unicode 字符串传递给 DLL,您应该像这样声明 Java 方法:

public void TestString(WString text);

And in Delphi:在 Delphi 中:

procedure TestString(Text: PChar); stdcall;
begin
    ShowMessage(Text);
end;

And call the function like this:并像这样调用 function:

INSTANCE.TestString(new WString("A Unicode string"));

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

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