将具有枚举成员的非托管结构编组到 c#
Posted
技术标签:
【中文标题】将具有枚举成员的非托管结构编组到 c#【英文标题】:Marshal unmanaged structure with enum member to c# 【发布时间】:2014-01-01 08:27:28 【问题描述】:我有一个unmanaged C++ code
,我想将其转换为managed C# code
,非托管代码如下所示,我已搜索但没有找到答案...我想知道编组的正确方法下面的代码,我不知道如何编组一个枚举,然后在一个结构中引用它。MMTPConxNack
结构是另一个结构内联合的成员。
层次结构如下图:
typedef enum
MMTPCnxNckRsn_NoAnswer=-2,
MMTPCnxNckRsn_SendError=-1,
MMTPCnxNckRsn_Ok=0,
MMTPCnxNckRsn_InvalidMember,
MMTPCnxNckRsn_HubNotReady,
MMTPCnxNckRsn_UnknownMember,
MMTPCnxNckRsn_LastCnxTooRecent,
MMTPCnxNckRsn_InvalidVersion,
MMTPCnxNckRsn_InvalidOptions,
MMTPCnxNckRsn_TooManyCnx
MMTPCnxNckRsn;
typedef struct
MMTPCnxNckRsn Reason;
MMTPConxNack;
typedef struct
long Length;
short Type;
union
MMTPConxReq ConxReq;
MMTPConxAck ConxAck;
MMTPConxNack ConxNack; // the structure with an enum inside
MMTPErrInd ErrInd;
Data;
MMTPMsg;
实际上我想编组 MMTPConxNack
结构..我使用 FieldOffset 来定义大小。提前致谢。
【问题讨论】:
需要查看更多代码,您所说的 FieldOffset 是什么?您实际上是将显示的代码移植到 C# 并通过网络进行编组,还是要将使用此代码创建的对象编组为用 c# 中的等效代码编写的新代码? @norlesh ,上面的代码是非托管 c++ 代码...我想编组MMTPConxNack
结构..当我想编组它时我不确定什么是正确的方法,因为它有一个枚举成员,它在一个联合体内。因为联合体在其成员之间共享内存,所以我知道设置每个成员的大小很重要。
它是从哪里编组到哪里的?
我不明白为什么这很重要??..有一个非托管的win32 dll,我想调用它的方法,所以我使用编组..但是dll中的函数接收网络上的消息.
谢谢,不能给你逐字逐句的答案 - 但我在答案中链接到的文章应该给你你需要的一切
【参考方案1】:
枚举看起来像这样:
public enum MMTPCnxNckRsn
MMTPCnxNckRsn_NoAnswer = -2,
MMTPCnxNckRsn_SendError = -1,
MMTPCnxNckRsn_Ok = 0,
MMTPCnxNckRsn_InvalidMember,
MMTPCnxNckRsn_HubNotReady,
MMTPCnxNckRsn_UnknownMember,
MMTPCnxNckRsn_LastCnxTooRecent,
MMTPCnxNckRsn_InvalidVersion,
MMTPCnxNckRsn_InvalidOptions,
MMTPCnxNckRsn_TooManyCnx
包含的结构是:
public struct MMTPConxNack
public MMTPCnxNckRsn Reason;
联合是:
[StructLayout(LayoutKind.Explicit)]
public struct MMTPMsgDataUnion
[FieldOffset(0)]
public MMTPConxReq ConxReq;
[FieldOffset(0)]
public MMTPConxAck ConxAck;
[FieldOffset(0)]
public MMTPConxNack ConxNack;
[FieldOffset(0)]
public MMTPErrInd ErrInd;
这是棘手的部分。您使用LayoutKind.Explicit
和FieldOffset
来指定C++ 联合的所有成员相互重叠。显然,您需要对此联合中包含的其他 3 种类型进行定义,这些定义在问题的 C++ 代码中是看不到的。我想你已经知道如何定义这些了。
一旦你声明了联合,最终的结构就很简单了:
public struct MMTPMMsg
public int Length;
public short Type;
public MMTPMsgDataUnion Data;
【讨论】:
MMTPMsgDataUnion
的大小不重要?并且它的所有成员都得到[FieldOffset(0)]
(零)??
上面的代码与问题中的匹配。大小相配。你认为没有?
@Paridokht 你还需要帮助吗?
是的...你能告诉我enum
的大小(以字节为单位)吗?我知道可能是我的问题不够清楚..对不起..但假设在 union(MMTPMsgDataUnion
) 之后还有另一个成员,所以我必须知道包含 enum
的 union 的大小才能设置 @987654332 @ 对于 MMTPMsgDataUnion
之后的成员...主要问题是要知道 enum
的大小(以字节为单位),其中包含无符号整数。
枚举只是一个 int,所以在 Windows 上它是四个字节。你打算如何处理这些信息?你觉得我的回答不准确吗?【参考方案2】:
你需要一个 C# 枚举和结构来匹配原生的:
public enum MMTPCnxNckRsn
MMTPCnxNckRsn_NoAnswer,
MMTPCnxNckRsn_SendError,
MMTPCnxNckRsn_Ok,
MMTPCnxNckRsn_InvalidMember,
MMTPCnxNckRsn_HubNotReady,
MMTPCnxNckRsn_UnknownMember,
MMTPCnxNckRsn_LastCnxTooRecent,
MMTPCnxNckRsn_InvalidVersion,
MMTPCnxNckRsn_InvalidOptions,
MMTPCnxNckRsn_TooManyCnx
public struct MMTPConxNack
public readonly MMTPCnxNckRsn Reason;
然后你像这样编组它:
var managedItem = (MMTPConxNack)Marshal.PtrToStructure(pointer,typeof(MMTPConxNack));
【讨论】:
您的意思是定义一个 c# 枚举,然后在我的MMTPConxNack
结构中将枚举类型的 Reason
成员设置为 int 类型?
如果你想在 C# 代码中使用它,你最终需要一个具有相同值的 C# 枚举。问题是如何将 c++ 结构转换为 .net 结构。您需要定义一个看起来相同的(即一个字段)并使用Marshal.PtrToStructure
你能给我举个例子吗?我知道我应该有一个 c# 枚举并且我已经定义了它。
谢谢你..我会测试你的答案..但我担心因为它在一个联合里面它不能正常工作,如果它工作正常我会把它标记为答案:)
@I3arnon 工会呢?为什么需要PtrToStructure
?以上是关于将具有枚举成员的非托管结构编组到 c#的主要内容,如果未能解决你的问题,请参考以下文章
在 C# 中将 CodeElements 编组到 IntPtr
P/Invoke 编组和解组 C# 和非托管 DLL 之间的二维数组、结构和指针