При запуске процесса через вызовы winapi (например, CreateProcessAsUserW
) вы получаете дескриптор процесса и потока. С этим вы можете получить PID процесса и с его помощью вы можете сделать вызов Process.GetProcessById
. Однако, когда процесс уже завершился, этот вызов завершится ошибкой.
Есть ли способ вместо этого получить объект Process
по дескриптору?
Теперь я использую GetExitCodeProcess
, по крайней мере, для получения информации некоторый, но я бы предпочел вернуть объект Process
с соответствующими наборами свойств.
@IInspectable Очевидно, что нет. Если процесс исчез из диспетчера задач (но открытые ручки остаются), GetProcessById
завершится ошибкой. OpenProcess
будет успешным.
Итак, моя оценка относительного качества реализации библиотеки .NET верна. Спасибо за подтверждение.
@IInspectable Он перечисляет обрабатывает все и выдает искусственное исключение, если среди них нет запрошенного идентификатора (который действительно является глупый). Так неужели EnumProcesses
виноват?
Нет, EnumProcesses
в порядке. Дело в том, что авторы библиотеки решили выбрать неподходящий для решения конкретной задачи API для получения дескриптора процесса по ID. Я имею в виду, что OpenProcess
буквально принимает идентификатор процесса, но .NET не использует его в своей реализации GetProcessById
.
Да, я согласен, это действительно просто реализация GetProcessById
, которая не очень хороша. Или отсутствие звонка GetProcessByNativeHandle
, или что-то в этом роде. Я не заметил никаких альтернативных конструкторов/фабричных функций, которые я мог бы «эксплуатировать», чтобы получить то, что я хочу. И я бы предпочел воздержаться от использования отражения для установки соответствующих закрытых членов Process, чтобы он действовал как правильный объект Process.
@Ertyui Ну, вы могу называете частный конструктор.
@GSerg Я пробовал это, но получил «Конструктор типа« System.Diagnostics.Process »не найден». Вот что я сделал: Process new_process = Activator.CreateInstance(typeof(Process), ".", false, (int)pid, null) as Process;
Наверное, конструктора просто нет в сборке? :/
@GSerg Ах, подождите, ваш пример со ссылкой работает. Я упустил из виду перегрузку, которая позволяет как привязываться к частному конструктору, так и передавать аргументы :) Тогда я пойду по этому пути. Я знаю, что это не лучшее / будущее доказательство. Но это делает его намного чище ..
Я «решил» проблему, выполнив следующие действия:
// Construct Process object through private constructor, taking the PID. This also works when the process has already exited.
Process new_process = Activator.CreateInstance(typeof(Process), BindingFlags.Instance | BindingFlags.NonPublic, null, new object[] { ".", false, (int)pid, null }, null, null) as Process;
// Wrap the handle and give ownership to wrapper
SafeProcessHandle safe_handle = new SafeProcessHandle((IntPtr)process_handle, true);
// Set interal process handle for Process object through private method. This prevents the .ExitCode accessor to throw an exception.
typeof(Process).GetMethod("SetProcessHandle", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(new_process, new object[] { safe_handle });
Это работает, но как-то не очень. Потому что он обращается к двум закрытым функциям через отражение. Дополнительные сведения о внутреннем устройстве объекта Process см. в статье здесь.
Пока вы держитесь за дескриптор процесса,
GetProcessById
будет успешным. Или должен, во всяком случае (я думаю, но опять же, код .NET не совсем воплощение качества кода).