17

我了解 IntPtr 的使用,尽管我真的不确定。

我从 MSDN 复制了 IDisposable 模式只是为了看看我能从中得到什么,虽然我大部分都理解它,但我不知道如何正确实现 IntPtr,甚至不知道它应该“指向什么” “到,或参考。最重要的是,我什至不知道如何将整数、字符串、字符、双精度等分配或强制转换为 IntPtr 以从中创建指针。

另外,IntPtr 是否需要使用不安全的代码?

无论如何,这里有一些代码只是为了描绘我正在谈论的内容:

namespace Utilities
{   
    class Disposer : IDisposable
    {

        private IntPtr handle;

        private Component component = new Component(); 

        private bool disposed = false;

        public Disposer(IntPtr handle)
        {
            this.handle = handle;

        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if(!this.disposed)
            {
                if (disposing)
                {
                    component.Dispose(); 
                }
                CloseHandle(handle);

                handle = IntPtr.Zero;

                disposed = true;

            }
        }

        [System.Runtime.InteropServices.DllImport("Kernal32")]
        private extern static Boolean CloseHandle(IntPtr handle);
    }



    public unsafe class ExecuteMain
    {
        Object nuller = new Object();

        byte boa = 0;

        byte *blargh = boa;

        public static void Main()
        { 

        }
    }
}

另外,有人能告诉我这里组件的意义是什么吗?我也很难理解这个概念。

4

4 回答 4

20

您可以这样使用 IntPtr 对象:

        int test = 55;

        // Allocating memory for int
        IntPtr intPointer = Marshal.AllocHGlobal(sizeof(int));

        Marshal.WriteInt32(intPointer,test);

        // sending intPointer to unmanaged code here

        //Test reading of IntPtr object
        int test2 = Marshal.ReadInt32(intPointer); // test2 would be equal 55

        // Free memory
        Marshal.FreeHGlobal(intPointer);

您可以探索其他Marshal方法来了解如何将字符串、双精度等写入 IntPtr。

所以关于您的示例代码的话 - 处置外部分配的非托管对象不是一个好主意。您应该只处理您在类构造函数中分配的对象。这不是严格的规则,而是某种良好的做法。

于 2011-05-23T06:31:49.793 回答
7

IntPtr(这个链接实际上说明了我所做的大部分工作)是一种特殊形式的整数,它是进程当前位数的指针大小——在 32 位 x86 中大小为 4 个字节,在 64 位 x86 中为 8 个字节,因为这对应于指针的大小。

虽然它可以引用内存中的位置,但它不需要。正如在发布的代码中一样,它可能只是指一个句柄或其他不透明的数字。这很重要,因为 P/Invoked 系统调用的大小变化(系统调用使用常量大小的整数,而有些依赖于体系结构,而指针总是依赖于体系结构)。anIntPtr本身不需要释放,但其中包含的不透明数字可能指的是确实需要释放的资源;这是获取价值的 API 合同的所有部分。

参见new IntPtr(long)和 与IntPtr.ToInt32/ToInt64标准数字类型的转换(在 64 位环境中可能ToInt32会引发溢出异常)。

不,虽然获取IntPtr(例如调用 P/Invoked 函数)的值可能需要适当的安全权限,但不需要代unsafe​​码(参见链接或unsafe允许的内容)——但可以说任何与本机代码对话的东西都是“不安全的” " 因为它会导致一个不错的进程崩溃 ;-)

快乐编码。

于 2011-05-23T06:24:27.627 回答
5

AnIntPtr只是大小与目标平台上指针大小匹配的值类型。您主要需要在处理非托管指针时使用它。一个IntPtr本身不能被释放,因为它只代表内存中的一个位置。您的清理工作需要特定于IntPtr. 假设您有一个需要窗口句柄来完成工作的非托管函数。在这种情况下,您可以使用该属性Control.Handle来获取指向控件窗口句柄的指针。要正确清理控件及其基础窗口,您不必IntPtr处理对非托管句柄的引用,而是释放控件。

[DllImport("UnmanagedLibrary.dll")]
private static void DoSomethingWithWindowHandle(IntPtr windowHandle);

private void Foo()
{
    Form form = new Form();
    // ...
    DoSomethingWithWindowHandle(form.Handle);
    // ...
    form.Dispose();
}
于 2011-05-23T06:24:26.610 回答
2

IntPtr 是一个指针大小的整数,在 32 位系统上为 32 位,在 64 位系统上为 64 位。它通常用于包装要传递给非托管函数的指针或句柄,就像您所做的那样。“不安全”意味着您在 C# 代码中使用指针,因此 IntPtrs 在不安全块之外或不允许编译不安全代码。

我也不能告诉你那个组件的意义,但它真的,真的不应该存在。句柄应该由一个对象拥有,该对象公开句柄所代表的功能并负责管理该句柄的生命周期。一个任意关闭它没有分配的句柄的类是非常糟糕的设计。

于 2011-05-23T06:23:09.977 回答