1

我有一个 DLL 作为扩展加载到第 3 方父进程中。在这个 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() (我现在正在测试这个假设。)

我至少可以做一件事来尝试规避问题(而不是启动暂停的线程),但我首先想先了解失败的根源。有谁知道什么可能导致这个以及如何解决它?

4

3 回答 3

1

引用GetExitCodeProcess上的 MSDN 文章:

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

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

鉴于您描述的场景,我认为最可能的原因是第三个:未处理的异常。查看您创建的流程的来源。

于 2008-09-26T12:47:39.247 回答
1

看看桌面堆内存。

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

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

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

Microsoft 支持也有一些有用的信息。

于 2008-10-23T17:44:04.553 回答
0

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

1.让你使用前 2 个参数到 creatprocess 命令首先工作。硬编码路径并调用 notepad.exe 并查看是否出现。继续调整它,直到你有记事本运行。

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

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

ps:在调试器中查看@err,hr,它会告诉你最后一个错误代码的解释,

于 2008-09-28T17:53:34.843 回答