2009-12-28 209 views
10

我在一些小的測試應用程序中創建了一個附加線程,並且想要暫掛這個附加線程的主線程。附加線程通過CreateRemoteThread從外部進程創建。獲取進程主線程的句柄

由於SuspendThread需要一個HANDLE到應該被掛起的線程,我想知道如何從運行在我的附加線程中的代碼獲得這個HANDLE

+0

什麼是你的目標平臺? – 2009-12-28 14:03:17

+0

這是Windows 7下的一個32位程序。我使用Visual Studio 2008,因此使用Visual C++。 – Etan 2009-12-28 14:09:00

+0

你只想暫停「主」線程還是全部?你究竟想達到什麼目的?它可能有另一種方式來做到這一點...... – cedrou 2009-12-28 14:14:01

回答

6
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; 
} 
+0

是否保證進程的「主」線程始終是快照中的第一個線程?另外,問題不在於如何確定主線程;這是關於如何得到一個句柄,這個答案忽略。 – 2010-07-14 14:00:07

+5

甚至沒有保證進程的「主」線程仍然存在!該進程的主線程可能已經完成了'ExitThread'。 – 2011-11-09 00:20:14

2

這種類型的許多有用的API函數都在(當然是!)Tool Help套件下。 CreateToolhelp32Snapshot() API將爲指定的進程拍攝正在運行的線程的快照。

// Take a snapshot of all running threads 
hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); 
if(hThreadSnap == INVALID_HANDLE_VALUE) 
    return(FALSE); 

完整的示例代碼here.

的結構返回不區分與其他主線程。我不知道這樣做的機制;而一些版本的C運行時將在主線程結束時全部使用ExitProcess(),在所有最新版本中,進程將繼續運行,直到最後一個線程退出。

Interjay建議使用GetThreadTimes可能是最好的選擇。如果您可以CreateProcess()目標進程,則PROCESS_INFORMATION塊的hThread成員包含主線程的tid。歡迎來自他人的任何想法。

+0

我想知道像OllyDbg這樣的軟件如何找出「主線程」是什麼。您也可以使用它附加到已經運行的進程。 – Etan 2009-12-28 16:38:58

+0

DebugActiveProcess() - http://msdn.microsoft.com/en-us/library/ms679295%28VS.85%29.aspx GetThreadContext()返回「當前線程上下文」的寄存器,但不區分主我知道的線程。 – 2009-12-28 21:20:30

3

你爲什麼不只是創建一個計劃範圍的全球性(使用extern如果你有)

HANDLE mainThread ; 
DWORD mainThreadId ; 

在主的第一行,(在創建任何線程之前)做

mainThread = GetCurrentThread() ; 
mainThreadId = GetCurrentThreadId() ; 

您可以使用any form of IPC共享所述1D或與遠程進程的句柄(未驗證共享手柄會工作,但它應該!)

+0

爲什麼在main而不是簡單的'HANDLE mainThread = GetCurrentThread()'? – Liviu 2014-06-17 14:01:57

+0

也問在這裏:http://stackoverflow.com/questions/13287963/id-of-main-thread-in-c – Liviu 2014-06-17 14:08:16

+1

根據'GetCurrentThread()'的文檔,它返回一個僞句柄,而不是句柄,所以使用它進行比較,我不會假設。 – Pol 2016-07-06 03:01:04

6

獲取線程ID使用此項功能:

/* 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; 
} 

簡單的開線程獲取句柄:

/* 
* 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); 
} 
+2

我不相信這會在各種環境下完美運作。具體來說,假設Tib地址在所有機器上的每個進程中都是相同的,甚至GetMainThreadId()的調用者都是主線程,對吧?你應該解釋它是如何工作的,因爲它有太多可疑的事情要問。 – Laie 2015-06-26 01:31:25

+0

這真棒,但我試圖使一個功能與32位和64位兼容 – Acidic 2017-09-19 06:29:07