5

我的应用程序必须提供从外部 DLL 调用不同函数和过程的能力。所以我们不知道参数的数量和它们的类型。我应该怎么做?

让我再解释一下。我的应用程序是一个 RAD 工具,它有自己的脚本和语法……我想让用户使用任何dll 文件并调用他们想要的任何函数或过程。我不能使用调用dll(LoadLibrary然后GetProcAddress)的简单方法,因为我不知道GetProcAddress引用的是什么类型(var Proc:procedure (A:??;B:??;...))。

4

4 回答 4

5

我的 ZGameEditor 项目的脚本功能中有一个 Delphi 实现,在下面的文件中搜索“TExpExternalFuncCall.Execute”:

http://code.google.com/p/zgameeditor/source/browse/trunk/ZExpressions.pas

在 Windows(x86 和 x64)、Linux、Android (ARM) 和 OS X (x86) 下测试和工作。处理 stdcall 和 cdecl 调用约定。

但是 libFFI 可能比我的实现更通用,所以我会推荐这种方法。

于 2011-03-19T13:08:08.673 回答
4

这是一个可以在我的机器上运行的简单示例,但我不是该主题的专家。

procedure TForm4.Button1Click(Sender: TObject);
var
  hmod: HMODULE;
  paddr: pointer;         
  c1, c2, ret: cardinal;
begin
  c1 := 400; //frequency
  c2 := 2000; // duration

  hmod := LoadLibrary('kernel32'); // Of course, the name of the DLL is taken from the script
  if hmod <> 0 then
    try
      paddr := GetProcAddress(hmod, 'Beep'); // ...as is the name of the exported function
      if paddr <> nil then
      begin
        // The script is told that this function requires two cardinals as
        // arguments. Let's call them c1 and c2. We will assume stdcall
        // calling convention. We will assume a 32-bit return value; this
        // we will store in ret.
        asm
          push c2
          push c1
          call [paddr]
          mov ret, eax
        end;
      end;
    finally
      FreeLibrary(hmod);
    end;
end;
于 2011-03-18T22:13:11.610 回答
3

您所描述的内容被称为外部功能接口(FFI),并非出于虚心。

我不建议您尝试从头开始开发自己的 FFI。FFI 的一个非常常见的选择是libffi

libffi的维基百科页面列出了以下项目作为 libffi 的用户:

Python、Dalvik、F-Script、PyPy、PyObjC、RubyCocoa、JRuby、Rubinius、MacRuby、gcj、GNU Smalltalk、IcedTea、Cycript、Pawn、Squeak、Java Native Access、PLT Scheme、Embeddable Common Lisp 和 Mozilla。

我个人通过我的 Delphi DLL 的 Python/ctypes 接口广泛使用 libffi,尽管幸运的是 Python/ctypes 将它包装在相当高的水平。

如果我按照您描述的路线出发,我会强烈考虑使用 libffi。如果您采用这条路线,则必须做一些工作才能从 Delphi 使用它,因为它是用 C/asm 编写的。

于 2011-03-18T22:09:12.333 回答
3

正如 David H 所说,关于 FFI,它几乎不适合胆小的人。

但是,您可以使用源代码,例如 FFI 的 Python ctypes 扩展模块,作为有关 libFFI (ctypes) 如何绑定到特定语法(在本例中为 python)的信息源。Python 源代码及其标准模块非常易读。

以下是在 Python 中使用 David 提到的库的示例:

http://code.activestate.com/recipes/146847/

由于 python(C 语言)的源代码可用,并且 Python 本身可以是 Delphi 中的扩展,因此您可以使用它开始。如果您准备编写自己的完整动态语言(作为 RAD 工具的一部分),那么您也可以应对 FFI 的挑战。

我个人并没有准备好从头开始发明一种完整、可行的编程语言及其所有库,所以我更喜欢将我所知道的东西混合在一起。C 或 Delphi 中的本机代码,以及 Python 中的动态脚本。您可以根据需要轻松地将所有三个组合到一个应用程序中。

于 2011-03-19T03:04:21.820 回答