Правильное использование 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 вне небезопасных блоков или без разрешения компиляции небезопасного кода.
Я также не могу сказать вам, в чем смысл этого компонента, но это действительно не должно существовать. Рукоять должен принадлежать объекту, предоставляющему функциональность, которую представляет дескриптор, и отвечать за управление жизненным циклом этого дескриптора. Класс, который просто произвольно закрывает дескрипторы, которые он не выделял, пугающе плохой дизайн.