GetExitCodeProcess()返回128

时间:2020-03-06 14:46:50  来源:igfitidea点击:

我有一个DLL作为扩展加载到第三方父进程中。我使用CreateProcess API从此DLL实例化外部进程(我自己的)。在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()(我现在正在测试该假设。)

我至少可以做一件事情来尝试解决该问题(不要使线程挂起),但是我首先要首先了解失败的根源。有谁知道这可能是什么原因以及如何解决?

解决方案

引用有关GetExitCodeProcess的MSDN文章:

如果进程已终止,则可以返回以下终止状态:

  • 在ExitProcess或者TerminateProcess函数中指定的退出值
  • 进程的main或者WinMain函数的返回值
  • 导致进程终止的未处理异常的异常值

考虑到我们描述的情况,我认为最有可能的原因是第三个原因:未处理的异常。查看我们创建的流程的来源。

我可以从代码示例中想到2个问题

1.首先使用creatprocess命令使用前两个参数。硬编码路径并调用notepad.exe,看看是否出现。继续进行调整,直到运行记事本。

2.与评论相反,如果我们将新进程的currentdirectory参数传递为NULL,它将使用该进程的当前工作目录从而不是父进程的起始目录启动新进程。

我假设外部进程exe由于无法在新路径中解析的dll依赖关系而无法正常启动。

ps:在调试器中监视@ err,hr,它将告诉我们最后一个错误代码的说明,

看看桌面堆内存。

本质上,桌面堆问题归结为资源耗尽(例如,启动太多进程)。当应用程序用尽了这些资源时,症状之一就是我们将无法启动新进程,并且对CreateProcess的调用将失败,代码为128.

请注意,我们在其中运行的上下文也有一定作用。例如,作为服务运行,与在控制台应用程序中测试代码相比,用完桌面堆的速度要快得多。

这篇文章有很多有关桌面堆的好信息

Microsoft支持还提供了一些有用的信息。