Как я могу правильно преобразовать их в C #, Marshall, чтобы я мог передать эти структуры в DLL (C ++)? - PullRequest
2 голосов
/ 09 февраля 2011

C ++

#define FIELD_SIZE_MSGID       24
#define FIELD_SIZE_TIME        12
#define FIELD_SIZE_ADMIN      256


typedef struct

{

      char MsgId[FIELD_SIZE_MSGID+1];

      char SendTime[FIELD_SIZE_TIME+1];

      char ReceiptTime[FIELD_SIZE_TIME+1]; 

} AdminDataM0;





typedef struct

{

      int Type;

      union

      { 
         AdminDataM0 M0;
         char Data[FIELD_SIZE_ADMIN + 1];     

      } AdData;


      char Unknown[FIELD_SIZE_ADMIN + 1];


} AdminData;

C #:

    [DllImport("Receiver.dll",
        CallingConvention = CallingConvention.Cdecl, 
        ExactSpelling = false, 
        SetLastError = false, 
        CharSet = CharSet.Ansi,
        EntryPoint = "SendMessage")]
    [return: MarshalAs(UnmanagedType.I4)]
    protected static extern int SendMessage(
        [MarshalAs(UnmanagedType.Struct)] ref AdminData ptrAdminData,
);


   protected const Int32 FIELD_SIZE_MSGID = 24;
   protected const Int32 FIELD_SIZE_TIME = 12;
   protected const Int32 FIELD_SIZE_ADMIN = 256;

   [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    public struct AdminDataM0
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = FIELD_SIZE_MSGID + 1)]
        public char[] MsgId;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = FIELD_SIZE_TIME + 1)]
        public char[] SendTime;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = FIELD_SIZE_TIME + 1)]
        public char[] ReceiptTime;
    }

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
 protected struct AdminData
{
     [MarshalAs(UnmanagedType.I4)]
     public Int32 nType;

     [MarshalAs(UnmanagedType.Struct)]
     public Data AdminData_Data;            

     [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
     public struct Data
     {
         [FieldOffset(0)]
         [MarshalAs(UnmanagedType.Struct)]
         public AdminDataM0 M0; //135

         [FieldOffset(0)]
         [MarshalAs(UnmanagedType.ByValArray, SizeConst = FIELD_SIZE_ADMIN + 1)]
         public char[] Data_FldSizeAdmin;                
     }

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = FIELD_SIZE_ADMIN + 1)]
     public char[] Unknown;
 }

MAIN:

AdminData oAdminData = new AdminData(); 
oAdminData.AdminData_Data = new oAdminData.Data();            
oAdminData.AdminData_Data.M0 = new oAdminDataM0();

oAdminData.AdminData_Data.M0.MsgId = new char[FIELD_SIZE_MSGID + 1];                                 
oAdminData.AdminData_Data.M0.SendTime = new char[FIELD_SIZE_TIME + 1];                             
oAdminData.AdminData_Data.M0.ReceiptTime = new char[FIELD_SIZE_TIME + 1];
oAdminData.AdminData_Data.Data_FldSizeAdmin = new char[FIELD_SIZE_ADMIN + 1];
oAdminData.Unknown = new char[FIELD_SIZE_ADMIN + 1];

string M0_MsgId = "MsgId";
string M0_SendTime = "Send Time";
string M0_ReceiptTime = "ReceiptTime";
string unknown =  "Unknown";

M0_MsgId.ToCharArray().CopyTo(oAdminData.AdminData_Data.M0.MsgId, 0);
M0_SendTime.ToCharArray().CopyTo(oAdminData.AdminData_Data.M0.SendTime, 0);                
M0_ReceiptTime.ToCharArray().CopyTo(oAdminData.AdminData_Data.M0.ReceiptTime, 0);


// function to DLL

SendMessage(ref oAdminData);

Проблема:

Только MsgId и DataData_FldSizeAdmin имеют значения, которые являются одинаковыми. Я думаю, это потому, что они используют один и тот же адрес памяти.

UNKNOWN, SENDTIME и RECEIPTIME не имеют значений.

1 Ответ

2 голосов
/ 09 февраля 2011

Вместо MarshalAs[UnmanagedType.ByValArray] вы должны использовать MashalAs[UnmanagedType.ByValTStr] внутри объявления вашей структуры:

как в:

...
public struct AdminDataM0
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = FIELD_SIZE_MSGID + 1)]
    public string MsgId;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = FIELD_SIZE_TIME + 1)]
    public string SendTime;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = FIELD_SIZE_TIME + 1)]
    public string ReceiptTime;
}
...

См. Документацию :

ByValTStr : Используется для встроенных символьных массивов фиксированной длины, которые появляются внутри структуры.Тип символа, используемый с ByValTStr, определяется аргументом System.Runtime.InteropServices.CharSet в System.Runtime.InteropServices.StructLayoutAttribute, применяемом к содержащейся структуре.Всегда используйте поле MarshalAsAttribute.SizeConst, чтобы указать размер массива.

.NET Framework Типы ByValTStr ведут себя как строки C-стиля, фиксированного размера внутри структуры (например, char s [5]).Поведение в управляемом коде отличается от поведения в Microsoft Visual Basic 6.0, которое не завершается нулем (например, MyString As String * 5).

Документация для «ByValArray» (выделено мной):

Когда для MarshalAsAttribute.Value установлено значение ByValArray, необходимо указать SizeConst, чтобы указать количество элементов в массиве. Поле ArraySubType может дополнительно содержать UnmanagedType элементов массива, когда необходимо различать строковые типы.Вы можете использовать этот UnmanagedType только для массива, который отображается как поля в структуре.

Так что я думаю, что для того, чтобы ваш код работал с использованием ByValArray, вы должны также добавить ArraySubTypeот LPStr до атрибута MarshalAs.

...