Безопасные дескрипторы при маршалинге структур 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;мои знания немного устарели.