如何在 C# 中获取 IntPtr 指针的属性

Posted

技术标签:

【中文标题】如何在 C# 中获取 IntPtr 指针的属性【英文标题】:How to get a property of an IntPtr pointer in C# 【发布时间】:2015-01-02 11:23:10 【问题描述】:

我在我的 C# 项目中使用了一些 C++ 包装器。问题是我有一个指向 C++ 类型Head 的指针hd(类型为IntPtr),它有一个名为xlong 的属性。我怎样才能得到那个财产?我知道两种方法:

var l = ((Head)Marshal.PtrToStructure(hd, typeof(Head))).xlong;

var l = ((Head*)hd.ToPointer())->xlong;

但是有没有办法直接使用 Marshal 获得它?我没有找到任何关于它的信息。如果没有,我应该使用哪种方式?

Head 定义为

[StructLayout(LayoutKind.Sequential)]
public struct Head

    public int w;
    public int h;
    public double wmod;
    public double hmod;
    public IntPtr xlong;
    public IntPtr ylong;
    public int pitch;
    public uint flags;

【问题讨论】:

与您的实际问题无关,但您的资源名称不会是 long。这是 C++ 和 C# 中的关键字。除此之外,它将(稍微)取决于Head 的定义。一般来说,你的两种方法不一定会给出相同的结果。如果您能展示您的 C# 类 Head 是如何定义的,将会很有帮助。 你是对的,属性是xlongHead 实际上是一个结构。这是它的代码:pastebin.com/eTQC2u8D 谢谢,我冒昧地将其添加到您的问题中。 使用Marshal.ReadIntPtr()。使用 Marshal.OffsetOf() 计算偏移量,通常在静态构造函数中。 @HansPassant Heh,当您只指出ReadIntPtr 而尚未提及OffsetOf 时,我正在写我的答案。现在看起来有点傻。 【参考方案1】:

一般来说,您的两种方法可能会给出不同的结果,但它不在这里:您的 Head 结构是 blittable,这意味着它对非托管代码和托管代码的表示完全相同。

因此,您可以使用最适合您的方法。你的第一种方法:

var l = ((Head)Marshal.PtrToStructure(hd, typeof(Head))).xlong;

的优点是不需要你自己编写任何不安全的代码,而是让系统库来处理。

你的第二种方法:

var l = ((Head*)hd.ToPointer())->xlong;

具有在提取 xlong 字段之前不制作不必要的数据副本的优点。

正如 Hans Passant 指出的那样,使用 Marshal.ReadIntPtr 可以直接通过 Marshal 类读取字段。这并不直接适合:它需要您首先计算偏移量。但是,Marshal 类已经包含一个为您执行此操作的方法:Marshal.OffsetOf

如果您采用这种方法,您可能希望将Marshal.OffsetOf 的结果缓存在static readonly 字段中,因为它永远不会改变,也无需为每次访问重新计算。

【讨论】:

感谢您的解释!我想我会使用Marshal.ReadIntPtr 方法,因为它不需要不安全的代码并且(我想)它不需要在获取属性之前获取结构。再次感谢! 另外和shigtly无关,如果我只想提取一次字段,我应该使用第二种方法吗? @user2223034 如果您只想这样做一次,请使用您最容易阅读和完全理解的任何一种形式。其中哪一个是我无法为您做出的决定。 好的,无论如何,目前看来我必须多次使用这些字段。谢谢。问候!

以上是关于如何在 C# 中获取 IntPtr 指针的属性的主要内容,如果未能解决你的问题,请参考以下文章

我用C#,上一步函数返回了一个IntPtr型的图片指针,我已知图片的长、宽,如何转换成image类。

创建 COM 接口,返回一个在 C# 中编组为 IntPtr 的指针

C# 句柄指针的 JFrame 等效项

在 C# 中传递 IntPtr 指针后,在非托管 C++ 代码中分配数组,编组类型

如何释放/释放 IntPtr 到函数指针?

如何通过 IntPtr 将 c++ 数组编组为 c#