将具有枚举成员的非托管结构编组到 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.ExplicitFieldOffset 来指定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 之间的二维数组、结构和指针

c# - 如何调用分配输出缓冲区以在c#中返回数据的非托管c++函数?

无法将结构从非托管库编组到单触引中的托管代码

从 c# dll 调用/编组字符串到非托管代码