【问题标题】:Converting a structure to an intptr将结构转换为 intptr
【发布时间】:2014-01-10 22:19:16
【问题描述】:

我有一个类定义如下:

[StructLayout(LayoutKind.Sequential)]
public class OUR_MEM_STR
            {
                public byte[] p;
                public int  len;
            };

这是下面 C 结构的等效定义:

typedef struct
{
    void *p;
    int  len;
} OUR_MEM_STR;

我对成员 p 使用了 byte[] 而不是 IntPtr 类型,因为它在整个 c# 项目中都被使用了。

我定义了一个 len = 10 和 p = new byte[10] 的对象 obj

我想把它变成一个 intptr。我如何获得对象的大小?

 IntPtr pObj = Marshal.AllocHGlobal(obj.len + sizeof(int));
 Marshal.StructureToPtr(obj, pObj, true);

看看我在那里做了什么。它似乎太难编码了。如果我执行以下 sn-p;

IntPtr pObj = Marshal.AllocHGlobal(Marshal.SizeOf(obj));

这样做会返回错误的大小,因为 obj.p 返回的大小是 4 而不是 10。因为指向字节数组的指针占用的内存是 4 个字节。

有没有更好的办法?

【问题讨论】:

  • 你能告诉我们你试图复制的结构的 C 定义吗?
  • @JaredPar,我编辑了这个问题
  • 所以,如果我这样做 IntPtr pObj = Marshal.AllocHGlobal(Marshal.SizeOf(obj));并且使用false参数,应该没问题吧?
  • 太酷了,它做到了。当我将结构写入 ptr 函数时,智能提示告诉我使用 true。他们让新开发者感到困惑

标签: c# class marshalling intptr


【解决方案1】:

返回值正确,p是一个指针,需要4个字节。

你不能这样,有两个内存分配。编组器为数组分配内存。它创建了一个 SAFEARRAY,一个 COM 数组类型。您的 C 代码不太可能对此感到满意。改为这样声明:

[StructLayout(LayoutKind.Sequential)]
public class OUR_MEM_STR {
    public IntPtr p;
    public int len;
};

并使用 Marshal.AllocHGlobal(10) 分配p。不要忘记再次清理。

不要将 true 传递给 StructureToPtr(),AllocHGlobal() 分配的内存没有初始化。这会让你的程序随机崩溃。你必须通过 false

【讨论】:

  • 谢谢! C# 垃圾回收不会自动清理吗?
  • 不,您分配了非托管内存。两次调用 Marshal.FreeHGlobal() 是一项硬性要求。请注意,这必须发生在 您的 pinvoked 代码停止使用该结构之后。
  • 正确。 Lil by lil 我正在掌握 pinvoke。感谢像你这样的人
  • 一次,就在我退出创建对象的函数之前,另一次?
  • 一次用于数组,再次用于结构。两者都必须被释放。
猜你喜欢
  • 1970-01-01
  • 2014-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-04
  • 2012-12-29
  • 2011-01-16
  • 1970-01-01
相关资源
最近更新 更多