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

标签 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;
 }

主要内容:

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

最佳答案

代替 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: Used for in-line, fixed-length character arrays that appear within a structure. The character type used with ByValTStr is determined by the System.Runtime.InteropServices.CharSet argument of the System.Runtime.InteropServices.StructLayoutAttribute applied to the containing structure. Always use the MarshalAsAttribute.SizeConst field to indicate the size of the array.

.NET Framework ByValTStr types behave like C-style, fixed-size strings inside a structure (for example, char s[5]). The behavior in managed code differs from the Microsoft Visual Basic 6.0 behavior, which is not null terminated (for example, MyString As String * 5).

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

When MarshalAsAttribute.Value is set to ByValArray, the SizeConst must be set to indicate the number of elements in the array. The ArraySubType field can optionally contain the UnmanagedType of the array elements when it is necessary to differentiate among string types. You can only use this UnmanagedType on an array that appear as fields in a structure.

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

关于c# - 我怎样才能正确地将它们转换为 c#,编码以便我可以将这些结构传递给 DLL (c++)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4944092/

相关文章:

c# 写入事件查看器

c++ - 这个给定数据结构的时间复杂度

c# - 从非托管 C++ 调用 C# 传递或返回 "Complex"类型

c# - native C++ 和 C# 互操作

c# - 对于 C# where 扩展方法,我需要包含哪个程序集?

c# - 字节溢出评估为零而不是异常?

c# - 无法加载规则程序集

C++ 帐户创建程序崩溃

c++ - 抽象基类的设计问题?

.net - 如何在“即点即用”安装上进行 Office 互操作?