【问题标题】:Will struct modifications in C# affect unmanaged memory?C# 中的结构修改会影响非托管内存吗?
【发布时间】:2010-09-02 18:29:58
【问题描述】:

我的直觉反应是否定的,因为托管和非托管内存是不同的,但我不确定 .NET Framework 是否在幕后使用编组。

我认为会发生的是: 从我的非托管 DLL 获取结构时,与调用获取 IntPtr 然后使用它和 Marshal 类将结构复制到托管内存中相同(并且对托管内存中的结构所做的更改不会冒泡) .

我似乎在 MSDN 上的任何地方都找不到此文档。任何链接将不胜感激。

我的代码如下所示:

[DllImport("mydll.dll", BestFitMapping=false, CharSet=CharSet.Ansi)]
private static extern int GetStruct(ref MyStruct s);

[StructLayout(LayoutKind.Sequential, Pack=0)]
struct MyStruct
{
     public int    Field1;
     public IntPtr Field2;
}

public void DoSomething()
{
      MyStruct s = new MyStruct();
      GetStruct(ref s);

      s.Field1 = 100; //does unmanaged memory now have 100 in Field1 as well?
      s.Field2 = IntPtr.Zero; //does unmanaged memory now have a NULL pointer in field Field2 as well?
}

【问题讨论】:

    标签: c# .net struct pinvoke


    【解决方案1】:

    不,P/Invoke 编组器将非托管结构成员值复制到结构的托管版本中。通常,结构的托管版本与它的非托管版本不兼容。内存布局是不可发现的,CLR 使用它来重新排序 字段以使结构更小。编组是必不可少的,您必须创建一个副本。

    使用给定的函数签名无法修改结构,因为您让填充传递给它的内存。函数本身已经复制了结构。但是,您可以参与 Field2 值,因为它是一个原始指针。如果这指向一个结构,则使用Marshal.PtrToStructure() 自己编组它。修改它的托管副本并使用Marshal.StructureToPtr() 将其复制回非托管内存。或者直接使用 Marshal.ReadXxx() 和 WriteXxx() 访问它。

    【讨论】:

    • 这是我所期望的,但我真的在 MSDN 等上寻找对此的某种确认。此外,Pack=0 也可以(它仅表示平台默认值,对于使用相同代码的 x86 和 x64 部署很重要)。见:msdn.microsoft.com/en-us/library/…
    • 这里真的不是找链接的好地方,推荐google。
    • 重申我在问题中所说的话也不是真正的答案:)。我希望有某种文档来解释 Microsoft 实施的行为。
    • StructureToPtr 为我工作。我必须修改一个非托管结构来设置配置值,它从未返回给 API,所以我不能只使用 PtrToStructure 制作的托管副本。但是 PtrToStructure 的顺序,修改托管结构数据,StructureToPtr 效果很好。
    【解决方案2】:

    CSharp 语言规范.doc 第 26 页

    使用 new 运算符调用结构构造函数,但这并不意味着正在分配内存。结构构造函数不是动态分配对象并返回对它的引用,而是简单地返回结构值本身(通常在堆栈上的临时位置),然后根据需要复制该值。

    由于“结构”后备存储并没有什么特别之处,因此人们不会期望在成员分配之后进行匿名编组操作。

    【讨论】:

    • 我认为这是正确的答案。当其字段发生变化时,没有任何东西会挂钩到结构(或其字段)以将更改回非托管内存,这一事实似乎最终回答了这个问题。
    猜你喜欢
    • 1970-01-01
    • 2013-09-25
    • 2020-01-19
    • 1970-01-01
    • 2018-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多