我怎样才能正确地将它们转换为c#,marshall所以我可以将这些结构传递给DLL(c ++)?

时间:2011-02-09 11:15:02

标签: c# c++ interop marshalling

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 个答案:

答案 0 :(得分:2)

代替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;
}
...

请参阅documentation

  

ByValTStr :用于在线,   固定长度的字符数组   出现在一个结构中。该   与ByValTStr一起使用的字符类型是   由...决定   System.Runtime.InteropServices.CharSet   的论点   System.Runtime.InteropServices.StructLayoutAttribute   适用于包含结构。   总是使用   MarshalAsAttribute.SizeConst字段   表示数组的大小。

     

.NET Framework ByValTStr类型的行为   像C风格的固定大小的字符串   在结构内部(例如,char   S [5])。托管代码中的行为   与Microsoft Visual不同   基本6.0行为,不是null   终止(例如,MyString As   字符串* 5)。

'ByValArray'sais(强调我的)的文档:

  

设置MarshalAsAttribute.Value时   到ByValArray,SizeConst必须是   设置为表示元素的数量   在数组中。 ArraySubType字段   可以选择包含   数组元素的UnmanagedType   什么时候需要区分   在字符串类型中。你只能使用   这个UnmanagedType在一个数组上   在结构中显示为字段。

因此,我认为您的代码可以使用ByValArray,您还应该在ArraySubType属性中添加LPStr MarshalAs