GetExitCodeProcess() возвращает 128

У меня есть DLL, которая загружается в сторонний родительский процесс в качестве расширения. Из этой DLL я создаю внешние процессы (мои собственные) с помощью CreateProcess API. Это прекрасно работает в 99,999% случаев, но иногда это внезапно дает сбой и перестает работать навсегда (возможно, перезапуск родительского процесса решит эту проблему, но это нежелательно, и я не хочу рекомендовать это, пока не решу проблему.) сбой проявляется тем, что внешний процесс больше не вызывается, хотя CreteProcess() не сообщает об ошибке, и GetExitCodeProcess() возвращает 128. Вот упрощенная версия того, что я делаю:

STARTUPINFO si;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;

PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(pi));

if(!CreateProcess(
    NULL,   // No module name (use command line). 
    "<my command line>",
    NULL,   // Process handle not inheritable. 
    NULL,   // Thread handle not inheritable. 
    FALSE,  // Set handle inheritance to FALSE. 
    CREATE_SUSPENDED,  // Create suspended.
    NULL,   // Use parent's environment block. 
    NULL,   // Use parent's starting directory. 
    &si,    // Pointer to STARTUPINFO structure.
    &pi))   // Pointer to PROCESS_INFORMATION structure.
{
    // Handle error.
}
else
{
    // Do something.

    // Resume the external process thread.
    DWORD resumeThreadResult = ResumeThread(pi.hThread);
    // ResumeThread() returns 1 which is OK
    // (it means that the thread was suspended but then restarted)

    // Wait for the external process to finish.
    DWORD waitForSingelObjectResult =  WaitForSingleObject(pi.hProcess, INFINITE);
    // WaitForSingleObject() returns 0 which is OK.

    // Get the exit code of the external process.
    DWORD exitCode;
    if(!GetExitCodeProcess(pi.hProcess, &exitCode))
    {
        // Handle error.
    }
    else
    {
        // There is no error but exitCode is 128, a value that
        // doesn't exist in the external process (and even if it
        // existed it doesn't matter as it isn't being invoked any more)
        // Error code 128 is ERROR_WAIT_NO_CHILDREN which would make some
        // sense *if* GetExitCodeProcess() returned FALSE and then I were to
        // get ERROR_WAIT_NO_CHILDREN with GetLastError()
    }

    // PROCESS_INFORMATION handles for process and thread are closed.
}

Внешний процесс можно вызвать вручную из проводника Windows или командной строки, и он отлично запускается сам по себе. Вызванный таким образом, он, прежде чем выполнять какую-либо реальную работу, создает файл журнала и записывает некоторую информацию о нем. Но при вызове, как описано выше, эта информация журнала вообще не отображается, поэтому я предполагаю, что основной поток внешнего процесса никогда не входит в main() (сейчас я проверяю это предположение).

Есть по крайней мере одна вещь, которую я мог бы сделать, чтобы попытаться обойти проблему (не запускать приостановленный поток), но сначала я хотел бы понять причину сбоя. Кто-нибудь знает, что может быть причиной этого и как это исправить?


person Community    schedule 26.09.2008    source источник
comment
Забыл похвалить редактирование: я пояснил, почему я предполагаю, что внешний процесс никогда не запускается, и я пояснил, почему я не думаю, что объяснение ERROR_WAIT_NO_CHILDREN уместно.   -  person    schedule 26.09.2008


Ответы (3)


Цитата из статьи MSDN о GetExitCodeProcess:

Если процесс завершился, могут быть возвращены следующие статусы завершения:

  • Значение выхода, указанное в функции ExitProcess или TerminateProcess.
  • Возвращаемое значение из функции main или WinMain процесса
  • Значение исключения для необработанного исключения, вызвавшего завершение процесса.

Учитывая описанный вами сценарий, я думаю, что наиболее вероятной причиной является третья: необработанное исключение. Посмотрите на источник процессов, которые вы создаете.

person Treb    schedule 26.09.2008
comment
код ошибки 128 RROR_WAIT_NO_CHILDREN 128 0x80 Нет дочерних процессов для ожидания. - person RomanM; 26.09.2008
comment
Да, я рассмотрел это. Непосредственно перед чем-либо еще процесс настраивает ведение журнала и регистрирует, что он был запущен. Это никогда не появляется. Я знаю, что ведение журнала должно быть успешным, поскольку DLL (работающая в родительском процессе) может создавать файлы журнала, поэтому дочерний процесс также должен иметь возможность их создавать. - person ; 26.09.2008
comment
Роман, я тоже думал об этом, но в худшем случае это не должно возвращаться как код выхода из GetExitCodeProcess() Может быть, это может быть возвращено как GetLastError(), но GetExitCodeProcess() не указывает на ошибку в первую очередь (он возвращает TRUE ) - person ; 26.09.2008
comment
Я думаю, что дам клиенту фиктивный внешний процесс и посмотрю, не в этом ли проблема (хотя этого не должно быть, поскольку он работает сам по себе). - person ; 26.09.2008

Посмотрите на память Desktop Heap.

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

Обратите внимание, что контекст, в котором вы работаете, также оказывает некоторое влияние. Например, при работе в качестве службы куча рабочего стола будет исчерпана намного быстрее, чем при тестировании кода в консольном приложении.

В этом сообщении много хорошая информация о куче рабочего стола

В службе поддержки Microsoft также есть полезная информация.

person Nader Shirazie    schedule 23.10.2008

Есть 2 проблемы, о которых я мог подумать из вашего примера кода.

1. Сначала используйте первые 2 параметра команды creatprocess. Жестко закодируйте пути и вызовите notepad.exe и посмотрите, появится ли это. продолжайте настраивать это, пока у вас не запустится блокнот.

2. Вопреки вашему комментарию, если вы передали параметр currentdirectory для нового процесса как NULL, он будет использовать текущий рабочий каталог процесса для запуска нового процесса, а не начальный каталог родителя.

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

ps: в отладчике следите за @err,hr, который сообщит вам объяснение последнего кода ошибки,

person computinglife    schedule 28.09.2008
comment
Спасибо за ответ - хороший улов на комментарий. Ваше объяснение имеет смысл, но это не так. Проблема в защитной оболочке, используемой компанией. Когда я отправил тот же exe без него, он работал без проблем. Я опубликую объяснение. - person ; 30.09.2008
comment
Здравствуйте, столкнулся с похожей проблемой, не могли бы вы написать объяснение. - person Naga; 08.09.2011