如何使用Interop将Delphi记录正确传递给C#结构?

时间:2010-07-12 18:46:49

标签: c# delphi interop delphi-7

在Delphi中我有这样的结构:

  TCustomerInfo = Packed Record
    CustomerNo: Integer;
    FirstName: String[50];
    LastName: String[50];
  End;

使用这样的虚拟过程:

procedure GetCustomer(CustomerNo: Integer; var CustomerInfo: TCustomerInfo);
begin
  CustomerInfo.CustomerNo := 19901;
  CustomerInfo.FirstName := 'JOHN';
  CustomerInfo.LastName := 'DOE';
end;

在C#中我有这个:

 [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)]
 struct CUSTOMER_INFO
 {
  public Int32 CustomerNo;
  [MarshalAs(UnmanagedType.ByValTStr, SizeConst=50)]
  public string FirstName;
  [MarshalAs(UnmanagedType.ByValTStr, SizeConst=50)]
  public string LastName;
 }

使用这样的导入Delphi函数:

 [DllImport("Exceline.dll")]
 extern static void GetCustomer(Int32 CustomerNo, ref CUSTOMER_INFO CustomerInfo);

我们的想法是确保C#应用程序正在处理所有内存分配和存储。

我的问题是从GetCustomer返回后没有任何内容被分配给我的C#结构: - /

2 个答案:

答案 0 :(得分:2)

我终于提出了一个避免所有Alloc / FreeHGlobal的解决方案,但如果这对于垃圾收集器来说真的是关于另一件事的话。

解决方案是先用FillChar清除TCustomer结构,然后使用Move程序复制数据。

delphi记录如下所示:

  TCustomer = packed record
    CustomerNo: Integer;
    FirstName: array [1..50] of Char;
    LastName: array [1..50] of Char;
  end;

然后我用一个过程将字符串复制到结构中:

procedure StrToBuf(Str: String; var buf);
begin
  Move(Pointer(str)^, buf, Length(str));
end;

在一个或多或少像这样的过程中:

procedure LoadCustomerFromQuery(var Query: TQuery; var Customer: TCustomer); stdcall;
begin

  FillChar(Customer, SizeOf(Customer), 0);

  StrToBuf(Query.FieldByName('FNAVN').AsString, Customer.FirstName);
  StrToBuf(Query.FieldByName('ENAVN').AsString, Customer.LastName);

  Customer.CustomerNo := Query.FieldByName('KUNDENR').AsInteger;

end;

最后,C#struct看起来像这样:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)]
public struct TCustomer
{
    public Int32 CustomerNo;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)]
    public string FirstName;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)]
    public string LastName;
}

答案 1 :(得分:1)

extern static void GetCustomer(Int32 CustomerNo, IntPtr CustomerInfo);
...
var info = default(CUSTOMER_INFO);
var ptr = Marshal.AllocHGlobal(Marshal.SizeOf(info));
Marshal.StructureToPtr(info, ptr, false);
GetCustomer(n, ptr);
Marshal.PtrToStructure(ptr, info);
Marshal.FreeHGlobal(ptr);