编组后字段中的值错误

Posted

技术标签:

【中文标题】编组后字段中的值错误【英文标题】:Wrong value in field after marshalling 【发布时间】:2013-01-04 16:02:54 【问题描述】:

我正在尝试将原始结构从 C++ 编组为 C#,并具有以下代码:

using System;
using System.Runtime.InteropServices;

namespace dotNet_part

    class Program
    
        static void Main(string[] args)
        
            Custom custom = new Custom();
            Custom childStruct = new Custom();

            IntPtr ptrToStructure = Marshal.AllocCoTaskMem(Marshal.SizeOf(childStruct));
            Marshal.StructureToPtr(childStruct, ptrToStructure, true);

            custom.referenceType = ptrToStructure;
            custom.valueType = 44;

            Custom returnedStruct = structureReturn(custom);
            Marshal.FreeCoTaskMem(ptrToStructure);

            returnedStruct = (Custom)Marshal.PtrToStructure(returnedStruct.referenceType, typeof(Custom));
            Console.WriteLine(returnedStruct.valueType); // Here 'm receiving 12 instead of 44
        

        [return:MarshalAs(UnmanagedType.I4)]
        [DllImport("CPlusPlus part.dll")]
        public static extern int foo(Custom param);

        // [return:MarshalAs(UnmanagedType.Struct)]
        [DllImport("CPlusPlus part.dll")]
        public static extern Custom structureReturn(Custom param);
    

    [StructLayout(LayoutKind.Sequential)]
    struct Custom
    
        [MarshalAs(UnmanagedType.I4)]
        public int valueType;
        public IntPtr referenceType;
    

还有C++部分:

typedef struct Custom CUSTOM;
extern "C"

    struct Custom
    
       int valueType;
       Custom* referenceType;
     Custom;

    _declspec(dllexport) int foo(CUSTOM param)
    
      return param.referenceType->valueType;
    

    _declspec(dllexport) CUSTOM structureReturn(CUSTOM param)
    
      return param;
    

为什么我在returnedStruct.valueType 中收到的是 12 而不是 44?

【问题讨论】:

这两个值相差32只是巧合吗?如果将 44 更改为 45,您的结果是否会从 12 更改为 13? 数值还是12,不管存哪个数字。 【参考方案1】:

这里有两个错误:

从语义上讲,您正在设置 custom.valueType = 44,但在返回结构时,您正在检查 custom.referenceType->valueType,它不应该是 44——它应该是 0。

第二个错误是你在这个指针上调用Marshal.FreeCoTaskMem() (custom.referenceType)你解组它之前!这意味着您正在将 未分配的内存 解组到您的 Custom 结构中。此时,这是未定义的行为,答案为 12 与收到访问冲突一样有效。


要解决第一个问题,您需要检查returnedStruct.valueType 无需解组returnedStruct.referenceType,或者需要将childStruct.valueType 设置为44,然后再将其编组为ptrToStructure

要解决第二个问题,您需要颠倒调用Marshal.PtrToStructure()Marshal.FreeCoTaskMem() 的顺序。

【讨论】:

谢谢,现在解决方案很明显了。

以上是关于编组后字段中的值错误的主要内容,如果未能解决你的问题,请参考以下文章

Flask-RESTPlus系列Part2:响应编组

提交后清除 textarea 字段中的值

Fragment 与 Parcel 一起崩溃:调用 onPause 方法时无法编组值错误

如何验证下拉列表中的“其他”选项?

解组忽略空字段

Transact-SQL统计某字段中的值第一次出现后的2小时内出现的次数