我需要将我的部分 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 字段没有任何好处)。
定义一些指针类型,如 PFoo
和 PBar
, 这将比 ^TFoo
写得更好例如
如果你需要访问一些数组,你可以定义 TFooArray
和 TBarArray
,如下面的代码所示。
不要忘记 cdecl
或 stdcall
任何函数/过程的调用约定。
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/