Как правильно передать Delphi Record в структуру C # с Interop? - PullRequest
1 голос
/ 12 июля 2010

В 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 #.

Моя проблема в том, что ничегоприсваивается моей структуре C # по возвращении из GetCustomer: - /

Ответы [ 2 ]

2 голосов
/ 03 августа 2010

Я наконец-то придумал решение, которое позволяет избежать всего Alloc / FreeHGlobal, но если это действительно bulletproff по отношению к сборщику мусора, это другое дело.

Решение состоит в том, чтобы сначала очистить структуру TCustomer с помощьюЗатем FillChar копирует данные с помощью процедуры 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 # выглядит примерно так:

[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 голос
/ 12 июля 2010
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);
...