Как процесс Win32 может получить pid своего родителя?

В настоящее время я передаю pid в командной строке дочернему элементу, но есть ли способ сделать это в Win32 API? В качестве альтернативы, может ли кто-нибудь облегчить мой страх, что pid, который я передаю, может принадлежать другому процессу через некоторое время, если родитель умер?


person twk    schedule 08.10.2008    source источник
comment
Windows XP не переназначает родительский PID равным -1 при завершении родительского процесса, поэтому возможно (и я видел, как это происходит) дерево процессов неверно. Таким образом, вы можете видеть NOTEPAD.EXE как родителя IEXPLORE.EXE в дереве, показанном Process Explorer, что явно неверно.   -  person Kevin Panko    schedule 28.06.2012


Ответы (5)


Обратите внимание, что если родительский процесс завершится, вполне возможно и даже вероятно, что PID будет повторно использован для другого процесса. Это стандартная операция Windows.

Поэтому, чтобы быть уверенным, как только вы получите идентификатор родителя и убедитесь, что это действительно ваш родитель, вы должны открыть его дескриптор и использовать его.

person shoosh    schedule 08.10.2008
comment
Это делается с помощью OpenProcess(). Смотрите ссылку в ответе artur02 ниже. - person Andreas Haferburg; 11.04.2013
comment
Повторно используемые PID могут быть обнаружены путем дополнительной проверки времени запуска. У реального родителя время начала будет раньше, чем у ребенка, у повторно используемого - после. - person ivan_pozdeev; 29.10.2014

На всякий случай, если кто-то еще столкнется с этим вопросом и ищет образец кода, мне пришлось сделать это недавно для проекта библиотеки Python, над которым я работаю. Вот тестовый/примерный код, который я придумал:

#include <stdio.h>
#include <windows.h>
#include <tlhelp32.h>

int main(int argc, char *argv[]) 
{
    int pid = -1;
    HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    PROCESSENTRY32 pe = { 0 };
    pe.dwSize = sizeof(PROCESSENTRY32);

    //assume first arg is the PID to get the PPID for, or use own PID
    if (argc > 1) {
        pid = atoi(argv[1]);
    } else {
        pid = GetCurrentProcessId();
    }

    if( Process32First(h, &pe)) {
        do {
            if (pe.th32ProcessID == pid) {
                printf("PID: %i; PPID: %i\n", pid, pe.th32ParentProcessID);
            }
        } while( Process32Next(h, &pe));
    }

    CloseHandle(h);
}
person Jay    schedule 17.02.2009
comment
у тебя случайно нет python-версии? - person Alex Okrushko; 30.08.2012
comment
Этот подход может предоставить устаревшие идентификаторы PID, как упоминалось в другом месте, и он может даже иметь циклы, если вы попытаетесь пройти родительские идентификаторы. - person jws; 11.09.2014
comment
+1000000 за пример кода. Не знаю, что в последнее время со stackoverflow, но я устал просматривать десятки страниц на веб-сайте программирования, не видя никакого кода. - person ; 28.02.2015
comment
Возможно, вы захотите добавить проверку для INVALID_HANDLE_VALUE. if ( h == INVALID_HANDLE_VALUE ) { // got an invalid handle - person hmatt1; 28.10.2015
comment
@JamesSchmidt, под циклами вы подразумеваете, что родитель процесса также может быть его потомком/потомком? При каких условиях это могло произойти? - person GetFree; 18.04.2017
comment
Родительский процесс может завершиться при работающем дочернем процессе, а дочерний по-прежнему будет удерживать PID этого старого родительского процесса. Затем позже PID может быть переназначен, и потом дочерний родитель по-прежнему ссылается на этот PID, который теперь может быть даже его собственным дочерним! - person jws; 18.04.2017

Лучший способ сделать это — вызвать DuplicateHandle() для создания наследуемой копии вашего дескриптора процесса. Затем создайте дочерний процесс и передайте значение дескриптора в командной строке. Close дублированный дескриптор в родительском процессе. Когда дочерний элемент закончит работу, ему также потребуется Close свою копию.

person Peter Ruderman    schedule 11.06.2009
comment
Этот метод имеет то преимущество, что дескриптор действительно будет ссылаться на вашего родителя, даже если родитель умрет до того, как вы получите к нему доступ. При использовании метода передачи pid потенциально существует состояние гонки (хотя и очень маловероятное) между передачей pid, доступом к нему дочернего элемента, завершением работы родителя и повторным использованием pid... - person Len Holgate; 11.06.2009
comment
Спасибо, Питер... DuplicateHandle - это именно то, что я искал. Вы правы, HANDLE лучше, чем PID (я просто хотел использовать WaitForSingleObject, чтобы дочерний элемент мог завершиться, если родитель неожиданно завершает работу). - person Matt Gallagher; 03.07.2010
comment
Одним из аргументов, необходимых для DuplicateHandle, является дескриптор целевого процесса. Вы написали, что сначала вы создаете дубликат дескриптора, а затем создаете дочерний процесс. Это ерунда. Вы должны сначала создать дочерний процесс, а затем создать дубликат дескриптора процесса. Таким образом, вы не можете передать значение дескриптора в командной строке. - person truthseeker; 21.01.2015
comment
@truthseeker: Нет ... сначала вы должны продублировать дескриптор. В противном случае дочерний процесс не смог бы его наследовать. Вы можете передать повторяющийся дескриптор в командной строке, потому что унаследованный дескриптор в дочернем процессе будет иметь то же числовое значение, что и в родительском процессе. Подумайте об этом: наследование дескрипторов было бы довольно бесполезным, если бы вы не могли получить доступ к этим дескрипторам в процессах, которые их унаследовали! - person Peter Ruderman; 21.01.2015
comment
Чтобы уточнить: обычно вы должны либо дублировать или наследовать дескриптор. Однако в этом случае все, что у вас есть, это псевдодескриптор, возвращаемый функцией GetCurrentProcess(), который не может быть унаследован. Таким образом, вы должны продублировать его, чтобы создать настоящий наследуемый дескриптор. Причина использования наследования заключается в том, что если вы дублируете дескриптор непосредственно дочернему процессу, у вас нет простого способа сообщить дочернему процессу, что такое значение дескриптора. - person Harry Johnston; 30.01.2015
comment
Почему родитель должен закрыть дескриптор своего собственного процесса? Не будет ли он автоматически закрыт при выходе из родительского процесса? Точно так же я ожидаю, что дочернему процессу нужно будет закрыть полученный дескриптор только в том случае, если он ожидает, что родительский процесс переживет его. - person Oliver Bock; 29.07.2020
comment
@Oliver Block: Строго говоря, для большинства приложений закрытие дескрипторов не требуется. Но это хорошая гигиена. Имейте в виду, что дескрипторы — это ограниченный ресурс. Если их небрежно слить, то можно выбежать. - person Peter Ruderman; 12.10.2020

«В качестве альтернативы, может ли кто-нибудь облегчить мои опасения, что pid, который я передаю, может принадлежать другому процессу через некоторое время, если родитель умер?»

Да, PID можно использовать повторно. В отличие от UNIX, Windows не поддерживает строгое дерево отношений родитель-потомок.

person user15071    schedule 08.10.2008
comment
Также в LINUX повторно используются идентификаторы процессов. Просто потому, что pid_t не имеет бесконечного размера. MAXPID 2^15. Я вижу, что это происходит несколько раз в течение дня. С другой стороны, в Windows существует сильная связь родитель-потомок через дескрипторы — пока вы держите дескриптор открытым, вы можете продолжать ссылаться на родительский процесс. - person ; 08.01.2016

person    schedule
comment
Перед использованием NtQueryInformationProcess помните, что это неподдерживаемый API, и я цитирую ссылку: NtQueryInformationProcess может быть изменен или недоступен в будущих версиях Windows. Кроме того, даже в документации поле идентификатора родительского процесса является зарезервированным полем. - person Marc Durdin; 24.11.2015
comment
Правильно, не очень хорошо работает с последним msvc 2017 - person Stef; 07.02.2019
comment
Я считаю, что этот метод в основном работает, но иногда NtQueryInformationProcess возвращает 0xC0000024 или 0xC0000008. - person Oliver Bock; 29.07.2020