【发布时间】:2013-03-13 21:17:24
【问题描述】:
您能帮我找到由 ID 进程给定的主(唯一)线程 ID,好吗?
任务上下文: 一个正在运行的进程(目前)没有窗口,只有一个(一些)线程。
想要:
仅在主线程发布WM_QUIT。
不想要的:
在非主线程使用TerminateProcess 或发布WM_QUIT。
【问题讨论】:
标签: c++ c windows multithreading
您能帮我找到由 ID 进程给定的主(唯一)线程 ID,好吗?
任务上下文: 一个正在运行的进程(目前)没有窗口,只有一个(一些)线程。
想要:
仅在主线程发布WM_QUIT。
不想要的:
在非主线程使用TerminateProcess 或发布WM_QUIT。
【问题讨论】:
标签: c++ c windows multithreading
您不能将消息发布到特定线程。消息被放入队列中,并且仅从主线程处理。
如果您想关闭具有 UI 的 windows 进程,请查看using sendmessage to send wm_close to another process
【讨论】:
PostThreadMessage。实际上,如果 Win32 提供 PostProcessMessage 并且您的假设是正确的(或者至少为此目的以这种方式工作),这会容易得多。但唉,不是这样......
#ifndef MAKEULONGLONG
#define MAKEULONGLONG(ldw, hdw) ((ULONGLONG(hdw) << 32) | ((ldw) & 0xFFFFFFFF))
#endif
#ifndef MAXULONGLONG
#define MAXULONGLONG ((ULONGLONG)~((ULONGLONG)0))
#endif
bool CloseProcessMainThread(DWORD dwProcID)
{
DWORD dwMainThreadID = 0;
ULONGLONG ullMinCreateTime = MAXULONGLONG;
HANDLE hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (hThreadSnap != INVALID_HANDLE_VALUE) {
THREADENTRY32 th32;
th32.dwSize = sizeof(THREADENTRY32);
BOOL bOK = TRUE;
for (bOK = Thread32First(hThreadSnap, &th32); bOK;
bOK = Thread32Next(hThreadSnap, &th32)) {
if (th32.th32OwnerProcessID == dwProcID) {
HANDLE hThread = OpenThread(THREAD_QUERY_INFORMATION,
TRUE, th32.th32ThreadID);
if (hThread) {
FILETIME afTimes[4] = {0};
if (GetThreadTimes(hThread,
&afTimes[0], &afTimes[1], &afTimes[2], &afTimes[3])) {
ULONGLONG ullTest = MAKEULONGLONG(afTimes[0].dwLowDateTime,
afTimes[0].dwHighDateTime);
if (ullTest && ullTest < ullMinCreateTime) {
ullMinCreateTime = ullTest;
dwMainThreadID = th32.th32ThreadID; // let it be main... :)
}
}
CloseHandle(hThread);
}
}
}
#ifndef UNDER_CE
CloseHandle(hThreadSnap);
#else
CloseToolhelp32Snapshot(hThreadSnap);
#endif
}
if (dwMainThreadID) {
PostThreadMessage(dwMainThreadID, WM_QUIT, 0, 0); // close your eyes...
}
return (0 != dwMainThreadID);
}
【讨论】:
获取主线程的线程 id 一个更简单、更可靠的方法是让主线程使用::GetCurrentThreadId() 将自己的线程 id 记录到一个共享的全局变量中,可能在您的 WinMain 中或在开头的某个地方你的“主线程”:
MainThreadId_G = ::GetCurrentThreadId();
然后在你的其他线程中,你可以调用:::PostThreadMessage(MainThreadId_G, WM_QUIT, returncode, 0);
【讨论】:
我检查了 MFC 中是如何处理的,看起来 UI 线程是由构造函数确定的:
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\atlmfc\src\mfc\appcore.cpp:
CWinApp::CWinApp(LPCTSTR lpszAppName)
{
...
m_nThreadID = ::GetCurrentThreadId();
并且使用 MFC 调用 AfxGetApp()->m_nThreadID 您可以找出 UI 线程 ID。
但是 - 如果 .dll 不是从主线程加载,则此方法不起作用 - 然后即使 MFC 的方法也不起作用 - AfxGetApp()->m_nThreadID 将返回主线程以外的其他内容。
但通常您的 .dll 是从主线程加载的,但您的 .dll 不需要启用 mfc。我可以推荐这样的方法:
class GetMainThread
{
public:
GetMainThread()
{
m_nThreadID = ::GetCurrentThreadId();
}
DWORD m_nThreadID;
}getMainThread;
DWORD getUIThread()
{
DWORD id = 0;
if( AfxGetApp() != NULL )
id = AfxGetApp()->m_nThreadID;
else
id = getMainThread.m_nThreadID;
return id;
} //getUIThread
如果 .dll 由主 UI 线程加载,您将从构造函数调用(GetMainThread 类)中获得正确的线程 ID。
如果您不需要它们,请删除 AfxGetApp() 调用(在我的应用程序中我需要它们)
【讨论】:
你是否在寻找这个功能:
DWORD WINAPI GetProcessIdOfThreadId(_In_ DWORD ThreadId)
{
HANDLE Thread = OpenThread(THREAD_QUERY_LIMITED_INFORMATION, FALSE, ThreadId);
DWORD process_id = GetProcessIdOfThread(Thread);
CloseHandle(Thread);
return process_id;
}
【讨论】:
在 cpp 文件的开头使用它,而不是在函数中:
DWORD mainThreadID = ::GetCurrentThreadId();
这将在你的 main 函数被执行之前初始化 mainThreadID,保证是主线程。
【讨论】: