【问题标题】:Why those two different behaviors with WaitForSingleObject function in CPP为什么在 CPP 中具有 WaitForSingleObject 函数的这两种不同行为
【发布时间】:2017-01-05 22:22:49
【问题描述】:

我有以下代码示例:

#include <iostream>
#include <windows.h>
#include <string>

using namespace std;

void main()
{
    SHELLEXECUTEINFO ShExecInfo = { 0 };
    ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
    ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
    ShExecInfo.hwnd = NULL;
    ShExecInfo.lpVerb = NULL;
    ShExecInfo.lpFile = "cmd.exe";
    ShExecInfo.lpParameters = "";
    ShExecInfo.lpDirectory = NULL;
    ShExecInfo.nShow = SW_SHOW;
    ShExecInfo.hInstApp = NULL;
    ShellExecuteEx(&ShExecInfo);
    WaitForSingleObject(ShExecInfo.hProcess, INFINITE);
    std::cout << "hi! Im done!";
    system("pause");
}

当我尝试运行cmd.exe 的代码时,在我关闭cmd.exe 窗口之前,消息不会打印到屏幕上。

但是,当我尝试运行 calc.exe 的代码时,消息会在计算器进程结束之前打印到屏幕上。

为什么这两个可执行文件表现出不同的行为?

我想我对WaitForSingleObject()函数的理解错过了一些东西。

【问题讨论】:

  • 您尚未在调用线程上初始化 COM。你不应该期待任何特定的结果。阅读documentation 不是可选的。它还告诉您有关返回值的信息。

标签: c++ windows


【解决方案1】:

我在 Windows 10 上尝试了您的代码,SysInternals Process Monitor 显示以下内容:

如您所见,calc.exe 产生一个新进程然后结束,从而满足等待。这就是为什么你会立即看到你的输出。第二个过程是实际的计算器过程。就我而言,它位于以下路径:

C:\Program Files\WindowsApps\Microsoft.WindowsCalculator_10.1612.3341.0_x64__8wekyb3d8bbwe\Calculator.exe

【讨论】:

  • 这是因为计算器现在是商店应用程序。 (叹气。)
  • 对,现在我明白为什么我不能从资源管理器启动它了
【解决方案2】:

正如 marcinj 解释的那样,calc.exe 正在启动第二个进程,然后立即退出。您正在等待HANDLEcalc.exe 进程,因此当calc.exe 退出时,等待得到满足。

如果您想等到所有(大)子进程结束,您需要将calc.exe 进程包装在Job object 中。

调用CreateJobObject(),将calc.exe进程的HANDLE传递给AssignProcessToJobObject(),然后等待来自作业对象的通知(仅仅等待作业本身是行不通的,见How do I wait until all processes in a job have exited?解释原因)。

calc.exe 启动的任何新进程,以及它们启动的进程等等,都将自动添加到同一个作业中(除非它们通过 @ 的 CREATE_BREAKAWAY_FROM_JOB 标志明确请求不添加到作业中) 987654336@,但在这个例子中我们不用担心)。当作业通知您所有进程都已结束时,您可以停止等待进一步的通知。

例如:

#include <windows.h>
#include <iostream>
#include <string>

using namespace std;

int main()
{
    HANDLE Job = CreateJobObject(NULL, NULL);
    if (!Job)
    {
        std::cout << "CreateJobObject, error " << GetLastError() << "\n";
        return 0;
    }

    HANDLE IOPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
    if (!IOPort)
    {
        std::cout << "CreateIoCompletionPort, error " << GetLastError() << "\n";
        CloseHandle(Job);
        return 0;
    }

    JOBOBJECT_ASSOCIATE_COMPLETION_PORT Port;
    Port.CompletionKey = Job;
    Port.CompletionPort = IOPort;
    if (!SetInformationJobObject(Job, JobObjectAssociateCompletionPortInformation, &Port, sizeof(Port)))
    {
        std::cout << "SetInformation, error " << GetLastError() << "\n";
        CloseHandle(IOPort);
        CloseHandle(Job);
        return 0;
    }

    STARTUPINFO si = { sizeof(STARTUPINFO) };
    PROCESS_INFORMATION pi = {};

    WCHAR cmdline[] = L"calc.exe";
    if (!CreateProcessW(NULL, cmdline, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi))
    {
        std::cout << "CreateProcess, error " << GetLastError() << "\n";
        CloseHandle(IOPort);
        CloseHandle(Job);
        return 0;
    }

    if (!AssignProcessToJobObject(Job, pi.hProcess))
    {
        std::cout << "Assign, error " << GetLastError() << "\n";
        TerminateProcess(pi.hProcess, 0);
        CloseHandle(pi.hThread);
        CloseHandle(pi.hProcess);
        CloseHandle(IOPort);
        CloseHandle(Job);
        return 0;
    }

    ResumeThread(pi.hThread);
    CloseHandle(pi.hThread);
    CloseHandle(pi.hProcess);

    DWORD CompletionCode;
    ULONG_PTR CompletionKey;
    LPOVERLAPPED Overlapped;

    while (GetQueuedCompletionStatus(IOPort, &CompletionCode, &CompletionKey, &Overlapped, INFINITE))
    {
        if ((reinterpret_cast<HANDLE>(CompletionKey) == Job) &&
            (CompletionCode == JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO))
        {
            break;
        }
    }

    CloseHandle(IOPort);
    CloseHandle(Job);

    std::cout << "hi! Im done!";

    return 0;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多