c++ - 我如何运行一个进程然后在它退出时得到通知?

标签 c++ winapi process

我正在尝试重新实现 .NET 的 Process.Exited事件,但到目前为止我一直没有成功。应用程序未打开未返回任何错误。我错过了什么?

#include <stdio.h>
#include <windows.h>

static void CALLBACK OnExited(void* context, BOOLEAN isTimeOut);

int main() 
{
    char *cmd = "C:\\Windows\\System32\\notepad.exe";
    STARTUPINFOA si = { sizeof(STARTUPINFOA) };
    //si.cb = STARTUPINFOA.sizeof;
    PROCESS_INFORMATION pi;
    if(CreateProcessA(NULL, cmd, NULL, NULL, FALSE, DETACHED_PROCESS | CREATE_SUSPENDED, NULL, NULL, &si, &pi))
    {
        HANDLE hWait;
        if(!RegisterWaitForSingleObject(&hWait, pi.hProcess, OnExited, NULL, INFINITE, WT_EXECUTEONLYONCE))
        {
            printf("register failed! = %d", GetLastError());
        }
    }
    else
    {
        printf("error = %d\n", GetLastError());
    }
}

static void CALLBACK OnExited(void* context, BOOLEAN isTimeOut)
{
    printf("OnExited got called!\n");
}

最佳答案

您正在使用 CREATE_SUSPENDED 标志创建新进程,但您没有恢复进程(通过将 pi.hThread 传递给 ResumeThread()) 注册新进程 HANDLE 后通知。即使您这样做了,您也不会在退出 main() 之前等待通知到达。

您也不会在使用完 pi.hThreadpi.hProcesshWait 后关闭它们。

尝试更像这样的东西:

#include <stdio.h>
#include <windows.h>

static void CALLBACK OnExited(void* context, BOOLEAN isTimeOut);

int main() 
{
    char *cmd = "C:\\Windows\\System32\\notepad.exe";

    STARTUPINFOA si = {};
    si.cb = sizeof(si);

    PROCESS_INFORMATION pi;

    if (!CreateProcessA(NULL, cmd, NULL, NULL, FALSE, DETACHED_PROCESS | CREATE_SUSPENDED, NULL, NULL, &si, &pi))
    {
        printf("create process error = %u\n", GetLastError());
    }
    else
    {
        HANDLE hWait = NULL;

        HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
        if (!hEvent)
        {
            printf("create event error = %u\n", GetLastError());
        }
        else if (!RegisterWaitForSingleObject(&hWait, pi.hProcess, OnExited, hEvent, INFINITE, WT_EXECUTEONLYONCE))
        {
            printf("register wait error = %u\n", GetLastError());
        }

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

        if (hEvent)
        {
            if (hWait)
            {
                WaitForSingleObject(hEvent, INFINITE);
                UnregisterWait(hWait);
            }

            CloseHandle(hEvent);
        }

        CloseHandle(pi.hProcess);
    }

    return 0;
}

static void CALLBACK OnExited(void* context, BOOLEAN isTimeOut)
{
    printf("OnExited got called!\n");
    SetEvent((HANDLE)context);
}

或者,如果省略 CREATE_SUSPENDED 标志,则可以省略 ResumeThread()。即使进程在等待线程开始监视它之前结束,等待通知仍然有效,只要您不在等待满足之前关闭进程句柄:

#include <stdio.h>
#include <windows.h>

static void CALLBACK OnExited(void* context, BOOLEAN isTimeOut);

int main() 
{
    char *cmd = "C:\\Windows\\System32\\notepad.exe";

    STARTUPINFOA si = {};
    si.cb = sizeof(si);

    PROCESS_INFORMATION pi;

    if (!CreateProcessA(NULL, cmd, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &si, &pi))
    {
        printf("create process error = %u\n", GetLastError());
    }
    else
    {
        CloseHandle(pi.hThread);

        HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
        if (!hEvent)
        {
            printf("create event error = %u\n", GetLastError());
        }
        else
        {
            HANDLE hWait = NULL;
            if (!RegisterWaitForSingleObject(&hWait, pi.hProcess, OnExited, hEvent, INFINITE, WT_EXECUTEONLYONCE))
            {
                printf("register wait error = %u\n", GetLastError());
            }
            else
            {
                WaitForSingleObject(hEvent, INFINITE);
                UnregisterWait(hWait);
            }

            CloseHandle(hEvent);
        }

        CloseHandle(pi.hProcess);
    }

    return 0;
}

static void CALLBACK OnExited(void* context, BOOLEAN isTimeOut)
{
    printf("OnExited got called!\n");
    SetEvent((HANDLE)context);
}

但是,无论哪种方式,在如此简单的控制台应用程序中使用 RegisterWaitForSingleObject() 都不是很有用。相反,它在多线程/GUI 应用程序中更有意义。对于此示例,您可以只使用 WaitForSingleObject() 代替:

#include <stdio.h>
#include <windows.h>

int main() 
{
    char *cmd = "C:\\Windows\\System32\\notepad.exe";

    STARTUPINFOA si = {};
    si.cb = sizeof(STARTUPINFOA);

    PROCESS_INFORMATION pi;

    if (!CreateProcessA(NULL, cmd, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &si, &pi))
    {
        printf("create process error = %d\n", GetLastError());
    }
    else
    {
        CloseHandle(pi.hThread);
        WaitForSingleObject(pi.hProcess, INFINITE);
        CloseHandle(pi.hProcess);
        printf("Exited!\n");
    }

    return 0;
}

关于c++ - 我如何运行一个进程然后在它退出时得到通知?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49161232/

相关文章:

c# - 将字符串数组作为缓冲区传递给 C++ 到 C#

c++ - 在什么平台上 memmove 和 memcpy 会有显着的性能差异?

c++ - 如何使用环境变量转换路径(例如 %temp%)

c++ - 什么 API 会启动 FTP 传输并向 GUI 报告状态?

bash - 是否可以将 STDIN 分布到并行进程中?

python - 如何知道windows中的进程是否在python中运行

c++ - 重新定义 C++ 关键字是否合法?

c# - 有人在 .NET 中使用过 Win32 API 函数 CredWrite 吗?

C++ 无法获取进程 ID (windows)

c++ - 与 std::condition_variable 相比,使用 std::atomic 的方法 wrt 在 C++ 中暂停和恢复 std::thread