如何转换C++;具有并集到C#的结构?
伙计们,在调用DLL中的函数后,我很难检索结构成员值。我试图把C++代码转换成C语言,但我不确定它是否正确。请帮助我理解这里的错误(如果有)以及如何纠正 这里的问题是,在从DLL调用ReceiveMessage函数后,无法正确检索内部结构(Union)的值。例如,m_objMsg.MsgData.StartReq.MsgID始终为0。 但是当我尝试使用C++ .exe程序时,MSGID有一个正确的值。(不是0) C++代码:如何转换C++;具有并集到C#的结构?,c#,c++,pinvoke,marshalling,C#,C++,Pinvoke,Marshalling,伙计们,在调用DLL中的函数后,我很难检索结构成员值。我试图把C++代码转换成C语言,但我不确定它是否正确。请帮助我理解这里的错误(如果有)以及如何纠正 这里的问题是,在从DLL调用ReceiveMessage函数后,无法正确检索内部结构(Union)的值。例如,m_objMsg.MsgData.StartReq.MsgID始终为0。 但是当我尝试使用C++ .exe程序时,MSGID有一个正确的值。(不是0) C++代码: extern int ReceiveMessage(SESSION,
extern int ReceiveMessage(SESSION, int, Msg*);
typedef struct
{
char SubsId[15];
int Level;
char Options[12];
} ConxReq;
typedef struct
{
char MsgId[25];
} StartReq;
typedef struct
{
long Length;
short Type;
union
{
ConxReq oConxReq;
StartReq oStartReq;
} Data;
} Msg;
/////////////////////////////////////////////////////
Msg oMsg;
int rc=ReceiveMessage(Session, 0, &oMsg);
switch(rc)
{
case 0:
switch(oMsg.Type)
{
case 0: // ConxReq
…
break;
case 1: // StartReq
…
break;
…
}
下面是我将其转换为c的尝试:
如果在C中加入这个结构,C++和C… 我有一个错误,说明“…对齐错误”或“…重叠…”
c++提前非常感谢您的时间和帮助…您必须使用StructLayout(LayoutKind.Explicit)和FieldOffset来创建联合 阿卡什是对的,看看这里: 另一个选项是创建两个结构,并在知道它是哪种类型后使用适当的强制转换 嗯
< C++ >马里奥< /P> < P>,我们知道所有的成员都共享同一个内存块,并且只能同时拥有一个对象。 为了在C#中实现这一点,我们需要使用LayoutKind来显式地将每个成员的所有起点设置为0 在上一个示例中,将显示一条错误消息,指出对象类型的偏移未正确对齐或被非对象类型重叠 答案是我们不能将FieldOffSet的所有成员都设置为0,因为不允许将引用类型与值类型组合。 -多亏了汉斯·帕桑的解释 我所做的是创建UNION成员结构的副本,并将所有字符串成员变量的类型更改为字节。 我使用字节,因为这是一种值类型,所以我可以将此结构放入FieldOffSet(0)中。 请注意,我调整了下一个成员变量的FieldOffSet,这样我仍然可以得到与字符串变量相同大小的变量。 还有结构大小,因为我最后有字节成员。 感谢阿卡什·卡瓦和马里奥·汤匙给了我一个想法,并为我提供了一个有用的链接 在DLL中调用函数并将此结构Obj(ref m_objMsg)作为参数传递后,我需要提取值。 一种方法是使用指向非托管内存中结构地址的指针,并将该指针转换为新的指针 具有相应成员变量的结构(我的原始结构) 请让我知道,如果你有其他或更好的方法来做到这一点。。。 请告知我所做的是正确的还是遗漏了什么
非常感谢!!!:) 谢谢你的回复。我没有看到LayoutKind.Absolute,我使用.Explicit并将所有FieldOffset设置为(0)以使其成为联合。感谢您的回复和链接。根据链接,联合体内部有两个结构。他们所做的是在联合内部显式提取两个struct和layout的所有成员变量。更可能的情况是,我在转换中所做的是将Union中每个结构的起始字段偏移量设置为0。不可能吗?唯一的区别是我仍然将所有成员变量放在每个结构中。创建两个结构并强制转换取决于类型,这是什么意思?抱歉问…感谢Mario的链接和创建另一个结构的想法。请看下面我的答案。
[DllImport("MyDLL.dll",
CallingConvention = CallingConvention.Cdecl,
CharSet = CharSet.Ansi)]
protected static extern Int32 ReceiveMessage(IntPtr session,
Int32 nTimeOut,
[MarshalAs(UnmanagedType.Struct)] ref Msg ptrMsg);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct ConxReq
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 15)]
public string SubsId;
public Int32 Level;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 12)]
public string Options;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct StartReq
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 25)]
public string MsgId;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
protected struct Msg
{
public int Length;
public Int16 Type;
public Data MsgData;
}
StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)]
public struct Data
{
[FieldOffset(0)]
public ConxReq oConxReq;
[FieldOffset(0)]
public StartReq oStartReq;
}
Msg m_objMsg = new Msg();
m_objMsg.MsgData = new Data();
m_objMsg.MsgData.oConxReq = new ConxReq();
m_objMsg.MsgData.oStartReq = new StartReq();
int rc = ReceiveMessage(m_Session, nTimeOut, ref m_objMsg);
then the SWITCH Condition
ConxNack oConxNack;
typedef struct
{
int Reason;
} ConxNack;
[StructLayout(LayoutKind.Sequential)]
public struct ConxNack
{
public int nReason;
}
[FieldOffset(0)]
public ConxNack oConxNack;
NEW STRUCTS (BYTES)
////////////////////////////////////////////////////////////////
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi, Size = 31)]
public struct ConxReq
{
[FieldOffSet(0)]
public byteSubsId;
[FieldOffSet(15)]
public Int32 Level;
[FieldOffSet(19)]
public byte Options;
}
[StructLayout(LayoutKind.Explicit, Size = 4)]
public struct ConxNack
{
[FieldOffSet(0)]
public int nReason;
}
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi, Size = 25)]
public struct StartReq
{
[FieldOffSet(0)]
public byte MsgId;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
protected struct Msg
{
public int Length;
public Int16 Type;
public Data MsgData;
}
StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)]
public struct Data
{
[FieldOffset(0)]
public ConxReq oConxReq;
[FieldOffset(0)]
public ConxNack oConxNack;
[FieldOffset(0)]
public StartReq oStartReq;
}
////////////////////////////////////////////////////////////////
MY ORIGINAL STRUCTS
////////////////////////////////////////////////////////////////
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct MyConxReq
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 15)]
public string SubsId;
public Int32 Level;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 12)]
public string Options;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct MyStartReq
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 25)]
public string MsgId;
}
[StructLayout(LayoutKind.Sequential)]
public struct MyConxNack
{
public int nReason;
}
///////////////////////////////////////////////////////////////
Since I have a Msg.Type, i know what kind of struct (type) I could cast the object.
Like for example
ReceiveMessage(m_Session, nTimeOut, ref oMsg);
switch (oMsg.Type)
{
case 0: // ConxReq
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(oMsg.MsgData.ConxReq); // use the new struct (bytes)
Marshal.StructureToPtr(oMsg.MsgData.ConxReq, ptr, false);
MyConxReq oMyConxReq = new MyConxReq;
oMyConxReq = (MyConxReq) Marshal.PtrToStructure(ptr, typeof(MyConxReq)); // convert it to the original struct
Marshal.FreeHGlobal(ptr);
Then you can use now the oMyConxReq object to acccess the member variables directly.