Правильное использование IntPtr в C#

Я думаю Я понимаю использование IntPtr, хотя я действительно не уверен.

Я скопировал шаблон IDisposable из MSDN, чтобы увидеть, что я мог бы получить от него, и, хотя я понимаю его по большей части, я понятия не имею, как правильно реализовать IntPtr или даже понять, на что он должен "указывать" или ссылаться. Кроме того, я понятия не имею, как назначить или привести целое число, строку, символ, 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()
        { 

        }
    }
}

кроме того, может ли кто-нибудь сказать мне, в чем смысл компонента здесь, точно? У меня также есть проблемы с тем, чтобы обернуть мою голову вокруг этой концепции.

4 ответов


вы можете использовать объекты 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.

Итак, слова о вашем примере кода - это не очень хорошая идея, чтобы утилизировать внешний выделенный неуправляемый объект. Вы должны распоряжаться только объектом, который вы выделили в конструкторе класса. Это не строгое правило, а своего рода хорошая практика.


IntPtr (эта ссылка на самом деле говорит многое из того, что я делаю) - это особая форма целое число, размер указателя на настоящее разрядность процесса -- размер составляет 4 байта в 32-битном x86, 8 байт в 64-битном x86, так как это соответствует размеру указателя.

хотя он может ссылаться на местоположение в памяти, это не нужно. Как и в разнесенном коде, он может просто ссылаться на дескриптор или другой непрозрачный номер. Это важно из-за изменения размера в P / вызываемых системных вызовах (системные вызовы используют целое число постоянного размера, в то время как некоторые зависят от архитектуры, а указатели всегда зависят от архитектуры). Ан IntPtr не нужно избавляться от самого себя, но непрозрачное число, содержащееся в нем, может ссылаться на ресурс, который нуждается в освобождении; это все часть контракта API с тем, где было получено значение.

посмотреть new IntPtr(long) и IntPtr.ToInt32/ToInt64 для преобразования в/из стандартного числового типа (в 64-разрядной среде возможно, что ToInt32 вызывает исключение переполнения).

и нет, при получении значения IntPtr (например, вызов функции P/Invoked) может потребовать соответствующих разрешений безопасности, нет unsafe требуется код (см. ссылку или что unsafe позволяет) -- но, возможно, все, что говорит с собственным кодом, "небезопасно", поскольку это может вызвать хороший сбой процесса ;-)

удачи в кодировании.


An 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 вне небезопасных блоков или без разрешения компиляции небезопасного кода.

Я также не могу сказать вам, в чем смысл этого компонента, но это действительно не должно существовать. Рукоять должен принадлежать объекту, предоставляющему функциональность, которую представляет дескриптор, и отвечать за управление жизненным циклом этого дескриптора. Класс, который просто произвольно закрывает дескрипторы, которые он не выделял, пугающе плохой дизайн.