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

时间:2016-06-28 15:59:04

标签: c++ windows winapi

我正在构建一个可以打开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);

1 个答案:

答案 0 :(得分:4)

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

其次,您正在调用CreateProcess()的Unicode版本,其中有一个警告,您的代码未处理。根据{{​​3}}:

  

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

     

此函数的Unicode版本CreateProcessW可以修改此字符串的内容。因此,此参数不能是只读内存的指针(例如const变量或文字字符串)。如果此参数是常量字符串,则该函数可能会导致访问冲突。

第三,如果你想在超时后终止进程,你可以使用TerminateProcess(),但这是强力的,应该尽可能避免。 Sublime有一个UI,所以首选的解决方案是让UI自行关闭,然后等待它这样做,如MSDN上所述:

CreateProcess() documentation

  

如果您绝对必须关闭某个流程,请按以下步骤操作:

     
      
  1. 将WM_CLOSE发布到您要关闭的进程所拥有的所有顶级窗口。许多Windows应用程序通过关闭来响应此消息。

         

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

         

    使用EnumWindows()查找目标窗口的句柄。在回调函数中,检查窗口的进程ID是否与要关闭的进程匹配。您可以通过调用GetWindowThreadProcessId()来完成此操作。建立匹配后,使用PostMessage()或SendMessageTimeout()将WM_CLOSE消息发布到窗口。

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

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

         

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

  6.         

    通过执行这些步骤,您可以为应用程序提供最佳的干净关闭机会(除了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);
}