3

我是这里的新手,但是,我有一个“大问题”

我有一个 DLL(在 Delphi 中),我想通过 Java 访问它。如果您在 DLL 的“主体”(.dpr) 中使用简单的返回或过程,这很容易。但我需要使用接口,因为我想在桌面应用程序和 Web 应用程序(使用 java)中使用相同的代码。代码如下:

测试库文件

library TESTLIB;  
{$DEFINE TESTLIB}  

uses  
  System.SysUtils,  
  System.Classes,  
  TestInt in 'TestInt.pas';  

{$R *.res}  

function MyReturn(Test: PTest): PChar; stdcall;  
begin  
    Result := 'Im Here!';  
    Test^.vResult := 'Test 123';  
end;  

exports MyReturn;  

begin  
end.

接口TestInt.pas

unit TestInt;  

interface  

type  
  PTest = ^TTest;  
  TTest = record  
    vResult: PChar;  
  end;  

  {$IFNDEF TESTELIB}  
  function MyReturn(Test: PTest): PChar; stdcall;  
  {$ENDIF}  

implementation  

{$IFNDEF TESTELIB}  
function MyReturn; external 'TESTLIB.DLL' name 'MyReturn';  
{$ENDIF}  

end.

以及我如何使用 Delphi 中的一个简单应用程序访问它:

unit FormMain;  

interface  

uses  
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,   Vcl.Graphics,  
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;  

type  
  TForm1 = class(TForm)  
    Button1: TButton;  
    procedure Button1Click(Sender: TObject);  
  private  
    { Private declarations }  
  public  
    { Public declarations }  
  end;  

var  
  Form1: TForm1;  

implementation  

{$R *.dfm}  

uses TestInt;  //The interface

procedure TForm1.Button1Click(Sender: TObject);  
var  
  Test: TTest; //Type declared in Interface TestInt.pas  
begin  
    ShowMessage(MyReturn(@Test)); //Returns Im Here!  

    ShowMessage(Test.vResult); //Test 123  
end;  

end.

我想使用 Java 访问它(JNI、JNA 等......如果可以提供一个例子会更好)

非常感谢你们!

4

2 回答 2

3

一般来说,Delphi DLL(使用 stdcall 调用约定)的访问方式与访问 Win32 API 的方式相同。您应该能够通过检查 Delphi 类型的大小并用类似大小的 Java 类型替换它们来找出适当的类型映射。

PCHAR映射到 Java 字符串,因此您提供的“接口”看起来像这样:

public interface TestInt extends StdCallLibrary {
    TestInt INSTANCE = (TestInt)Native.loadLibrary("TestInt", TestInt.class);

    class Test extends Structure {
        public String vResult;
        public Test() { }
        public Test(Pointer p) { 
            super(p);
            read();
        }
        protected List getFieldOrder() { return Arrays.asList(new String[] { "vResult" }); }
    }

    String MyReturn(Test test);
}

请记住David关于返回字符串的警告;如果 delphi 分配了内存,它必须稍后释放内存,所以通常更容易让调用者 (Java) 传递分配的内存并让 delphi 简单地写入提供的缓冲区。

于 2013-03-25T18:30:42.040 回答
2

想在桌面应用程序和 Web 应用程序中使用相同的代码(使用 java)

代替使用 JNI/JNA 执行此任务,您的 Delphi 代码可以通过 HTTP Web 服务(例如 JSON/REST)而不是直接的进程内通信方法公开。对于基于 Delphi 的 Web 服务,您可以使用 Indy、Synapse 或为 IIS 构建 ISAPI DLL。然后,Java Web 应用程序充当 Web 服务客户端。它可以在许多操作系统上运行,而 JNI/JNA 要求这两个部分都在同一个目标上编译和运行。


更新:关于您的评论,如果速度非常重要,还有其他用于进程内通信的选项,例如共享内存映射文件和 IOCP,它们非常快。

但是我不认为基于套接字的解决方案会变慢。您可以在 Delphi 应用程序和 Java 进程之间创建直接套接字连接,并轻松地每秒传输数千条消息。如果消息在不到一毫秒的时间内没有处理,你确定会有问题吗?

Java 文档建议使用管道和套接字进行进程间通信:

为了促进进程之间的通信,大多数操作系统都支持进程间通信 (IPC) 资源,例如管道和套接字。IPC 不仅用于同一系统上的进程之间的通信,还用于不同系统上的进程之间的通信。

于 2013-03-25T15:50:50.670 回答