Reputation: 77
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);
Problem:
Only the MsgId and the DataData_FldSizeAdmin have values which is the same value. I think it's because they are sharing the same memory address.
UNKNOWN, SENDTIME and RECEIPTIME don't have values.
Upvotes: 2
Views: 1879
Reputation: 8372
In stead of MarshalAs[UnmanagedType.ByValArray]
, you should use MashalAs[UnmanagedType.ByValTStr]
inside the declaration of your struct:
as in:
...
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;
}
...
See the 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).
The documentation for ´ByValArray´ sais (emphasis mine):
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.
So I think for your code to work using ByValArray
, you should also add a ArraySubType
of LPStr
to the MarshalAs
attribute.
Upvotes: 2