Маршал IntPtr в типичной безопасности - PullRequest
3 голосов
/ 21 февраля 2012

У меня есть следующие функции c

opaque_struct* create() {}
void free(opaque_struct*) {}

, которые я хочу вызвать с помощью PInvoke:

[DllImport("test")]
public static extern IntPtr create ();
[DllImport("test")]
public static extern void free (IntPtr);

Я думаю, это будет работать нормально, но я ищу способв управляемом коде явно указывается, что «free» принимает только IntPtr, возвращенный «create», и избегает случайной передачи другого IntPtr, полученного от других функций.

Структура, на которую указывает структура, непрозрачна в отношении всего управляемого кода.

Невозможно расширить IntPtr, даже если все, что я делаю, это даю ему новое имя, без дополнительных свойств.

Есть ли способ сделать этот типизированный IntPtr?

1 Ответ

6 голосов
/ 21 февраля 2012

При работе с неуправляемой памятью всегда существует вероятность «аварии» для каждого определения.

Тем не менее, вы можете обернуть IntPtr в класс, как Microsoft сделала со своим SafeHandle классом и связанными SafeFileHandle, SafePipeHandle ... и т. Д.

Вы можете создать свой собственный класс SafeHandle (вы можете наследовать от System.Runtime.InteropServices.SafeHandle) и использовать его в своих декларациях P / Invoke:

[DllImport("test")]
public static extern MySafeHandle create ();

[DllImport("test")]
public static extern void free (MySafeHandle pointer);

Другое преимущество SafeHandle состоит в том, что он реализует IDisposable и, таким образом, позволяет использовать оператор using, чтобы гарантировать, что ваш free() метод всегда называется:

using (MySafeHandle ptr = create())
{
    // Use your ptr instance here
    // You can retrieve the IntPtr value itself using
    // ptr.DangerousGetHandle()

    // When you get out of the scope of the using(), the MySafeHandle
    // object will be disposed and ptr.ReleaseHandle() will be called.
    // Just add your call to free() in the overriden ReleaseHandle method
}

Как вы можете видеть, даже не нужно вызывать free() вручную, так как это происходит автоматически при утилизации SafeHandle.

...