Что лучше/безопаснее использовать: HandleRef или IntPtr (более новый исходный код от Microsoft больше не использует HandleRef)

Например, в старом исходном коде .NET Framework 2.0 (Windows Forms, Visual Studio 2005 - Whidbey) функция GetClientRect была определена с помощью HandleRef:

    [DllImport(ExternDll.User32, ExactSpelling=true, CharSet=CharSet.Auto)]
    public static extern bool GetClientRect(HandleRef hWnd, [In, Out] ref NativeMethods.RECT rect); 

В новом пакете кода Windows API (от Microsoft, 2009/2010) эта же функция определяется с помощью IntPtr:

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern bool GetClientRect(IntPtr hwnd, ref CoreNativeMethods.RECT rect);

На самом деле HandleRef не используется ни в одном из исходных файлов кода кода Windows API, в то время как он широко использовался в подписях собственных методов в старых исходных файлах .NET Framework.

Ответы

Ответ 1

Это немного подозрительно. HandleRef не требуется, когда значения дескриптора хранятся в производном объекте SafeHandle. Что объявляет пакет кода, ZeroInvalidHandle, с несколькими производными от него, как SafeWindowHandle.

Однако он никоим образом не использует ни один из этих классов SafeHandle. Не уверен, что это действительно так, многие расширения Vista и Win7 на самом деле являются COM-интерфейсами. Не традиционный API C API. Они сохраняются в живых через подсчет ссылок и, таким образом, не подвергаются подобному сбою сборщика мусора.

Лично я просто не беспокоюсь об этом. Получение объекта класса, собранного во время выполнения вызова API, является ошибкой. Это может произойти так же легко через микросекунду после завершения вызова API. Все еще ошибка, просто не тот, который вызывает отказ API. Не уверен, что я действительно хочу, чтобы это не провалилось, я бы предпочел исключение, когда у меня появился код в моем коде. Microsoft должна защитить себя от этого, они не хотят получить вину за исключение. Я делаю.

Ответ 2

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

Быстрый просмотр рефлектора в сигнатурах функций в различных классах NativeMethods, найденных в .NET Framework, показывает, что фактическое использование довольно хорошо разделено между ними.

Я предполагаю, что это основано на том, необходимо ли предотвращать преждевременный сбор мусора (который является основным преимуществом при использовании HandleRef). Также имейте в виду, что использование HandleRef не требуется, если только обработчик, который вы передаете, связан с управляемым объектом. Неуправляемые объекты не будут собирать мусор.

Ответ 3

IntPtr - это просто структура, которая обертывает указатель. Что касается HandleRef MSDN говорит "Обертка дескриптора с HandleRef гарантирует, что управляемый объект не будет мусором, собранным до тех пор, пока платформа не вызовет вызов завершается". Существует вероятность того, что GC может завершить обработку дескриптора во время P/Invoke, если вы не сделаете ничего с ним после вызова P/Invoke. Таким образом HandleRef выглядит более безопасным.