I have created an additional thread in some small testing app and want to suspend the main thread from this additional thread. The additional thread is created via CreateRemoteThread
from an external process.
Since SuspendThread
needs a HANDLE
to the thread which should be suspended, I want to know how to get this HANDLE
from code running in my additional thread.
I don't think there is anything that differentiates the main thread from other threads once the process has started. However, you can enumerate all threads in the process, and use GetThreadTimes to find the thread with the earliest creation time. Call OpenThread to get a HANDLE
from a thread ID.
DWORD GetMainThreadId () {
const std::tr1::shared_ptr<void> hThreadSnapshot(
CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0), CloseHandle);
if (hThreadSnapshot.get() == INVALID_HANDLE_VALUE) {
throw std::runtime_error("GetMainThreadId failed");
}
THREADENTRY32 tEntry;
tEntry.dwSize = sizeof(THREADENTRY32);
DWORD result = 0;
DWORD currentPID = GetCurrentProcessId();
for (BOOL success = Thread32First(hThreadSnapshot.get(), &tEntry);
!result && success && GetLastError() != ERROR_NO_MORE_FILES;
success = Thread32Next(hThreadSnapshot.get(), &tEntry))
{
if (tEntry.th32OwnerProcessID == currentPID) {
result = tEntry.th32ThreadID;
}
}
return result;
}
Get the thread id with this function:
/* CAUTION: ONLY x86 TESTED
* get the thread id of the main thread of a target process
*
* params:
* DWORD dwPid process id of the target process
*
* return:
* Success thread id
* Error NULL
*/
DWORD GetMainThreadId(DWORD dwPid)
{
LPVOID lpTid;
_asm
{
mov eax, fs:[18h]
add eax, 36
mov [lpTid], eax
}
HANDLE hProcess = OpenProcess(PROCESS_VM_READ, FALSE, dwPid);
if(hProcess == NULL)
return NULL;
DWORD dwTid;
if(ReadProcessMemory(hProcess, lpTid, &dwTid, sizeof(dwTid), NULL) == FALSE)
{
CloseHandle(hProcess);
return NULL;
}
CloseHandle(hProcess);
return dwTid;
}
Simple open the thread to get the handle:
/*
* get a handle to the main thread of a target process
* if successfull, the returned handle must be closed with CloseHandle()
*
* params:
* DWORD dwPid process id of the target process
* DWORD dwDesiredAccess desired access rights to the thread
*
* return:
* Success thread handle with desired access rights
* Error NULL
*/
HANDLE GetMainThreadHandle(DWORD dwPid, DWORD dwDesiredAccess)
{
DWORD dwTid = GetMainThreadId(dwPid);
if(dwTid == FALSE)
return NULL;
return OpenThread(dwDesiredAccess, FALSE, dwTid);
}
Why don't you just create a program-wide global (use extern if you have to)
HANDLE mainThread ;
DWORD mainThreadId ;
On the first line of main, (before any threads are created) do
mainThread = GetCurrentThread() ;
mainThreadId = GetCurrentThreadId() ;
You can use any form of IPC to share either the id or the HANDLE with the remote process (haven't verified sharing the HANDLE will work but it should!)
A number of useful API functions of this type are under the (of course!) Tool Help suite. The CreateToolhelp32Snapshot()
API will take a snapshot of the running threads for a specified process.
// Take a snapshot of all running threads
hThreadSnap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
if( hThreadSnap == INVALID_HANDLE_VALUE )
return( FALSE );
Full example code here.
The struct returned does not differentiate the primary thread from the others. I do not know a mechanism to do so; while some versions of the C runtime will all ExitProcess() at the end of the primary thread, in all recent versions the process continues to run until the last thread exits.
Interjay's recommendation to use GetThreadTimes may be the best bet. If you can CreateProcess()
the target process, the hThread member of the PROCESS_INFORMATION
block contains the tid for the primary thread. Welcome any ideas from others.