delphi - 编写要从 gcc 应用程序调用的 Delphi/FreePascal DLL

标签 delphi dll gcc freepascal shared-libraries

我需要将我的部分 Win32 Delphi 应用程序提供给另一家公司的 Linux gcc 程序。

吞吐量和部署要求使任何类型的远程服务都不合适,因此我正在考虑使用 FreePascal 构建 gcc 应用程序可以调用的 .SO(Linux 等效的 DLL)。

自从我使用 C/C++ 并且从未在 Linux 上使用过很长时间了,所以我有点不确定如何最好地构建 DLL/SO 接口(interface)以与 gcc 调用者兼容。

这是我的数据结构的表示

TFoo = record
  x, y : double;
  a : smallint;
  b : string;
end;

TBar = record
  a : double;
  b : longint;
  c : string;
end;

TFooBar = record
  foo : array of TFoo;
  bar : array of TBar;
end;

procedure Process(const inFooBar : TFooBar);

要通过 FreePascal 使此 Process 方法在外部可用。所以我需要如何修改这些声明?我在想一些事情
TFoo = record
  x, y : double;
  a : smallint;
  b : PChar;
end;

TBar = record
  a : double;
  b : longint;
  c : PChar;
end;

TFooBar = record
  foo : ^TFoo;
  foo_count : longint;
  bar : ^TBar;
  bar_count : longint;
end;

procedure Process(const inFooBar : TFooBar);

我在正确的轨道上吗?我不必完全正确,其他公司的程序员很可能会纠正我的错误。我只是不想让他们看到我发给他们的东西时笑得太厉害。

最佳答案

使用PAnsiChar而不是 PChar , 和 integer而不是 longint/smallint (由于您使用对齐的记录,因此使用 smallint 字段没有任何好处)。

定义一些指针类型,如 PFooPBar , 这将比 ^TFoo 写得更好例如

如果你需要访问一些数组,你可以定义 TFooArrayTBarArray ,如下面的代码所示。

不要忘记 cdeclstdcall任何函数/过程的调用约定。

type
TFoo = record
  x, y : double;
  a : integer;
  b : PAnsiChar;
end;

TBar = record
  a : double;
  b : integer;
  c : PAnsiChar;
end;

TFooArray = array[0..maxInt div sizeof(TFoo)-1] of TFoo;
TBarArray = array[0..maxInt div sizeof(TBar)-1] of TBar;

PBar = ^TBar;
PFoo = ^TFoo;
PFooArray = ^TFooArray;
PBarArray = ^TBarArray;

TFooBar = record
  foo : PFooArray;
  foo_count : integer;
  bar : PBarArray;
  bar_count : integer;
end;

procedure Process(const inFooBar : TFooBar); cdecl; external 'ProcessGCCLibrary.so';

您的进程将是只读的吗?

如果 C 部分需要添加一些项,则必须向外部库提供一些内存重新分配方法,至少映射 reallocmem() .

请注意,Delphi 动态数组可以很容易地映射到 C 兼容结构中,如下所示:
type
  TFooDynArray: array of TFoo;
  TBarDynArray: array of TBar;

procedure CallProcess(const aFoo: TFooDynArray; const aBar: TBarDynArray);
var tmp: TFooBar;
begin
  tmp.foo := pointer(aFoo);
  tmp.foo_count := length(aFoo);
  tmp.bar := pointer(aBar);
  tmp.bar_count := length(aBar);
  Process(tmp);
end;

这可以使您的 Delphi 代码更具可读性。看看我们的 TDynArray wrapper如果您想对这样一个动态记录数组进行高级访问,请使用 TList - 类似的方法。

由于AnsiString类型映射 PAnsiChar ,从二进制的角度来看,您甚至可以这样定义您的记录:
type
TFoo = record
  x, y : double;
  a : integer;
  b : AnsiString;
end;

TBar = record
  a : double;
  b : integer;
  c : AnsiString;
end;

当映射到 gcc 应用程序时,它将被读取为常规 *char .

使用 AnsiString在这里,您不需要处理 Delphi 代码的内存分配。使用关联的动态数组,它可以使您的 Delphi 代码更易于维护。请注意,我们的 TDynArray包装器将处理嵌套的 AnsiString按预期在记录中,即使是最高级别的方法(例如二进制序列化或散列)。

关于delphi - 编写要从 gcc 应用程序调用的 Delphi/FreePascal DLL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6105474/

相关文章:

delphi - 实现可变长度数组的最佳方法是什么?

delphi - 如何在 sgcWebSockets 3.2 中配置 SSL?

vb.net - 如何将vb类添加到类库中?

c - gcov 警告 : merge mismatch for summaries

Delphi:将记录参数分解为字段

delphi - '23/02/2011 12 :34:56' is not valid date and time

dll - DLL 和 LIB 扩展的区别

c - 合并 C Dll 的最简单方法。有来源

c++ - gcc '-m32' 选项在不运行 valgrind 时更改浮点舍入

c++ - 当 C 代码调用 Fortran 子程序时,子程序顶部发生段错误