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

问题描述 投票:0回答:1

我正在构建一个程序,该程序将打开 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);
c++ windows winapi
1个回答
7
投票

首先,如果

WaitForSingleObject()
fails
,您将调用
CloseHandle()
CreateProcess(),这是无用的。除非它成功,否则不要调用这些函数。

其次,您正在调用

CreateProcess()
的 Unicode 版本,它有一个警告,即您的代码未处理。根据
CreateProcess()
文档

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

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

第三,如果你想在超时后终止进程,你可以使用TerminateProcess()

,但这是蛮力,应该尽可能避免。 Sublime 有一个 UI,所以首选的解决方案是要求 UI 自行关闭,然后等待它关闭,如 MSDN 上所述:

如何在 Win32 中“干净地”终止应用程序.

如果您绝对必须关闭进程,请按照下列步骤操作:

    向您要关闭的进程拥有的所有顶级窗口发布 WM_CLOSE。许多 Windows 应用程序通过关闭来响应此消息。
注意:控制台应用程序对 WM_CLOSE 的响应取决于它是否安装了控制处理程序。

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

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

  2. 如果返回值为 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); }
    
© www.soinside.com 2019 - 2024. All rights reserved.