Sei*_*eld -3 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);
Run Code Online (Sandbox Code Playgroud)
首先,您正在调用WaitForSingleObject()and CloseHandle()if CreateProcess() failed,这是无用的。除非成功,否则不要调用这些函数。
其次,您正在调用 的 Unicode 版本CreateProcess(),但需要注意的是,您的代码无法处理。根据CreateProcess()文档:
lpCommandLine [in, out, optional]
要执行的命令行。此字符串的最大长度为 32,768 个字符,包括 Unicode 终止空字符。如果 lpApplicationName 为 NULL,则 lpCommandLine 的模块名称部分限制为 MAX_PATH 个字符。此函数的 Unicode 版本 CreateProcessW 可以修改此字符串的内容。因此,此参数不能是指向只读内存的指针(例如 const 变量或文字字符串)。如果此参数是一个常量字符串,该函数可能会导致访问冲突。
第三,如果你想在超时后终止进程,你可以使用TerminateProcess(),但这是蛮力,应该尽可能避免。Sublime 有一个 UI,所以首选的解决方案是让 UI 关闭自己,然后等待它关闭,如 MSDN 上所述:
如果您绝对必须关闭某个进程,请执行以下步骤:
向要关闭的进程拥有的所有顶级窗口发布 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);
}
Run Code Online (Sandbox Code Playgroud)