【问题标题】:Marshal unmanaged structure with enum member to c#将具有枚举成员的非托管结构编组到 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中的函数接收网络上的消息.
  • 谢谢,不能给你逐字逐句的答案 - 但我在答案中链接到的文章应该给你你需要的一切

标签: c# c++ pinvoke marshalling


【解决方案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
猜你喜欢
  • 1970-01-01
  • 2015-10-26
  • 1970-01-01
  • 1970-01-01
  • 2021-09-26
  • 1970-01-01
  • 2019-03-02
  • 2018-03-19
相关资源
最近更新 更多