Безопасные дескрипторы при маршалинге структур Win32 (PROCESS_INFORMATION)

Я нахожусь в процессе преобразования моего кода Win32 p/invoke для использования SafeHandle классы вместо типичного IntPtr ручки.

Хотя все работает довольно хорошо DllImport подписи методов, я не могу на всю жизнь заставить их работать при маршалинге структур Win32 (т.е. PROCESS_INFORMATION).

// This works without issue.
[StructLayout(LayoutKind.Sequential)]
internal struct Win32ProcessInformation
{
    public IntPtr ProcessHandle { get; set; }
    public IntPtr ThreadHandle { get; set; }
    public int ProcessId { get; set; }
    public int ThreadId { get; set; }
}

// This does not work!
[StructLayout(LayoutKind.Sequential)]
internal struct Win32ProcessInformation
{
    public ProcessSafeHandle ProcessHandle { get; set; }
    public ThreadSafeHandle ThreadHandle { get; set; }
    public int ProcessId { get; set; }
    public int ThreadId { get; set; }
}

ProcessSafeHandle а также ThreadSafeHandle классы прекрасно работают с такими методами, как ReadProcessMemory или же WriteProcessMemory, но я не могу использовать их в структурах Win32, как указано выше.

Я пропускаю какую-то магию аннотаций?

1 ответ

Решение

Насколько я знаю*, маршалер взаимодействия не поддерживает использование SafeHandles в классах / структурах.

Так что работает нормально заменить IntPtr с SafeHandle в объявлении функции P/Invoke, но он не работает, чтобы заменить его в структуре. Ручки в PROCESS_INFORMATION структура должна быть инициализирована неуправляемым кодом, который ничего не знает об управляемом SafeHandle класс, поэтому CLR должен иметь специальные знания о том, как сделать необходимые [out] сортировочный.

Но не стоит беспокоиться. Там нет ничего плохого в вашем объявлении структуры как есть:

[StructLayout(LayoutKind.Sequential)]
internal struct Win32ProcessInformation
{
    public IntPtr ProcessHandle { get; set; }
    public IntPtr ThreadHandle { get; set; }
    public int ProcessId { get; set; }
    public int ThreadId { get; set; }
}

Если вы хотите, как только вы вызвали функцию, которая заполняет Win32ProcessInformation структура, вы можете создать SafeHandle объект для каждого из значений дескриптора, хранящихся в IntPtrs. Это обеспечит закрытие дескрипторов при сборке мусора (если вы забудете вызвать Dispose() ранее).

Для дескрипторов процесса (как в этом примере), SafeWaitHandleбудет хорошим выбором, так как все дескрипторы процесса ожидаемы. Это избавляет вас от необходимости делать дополнительную работу, потому чтоSafeWaitHandleпредоставляется уже как публичная специализация SafeHandle. (Говоря о выполнении дополнительной работы, я предполагаю, что вы уже проверили, чтобы убедиться, чтоProcess класс уже не включает причину, по которой вы P/Invoking API-интерфейсы процесса?)

* Возможно, это изменилось в самой последней версии CLR;мои знания немного устарели.

Другие вопросы по тегам