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

|| 我需要将我的Win32 Delphi应用程序的一部分提供给另一家公司的Linux gcc程序。 吞吐量和部署要求使任何种类的远程服务都不适合,因此我正在考虑使用FreePascal构建gcc应用程序可以调用的.SO(相当于DLL的Linux操作系统)。 自从我使用C / C ++以来已经有很长时间了,而我从未在Linux上使用过,所以我不确定如何最好地构造DLL / SO接口以与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 .SO使该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代码更具可读性。如果您想使用类似
TList
的方法高层访问这种动态记录数组,请看一下
TDynArray
包装器。 由于
AnsiString
类型映射
PAnsiChar
,因此从二进制的角度来看,您甚至可以这样定义记录:
type
TFoo = record
  x, y : double;
  a : integer;
  b : AnsiString;
end;

TBar = record
  a : double;
  b : integer;
  c : AnsiString;
end;
映射到gcc应用程序时,它将作为常规ѭ21读取。 在这里使用
AnsiString
,您将不需要处理Delphi代码中的内存分配。使用关联的动态数组,可以使您的Delphi代码更易于维护。请注意,即使对于最高级的方法(例如二进制序列化或哈希处理),我们的
TDynArray
包装器也将按预期处理记录中的嵌套
AnsiString
。     
为确保记录的打包/对齐/填充符合GCC的要求,请将{$ packrecords c}添加到您的Pascal源。请注意,该指令特定于Free Pascal编译器,Delphi不支持它。     
看起来还不错想法: 您的数组(声明为指针和计数)将被完全手动管理-对您来说还好吗? 您应该更改:
procedure Process(const inFooBar : TFooBar);
包括与C兼容的调用约定。我不确定FreePascal和GCC都支持什么,但是像
cdecl
这样的东西应该可以正常工作。 您(出于安全考虑)还应指定结构对齐方式/装箱。
PChar
应该明显窄或宽(这些天宽是正常的。)     

要回复问题请先登录注册