如何正确地将这些转换为 c#,marshall,以便我可以将这些结构传递给 DLL (c++)?

Posted

技术标签:

【中文标题】如何正确地将这些转换为 c#,marshall,以便我可以将这些结构传递给 DLL (c++)?【英文标题】:How can I correctly convert these to c#, marshall so I can pass these struct to DLL (c++)? 【发布时间】:2011-02-09 11:15:01 【问题描述】:

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;
 

主要:

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 没有值。

【问题讨论】:

我已经在 c# 中尝试过这些,但我相信仍然缺少...我将 [FieldOffset(0)] 用于内部结构的两个成员变量,因为它是 c++ 中的联合。跨度> 这是在什么平台上的?您是否在同一平台上保存和加载数据?您必须小心注意不同平台上的不同对齐方式。 谢谢史蒂夫!对!我在 WinXP 上运行它。 Steve 你所说的对齐是什么意思?对不起,我还是 c# 的新手。 当一个 C# 结构被编组时,它会生成一个字节块。字节数组中 C# 结构的每个成员的位置在不同平台上可能会有所不同,因此您有时需要调整编组生成字节数组的方式,以使其在两个平台上的工作方式相同。 【参考方案1】:

您应该在结构声明中使用MashalAs[UnmanagedType.ByValTStr],而不是MarshalAs[UnmanagedType.ByValArray]

如:

...
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 [5])。托管代码中的行为 不同于 Microsoft Visual 基本 6.0 行为,不为空 终止(例如,MyString As 字符串 * 5).

'ByValArray' sais 的文档(重点是我的):

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

所以我认为要让您的代码使用ByValArray 工作,您还应该将LPStrArraySubType 添加到MarshalAs 属性。

【讨论】:

@Ryan:顺便说一句,您可以在 Stack Overflow 上接受答案...甚至可以投票 ;-)

以上是关于如何正确地将这些转换为 c#,marshall,以便我可以将这些结构传递给 DLL (c++)?的主要内容,如果未能解决你的问题,请参考以下文章

将包含结构的 c++ 函数传递给 C#,并使用 Marshal.PtrToStructure 将其转换为 c# 函数

如何正确地将日期时间从 c# 传递到 sql?

如何正确地将 NaN 转换为 NA

如何正确地将 Blob 对象转换为 ByteArrayInputStream 对象? [复制]

如何正确地将数据帧的所有日期时间列转换为 iso 格式

如何正确地将自定义按钮集转换为响应对象?