[英]How (best) to post WM_QUIT to a running process?
Enumerate processes & threads, then use PostThreadMessage(thread, WM_QUIT, 0, 0)
枚举进程和线程,然后使用PostThreadMessage(thread, WM_QUIT, 0, 0)
There are examples of such an approach:有这种方法的例子:
Enumerate top level windows, obtain the process identity, and send the message to the window:枚举顶级窗口,获取进程标识,并将消息发送到窗口:
Basically, what I want is a sure-fire way to tell my application - the specific instance that is started from a specific executable pathname (arguments don't matter - but path does), to shut down.基本上,我想要的是一种可靠的方式来告诉我的应用程序 - 从特定的可执行路径名(参数无关紧要 - 但路径重要)启动的特定实例,关闭。
Is there a better way entirely:有没有更好的方法:
Thanks in advance for any thoughts you might offer...预先感谢您提供的任何想法...
Here's how I solved it for myself, compatible with XP, and can deal with a process that has multiple top-level windows and multiple threads, assuming that the target process does correctly handle WM_QUIT for itself (which it certainly should!)这是我自己解决的方法,与 XP 兼容,并且可以处理具有多个顶级窗口和多个线程的进程,假设目标进程确实为自己正确处理了 WM_QUIT(它当然应该这样做!)
I'm targeting Win32 API from C++:我的目标是来自 C++ 的 Win32 API:
call Shutdown(filename);
调用Shutdown(filename);
That calls GetProcessID(filename)
to get the process ID And then calls EnumerateWindowThreads(processID)
in order to get the set of threads with top level windows (which we can assume are 'main' threads for the process), and uses PostThreadMessage(..., WM_QUIT, ...)
to ask each of them to terminate.调用GetProcessID(filename)
来获取进程 ID 然后调用EnumerateWindowThreads(processID)
以获取具有顶级窗口的线程集(我们可以假设它们是进程的“主”线程),并使用PostThreadMessage(..., WM_QUIT, ...)
要求他们每个人终止。
You can open a process handle on the process ID before posting the WM_QUIT
messages if you want to call GetExitCodeProcess(process_handle, &exit_code)
.如果您想调用GetExitCodeProcess(process_handle, &exit_code)
您可以在发布WM_QUIT
消息之前打开进程 ID 上的进程句柄。 Just make sure you obtain and hold open a process handle before/while you're posting the quits in order to ensure you have something to query after it is done...只需确保在发布退出之前/期间获得并保持打开一个进程句柄,以确保在完成后有一些东西要查询......
DWORD Shutdown(const TCHAR * executable) {
// assumption: zero id == not currently running...
if (DWORD dwProcessID = GetProcessID(executable)) {
for (DWORD dwThreadID : EnumerateWindowThreads(dwProcessID))
VERIFY(PostThreadMessage(dwThreadID, WM_QUIT, 0, 0));
}
}
// retrieves the (first) process ID of the given executable (or zero if not found)
DWORD GetProcessID(const TCHAR * pszExePathName) {
// attempt to create a snapshot of the currently running processes
Toolbox::AutoHandle::AutoCloseFile snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
if (!snapshot)
throw CWin32APIErrorException(_T(__FUNCTION__), _T("CreateToolhelp32Snapshot"));
PROCESSENTRY32 entry = { sizeof(PROCESSENTRY32), 0 };
for (BOOL bContinue = Process32First(snapshot, &entry); bContinue; bContinue = Process32Next(snapshot, &entry)) {
#if (_WIN32_WINNT >= 0x0600)
static const BOOL isWow64 = IsWow64();
if (isWow64) {
Toolbox::AutoHandle::AutoCloseHandle hProcess(OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, entry.th32ProcessID));
DWORD dwSize = countof(entry.szExeFile);
if (!QueryFullProcessImageName(hProcess, 0, entry.szExeFile, dwSize))
//throw CWin32APIErrorException(_T(__FUNCTION__), _T("QueryFullProcessImageName"));
continue;
}
#else
// since we require elevation, go ahead and try to read what we need directly out of the process' virtual memory
if (auto hProcess = Toolbox::AutoHandle::AutoCloseHandle(OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, FALSE, entry.th32ProcessID))) {
if (!GetModuleFileNameEx(hProcess, nullptr, entry.szExeFile, countof(entry.szExeFile)))
//throw CWin32APIErrorException(_T(__FUNCTION__), _T("GetModuleFileNameEx"));
continue;
}
#endif
if (compare_no_case(entry.szExeFile, pszExePathName) == STRCMP_EQUAL)
return entry.th32ProcessID; // FOUND
}
return 0; // NOT FOUND
}
// returns the set of threads that have top level windows for the given process
std::set<DWORD> EnumerateWindowThreads(DWORD dwProcessID) {
if (!dwProcessID)
throw CLabeledException(_T(__FUNCTION__) _T(" invalid process id (0)"));
std::set<DWORD> threads;
for (HWND hwnd = GetTopWindow(NULL); hwnd; hwnd = ::GetNextWindow(hwnd, GW_HWNDNEXT)) {
DWORD dwWindowProcessID;
DWORD dwThreadID = ::GetWindowThreadProcessId(hwnd, &dwWindowProcessID);
if (dwWindowProcessID == dwProcessID)
threads.emplace(dwThreadID);
}
return threads;
}
My apologies for using Toolbox::AutoHandle::AutoCloseHandle
and my various exception classes.我很抱歉使用Toolbox::AutoHandle::AutoCloseHandle
和我的各种异常类。 They're trivial - AutoCloseHandle is RAII for HANDLE, and the exception classes exist because our code base predates the standard library (and the standard library still can't deal with UNICODE exceptions anyway).它们是微不足道的 - AutoCloseHandle 是 HANDLE 的 RAII,并且存在异常类是因为我们的代码库早于标准库(而且标准库仍然无法处理 UNICODE 异常)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.