C#中正确使用IntPtr

本文关键字:IntPtr | 更新日期: 2023-09-27 17:57:28

认为我理解IntPtr的使用,尽管我真的不确定。

我从MSDN中复制了IDisposable模式,只是想看看我能从中得到什么,虽然我对它有很大的了解,但我不知道如何正确地实现IntPtr,甚至不知道它应该"指向"或引用什么。除此之外,我甚至不知道如何将整数、字符串、char、double等赋值或强制转换为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()
        { 
        }
    }
}

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

C#中正确使用IntPtr

您可以通过以下方式使用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方法来了解如何将字符串、doubles等写入IntPtr。

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

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

虽然它可以引用内存中的一个位置,但它不需要。就像在发布的代码中一样,它可以只引用句柄或其他不透明的数字。这一点很重要,因为P/Invoked系统调用的大小发生了变化(系统调用使用常量大小的整数,而有些调用取决于体系结构,指针始终依赖于体系结构)。IntPtr不需要自行处理,但其中包含的不透明数字可能指的是确实需要释放的资源;这都是API合同的一部分,在那里获得了价值。

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

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

快乐的编码。

IntPtr只是一种值类型,其大小与目标平台上指针的大小相匹配。您需要主要在处理非托管指针时使用它。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();
}

IntPtr是指针大小的整数,在32位系统上为32位,在64位系统上则为64位。它通常用于包装要移交给非托管函数的指针或句柄。"不安全"意味着你在C#代码中使用指针,所以IntPtrs在不安全块之外,或者out允许编译不安全的代码。

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