delphi record to C#

2019-09-21 14:45发布

问题:

need help converting delphi record to C# struct and passing this struct to C dll:

type Transaction = record
  pos_id: array[0..9] of char;
  ev_type: array[0..4] of char;
  amount: array[0..14] of char;
  chip_reader_used: boolean;
  internal_magstripereader_used: boolean;
  track2data: array[0..99] of char;
  card_usage_mode: array[0..4] of char;
  receipt_directory: array[0..254] of char;
  additional_info: array[0..999] of char;
  event_number: array[0..9] of char;
  original_filingcode: array[0..19] of char;
  transaction_reasoncode: array[0..9] of char;
end;

tried following but not working:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public unsafe struct Transaction {
        public fixed byte pos_id[10];
        public fixed byte ev_type[5];
        public fixed byte amount[15];
        public bool       chip_reader_used;
        public bool       internal_magstripereader_used;
        public fixed byte track2data[100];
        public fixed byte card_usage_mode[5];
        public fixed byte receipt_directory[255];
        public fixed byte additional_info[1000];
        public fixed byte event_number[10];
        public fixed byte original_filingcode[20];
        public fixed byte transaction_reasoncode[10];
};

and C function is:

void Card_Event(struct)

C# (loaded by GetProcAddress)

[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate void Card_Event_Func(ref Transaction transaction);

IntPtr procAddr = GetProcAddress(_hDLL, "Card_Event");
if ( procAddr == IntPtr.Zero )
    return false;
Card_Event_Func Card_Event = (Card_Event_Func)Marshal.GetDelegateForFunctionPointer(procAddr, typeof(Card_Event_Func));

回答1:

You should use UnmanagedType.ByValTStr for the strings. There is no need for unsafe code here. You'll find that declaration below, using strings, is much easier to use than unsafe fixed arrays.

Note that you also need to specify single byte marshalling for the booleans. The default marshalling for bool is a 4 byte BOOL compatible with Win32 API functions.

Finally, I'm not sure why you chose to pack the record. There's no indication in the Delphi code that it is packed.

So, the final translation looks like this:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct Transaction 
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
    public string pos_id;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 5)]
    public string ev_type;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 15)]
    public string amount;

    [MarshalAs(UnmanagedType.I1)]
    public bool chip_reader_used;

    [MarshalAs(UnmanagedType.I1)]
    public bool internal_magstripereader_used;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
    public string track2data;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 5)]
    public string card_usage_mode;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 255)]
    public string receipt_directory;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1000)]
    public string additional_info;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
    public string event_number;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
    public string original_filingcode;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
    public string transaction_reasoncode;
};

I'm not sure that you have translation the function call correctly because you've not shown a function native code declaration of the function.