Reputation: 1927
In Delphi I have a structure like this:
TCustomerInfo = Packed Record
CustomerNo: Integer;
FirstName: String[50];
LastName: String[50];
End;
With a dummy-proc like this:
procedure GetCustomer(CustomerNo: Integer; var CustomerInfo: TCustomerInfo);
begin
CustomerInfo.CustomerNo := 19901;
CustomerInfo.FirstName := 'JOHN';
CustomerInfo.LastName := 'DOE';
end;
In C# I have this:
[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;
}
With an imported Delphi function like this:
[DllImport("Exceline.dll")]
extern static void GetCustomer(Int32 CustomerNo, ref CUSTOMER_INFO CustomerInfo);
The idea is to make sure all memory allocation and storage is being handled by the C# application.
My problem is that nothing gets assigned to my C# struct upon return from GetCustomer :-/
Upvotes: 1
Views: 2737
Reputation: 1927
I finally came up with a solution which avoids all the Alloc/FreeHGlobal, but if this is truly bulletproff with regards to the garbage collector is another matter.
The solution is to first clear the TCustomer structure with FillChar then copy the data using the Move procedure.
The delphi record looks like this:
TCustomer = packed record
CustomerNo: Integer;
FirstName: array [1..50] of Char;
LastName: array [1..50] of Char;
end;
Then i copy the string to the structure with a procedure:
procedure StrToBuf(Str: String; var buf);
begin
Move(Pointer(str)^, buf, Length(str));
end;
Within a proc more or less like this:
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;
Finally the C# struct looks something like this:
[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;
}
Upvotes: 2
Reputation: 13897
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);
Upvotes: 1