Что лучше / безопаснее использовать: HandleRef или IntPtr (более новый исходный код от Microsoft больше не использует HandleRef) - PullRequest
14 голосов
/ 02 декабря 2010

Например, в старом исходном коде .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 Code Pack (от 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 Code Pack, хотя он активно использовался в сигнатурах собственных методов в старых исходных файлах .NET Framework.

Ответы [ 3 ]

9 голосов
/ 02 декабря 2010

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

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

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

3 голосов
/ 02 декабря 2010

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

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

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

3 голосов
/ 02 декабря 2010

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

...