Winapi GetExitCodeProcess()返回128

Winapi GetExitCodeProcess()返回128,winapi,dll,process,Winapi,Dll,Process,我有一个DLL作为扩展加载到第三方父进程中。从这个DLL中,我使用CreateProcess API实例化外部进程(我自己的)。这在99.999%的情况下非常有效,但有时会突然失败并永久停止工作(可能重新启动父进程可以解决此问题,但这是不可取的,在解决问题之前,我不建议这样做。)失败的症状是外部进程不再被调用,即使CreteProcess()也是如此不报告错误,GetExitCodeProcess()返回128。以下是我所做工作的简化版本: STARTUPINFO si; ZeroMemory(

我有一个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.
}
startupinfosi;
零内存(&si,sizeof(si));
si.cb=sizeof(si);
si.dwFlags=STARTF_USESHOWWINDOW;
si.wShowWindow=SW_HIDE;
处理信息;
零内存(&pi,sizeof(pi));
如果(!CreateProcess(
NULL,//没有模块名称(使用命令行)。
"",
NULL,//进程句柄不可继承。
NULL,//线程句柄不可继承。
FALSE,//将句柄继承设置为FALSE。
CREATE\u SUSPENDED,//CREATE SUSPENDED。
NULL,//使用父级的环境块。
NULL,//使用父级的起始目录。
&si,//指向STARTUPINFO结构的指针。
&pi))//指向进程\信息结构的指针。
{
//处理错误。
}
其他的
{
//做点什么。
//恢复外部进程线程。
DWORD resumeThreadResult=ResumeThread(pi.hThread);
//ResumeThread()返回1,这是正常的
//(这意味着线程已挂起,但随后重新启动)
//等待外部进程完成。
DWORD waitForSingelObjectResult=WaitForSingleObject(pi.hProcess,无穷大);
//WaitForSingleObject()返回0,这是正常的。
//获取外部进程的退出代码。
德沃德出口代码;
if(!GetExitCodeProcess(pi.hProcess,&exitCode))
{
//处理错误。
}
其他的
{
//没有错误,但exitCode为128,该值
//在外部流程中不存在(即使
//已存在(它不重要,因为它不再被调用)
//错误代码128是Error\u WAIT\u NO\u子项,这将导致一些错误
//sense*if*GetExitCodeProcess()返回FALSE,然后我将
//使用GetLastError()获取错误\u等待\u否\u子项
}
//进程和线程的进程信息句柄已关闭。
}
外部进程可以从Windows资源管理器或命令行手动调用,它可以自行启动。这样调用它,在执行任何实际工作之前,会创建一个日志文件并记录有关它的一些信息。但是像上面描述的那样调用这个日志信息根本不会出现,所以我假设外部进程的主线程从未进入main()(我现在正在测试这个假设)


我至少可以做一件事来避免这个问题(不要启动挂起的线程),但我首先想了解失败的根源。有人知道是什么原因导致了这种情况,以及如何解决它吗?

引用了MSDN关于:

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

  • 中指定的退出值 退出进程或终止进程 作用
  • 来自 的main或WinMain函数 过程
  • 的异常值 导致异常的未处理异常 终止的过程

考虑到您描述的场景,我认为最有可能的原因是第三个:未处理的异常。请查看您创建的流程的源代码。

我可以从您的代码示例中想到两个问题

1.首先使用creatprocess命令的前两个参数。硬编码路径并调用notepad.exe,然后查看是否出现这种情况。继续调整,直到你有记事本运行

2.与您的注释相反,如果您已将新进程的currentdirectory参数传递为NULL,则它将使用进程的当前工作目录而不是父进程的起始目录来启动新进程

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


ps:在调试器中观察@err,hr,它将告诉您上一个错误代码的解释,

看看桌面堆内存

从本质上讲,桌面堆问题归结为资源耗尽(例如启动太多进程)。当您的应用程序耗尽这些资源时,其中一个症状是您将无法启动新进程,对CreateProcess的调用将失败,代码为128

请注意,您在其中运行的上下文也有一些影响。例如,作为服务运行时,您将比在控制台应用程序中测试代码更快地用完桌面堆

这有很多关于桌面堆的好信息


也有一些有用的信息。

错误代码128 error\u WAIT\u NO\u CHILDREN 128 0x80没有要等待的子进程。是的,我已经研究过了。在进行任何其他操作之前,流程会设置日志记录并记录其已启动。这从来没有出现过。我知道日志记录应该会成功,因为DLL(在父进程中运行)可以创建日志文件,因此子进程也应该能够创建日志文件。Roman,我也想到了这一点,但最坏的情况是,它不应该作为GetExitCode()的退出代码返回。可能它可以作为GetLastError()返回,但GetExitCodeProcess()返回一开始并不表示有错误(返回TRUE),我想我会给客户一个虚拟的外部流程,看看这是否是问题所在(尽管它不应该是因为它自己工作)忘了推荐编辑:我澄清了为什么我认为外部进程从未运行,我澄清了为什么我认为错误\u等待\u否\u儿童的解释不合适。感谢您的帮助