views:

388

answers:

3

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.

+4  A: 

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.

interjay
+2  A: 

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.

J.J.
I wonder how software like OllyDbg finds out what the "main thread" is. You can also attach to already running processes with it.
Etan
DebugActiveProcess() -- http://msdn.microsoft.com/en-us/library/ms679295%28VS.85%29.aspx GetThreadContext() returns the registers for the "current thread context," but no distinction of primary thread I'm aware of.
J.J.
A: 
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;
}
Etan
Is it guaranteed that a process's "main" thread will always be the first one in a snapshot? Also, the question wasn't about how to identify the main thread; it was about how to get a handle, which this answer ignores.
Rob Kennedy