On Windows Vista onwards, there is a new Native API function named NtGetNextThread for thread enumeration1. The prototype for NtGetNextThread is as follows
NTSTATUS NTAPI NtGetNextThread(
ULONG HandleAttributes,//pass OBJ_XXX flags here
ULONG Flags,//must be zero
Threads in a process are maintained in a linked list in process object and NtGetNextThread makes use of that linked list to enumerate threads in a process.
Enumerating threads in a process2 via toolhelp snapshots has the drawback that all threads show up in the snapshot and one checks the pid of the threads in the snapshots to get to all threads in a process. This is a bit convoluted. NtGetNextThread seems at first glance to be more straightforward since you can specify the process you want to enumerate threads of - in the ProcessHandle parameter. The process should have been opened with at least PROCESS_QUERY_INFORMATION access.
For getting at the very first thread in the process, the thread handle passed is NULL since you have not got any handles yet. But for subsequent calls, one is supposed to pass the handle returned in the previous call (via NewThreadHandle parameter) to NtGetNextThread. NtGetNextThread returns STATUS_NO_MORE_ENTRIES when called after the last thread has been enumerated.
However there are oddities that one needs to consider when using NtGetNextThread. You cannot enumerate all threads in the system by this call. If both ProcessHandle and ThreadHandle parameters are passed as NULL, NtGetNextThread returns STATUS_INVALID_HANDLE. Therefore if you cannot open a process, you cannot enumerate threads in the process.
- 1 2