使用CreateProcess()并退出/关闭打开的应用程序



我正在构建一个程序,该程序将打开Sublime文本并在一段时间后关闭应用程序本身。我不知道如何使用现有的代码关闭应用程序。

这是我目前为止写的:

STARTUPINFO         siStartupInfo;
PROCESS_INFORMATION piProcessInfo;
memset(&siStartupInfo, 0, sizeof(siStartupInfo));
memset(&piProcessInfo, 0, sizeof(piProcessInfo));
siStartupInfo.cb = sizeof(siStartupInfo);
if (CreateProcess(L"C:\Program Files\Sublime Text 2\sublime_text.exe",       
    L" source.cpp",                 
    NULL,
    NULL,
    FALSE,
    CREATE_DEFAULT_ERROR_MODE,
    NULL,
    NULL,
    &siStartupInfo,
    &piProcessInfo) == FALSE)
    WaitForSingleObject(piProcessInfo.hProcess, INFINITE);
::CloseHandle(piProcessInfo.hThread);
::CloseHandle(piProcessInfo.hProcess);

首先,如果CreateProcess() 失败,则呼叫WaitForSingleObject()CloseHandle(),这是无用的。除非成功,否则不要调用这些函数

第二,您正在调用CreateProcess()的Unicode版本,它有一个警告,您的代码不能处理。根据CreateProcess()文档:

lpCommandLine [in, out, optional]
要执行的命令行。此字符串的最大长度为32,768个字符,包括Unicode终止null字符。如果lpApplicationName为NULL, lpCommandLine的模块名部分被限制为MAX_PATH字符。

这个函数的Unicode版本CreateProcessW可以修改这个字符串的内容。因此,该形参不能是指向只读内存的指针(如const变量或字面值字符串)。

如果该参数为常量字符串,则该函数可能导致访问冲突。
第三,如果您想在超时后终止进程,可以使用TerminateProcess(),但这是蛮力,应该尽可能避免。Sublime有一个UI,所以首选的解决方案是要求UI关闭自己,然后等待它这样做,正如MSDN上的文档:

如何"干净利落地"终止应用程序;在Win32 .

如果您必须关闭一个进程,请遵循以下步骤:

  1. Post一个WM_CLOSE命令给你想要关闭的进程所有的顶层窗口。许多Windows应用程序对此消息的响应是关闭。

注意:控制台应用程序对WM_CLOSE的响应取决于它是否安装了控件处理程序。

使用EnumWindows()查找目标窗口的句柄。在回调函数中,检查windows的进程ID是否与您想要关闭的进程匹配。你可以通过调用GetWindowThreadProcessId()来做到这一点。一旦你建立了一个匹配,使用PostMessage()或SendMessageTimeout()将WM_CLOSE消息发送到窗口。

  • 使用WaitForSingleObject()等待进程句柄。确保使用超时值等待,因为在很多情况下WM_CLOSE不会关闭应用程序。记住要使超时足够长(使用WaitForSingleObject()或SendMessageTimeout()),以便用户可以响应为响应WM_CLOSE消息而创建的任何对话框。

  • 如果返回值为WAIT_OBJECT_0,则应用程序将自己关闭。如果返回值为WAIT_TIMEOUT,则必须使用TerminateProcess()来关闭应用程序。

  • 注意:如果您从WaitForSingleObject()中获得的返回值不是WAIT_OBJECT_0或WAIT_TIMEOUT,请使用GetLastError()来确定原因。

    通过执行这些步骤,您可以为应用程序提供最佳的干净关机机会(除了IPC或用户干预之外)。

    说了这些,试着这样做:

    BOOL CALLBACK SendWMCloseMsg(HWND hwnd, LPARAM lParam)
    {
        DWORD dwProcessId = 0;
        GetWindowThreadProcessId(hwnd, &dwProcessId);
        if (dwProcessId == lParam)
            SendMessageTimeout(hwnd, WM_CLOSE, 0, 0, SMTO_ABORTIFHUNG, 30000, NULL);
        return TRUE;
    }
    ...
    STARTUPINFO         siStartupInfo;
    PROCESS_INFORMATION piProcessInfo;
    memset(&siStartupInfo, 0, sizeof(siStartupInfo));
    memset(&piProcessInfo, 0, sizeof(piProcessInfo));
    siStartupInfo.cb = sizeof(siStartupInfo);
    WCHAR szFilename[] = L"C:\full path to\source.cpp";
    if (CreateProcess(L"C:\Program Files\Sublime Text 2\sublime_text.exe",       
        szFileName,                 
        NULL,
        NULL,
        FALSE,
        CREATE_DEFAULT_ERROR_MODE,
        NULL,
        NULL,
        &siStartupInfo,
        &piProcessInfo))
    {
        CloseHandle(piProcessInfo.hThread);
        WaitForInputIdle(piProcessInfo.hProcess, INFINITE);
        if (WaitForSingleObject(piProcessInfo.hProcess, SomeTimeoutHere) == WAIT_TIMEOUT)
        {
            EnumWindows(&SendWMCloseMsg, piProcessInfo.dwProcessId);
            if (WaitForSingleObject(piProcessInfo.hProcess, AnotherTimeoutHere) == WAIT_TIMEOUT)
            {
                // application did not close in a timely manner, do something...
                // in this example, just kill it.  In a real world
                // app, you should ask the user what to do...
                TerminateProcess(piProcessInfo.hProcess, 0);
            }
        }
        CloseHandle(piProcessInfo.hProcess);
    }
    

    最新更新