The following example obtains a list of running threads for the specified process. First, the RefreshThreadList function takes a snapshot of the currently executing threads in the system using the CreateToolhelp32Snapshot function, then it walks through the list recorded in the snapshot, using the Thread32First and Thread32Next functions. The parameter for RefreshThreadList is the identifier of the process whose threads will be listed.
// Take a snapshot of all threads currently in the system.
hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (hThreadSnap == INVALID_HANDLE_VALUE)
return (FALSE);
// Fill in the size of the structure before using it.
te32.dwSize = sizeof(THREADENTRY32);
// Walk the thread snapshot to find all threads of the process.
// If the thread belongs to the process, add its information
// to the display list.
if (Thread32First(hThreadSnap, &te32))
{
do
{
if (te32.th32OwnerProcessID == dwOwnerPID)
{
printf( "\nTID\t\t%d\n", te32.th32ThreadID);
printf( "Owner PID\t%d\n", te32.th32OwnerProcessID);
printf( "Delta Priority\t%d\n", te32.tpDeltaPri);
printf( "Base Priority\t%d\n", te32.tpBasePri);
}
}
while (Thread32Next(hThreadSnap, &te32));
bRet = TRUE;
}
else
bRet = FALSE; // could not walk the list of threads
// If Windows NT:
if( osver.dwPlatformId == VER_PLATFORM_WIN32_NT )
{
// Load library and get the procedures explicitly. We do
// this so that we don't have to worry about modules using
// this code failing to load under Windows 95, because
// it can't resolve references to the PSAPI.DLL.
hInstLib = LoadLibraryA( "PSAPI.DLL" ) ;
if( hInstLib == NULL )
return FALSE ;
// Call the PSAPI function EnumProcesses to get all of the
// ProcID's currently in the system.
// NOTE: In the documentation, the third parameter of
// EnumProcesses is named cbNeeded, which implies that you
// can call the function once to find out how much space to
// allocate for a buffer and again to fill the buffer.
// This is not the case. The cbNeeded parameter returns
// the number of PIDs returned, so if your buffer size is
// zero cbNeeded returns zero.
// NOTE: The "HeapAlloc" loop here ensures that we
// actually allocate a buffer large enough for all the
// PIDs in the system.
dwSize2 = 256 * sizeof( DWORD ) ;
lpdwPIDs = NULL ;
do
{
if( lpdwPIDs )
{
HeapFree( GetProcessHeap(), 0, lpdwPIDs ) ;
dwSize2 *= 2 ;
}
lpdwPIDs = HeapAlloc( GetProcessHeap(), 0, dwSize2 );
if( lpdwPIDs == NULL )
{
FreeLibrary( hInstLib ) ;
FreeLibrary( hInstLib2 ) ;
return FALSE ;
}
if( !lpfEnumProcesses( lpdwPIDs, dwSize2, &dwSize ) )
{
HeapFree( GetProcessHeap(), 0, lpdwPIDs ) ;
FreeLibrary( hInstLib ) ;
FreeLibrary( hInstLib2 ) ;
return FALSE ;
}
}while( dwSize == dwSize2 ) ;
// How many ProcID's did we get?
dwSize /= sizeof( DWORD ) ;
// Loop through each ProcID.
for( dwIndex = 0 ; dwIndex < dwSize ; dwIndex++ )
{
szFileName[0] = 0 ;
// Open the process (if we can... security does not
// permit every process in the system).
hProcess = OpenProcess(
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
FALSE, lpdwPIDs[ dwIndex ] ) ;
if( hProcess != NULL )
{
// Here we call EnumProcessModules to get only the
// first module in the process this is important,
// because this will be the .EXE module for which we
// will retrieve the full path name in a second.
if( lpfEnumProcessModules( hProcess, &hMod,
sizeof( hMod ), &dwSize2 ) )
{
// Get Full pathname:
if( !lpfGetModuleFileNameEx( hProcess, hMod,
szFileName, sizeof( szFileName ) ) )
{
szFileName[0] = 0 ;
}
}
CloseHandle( hProcess ) ;
}
// Regardless of OpenProcess success or failure, we
// still call the enum func with the ProcID.
if(!lpProc( lpdwPIDs[dwIndex], 0, szFileName, lParam))
break ;
// Did we just bump into an NTVDM?
if( _stricmp( szFileName+(strlen(szFileName)-9),
"NTVDM.EXE")==0)
{
// Fill in some info for the 16-bit enum proc.
sInfo.dwPID = lpdwPIDs[dwIndex] ;
sInfo.lpProc = lpProc ;
sInfo.lParam = lParam ;
sInfo.bEnd = FALSE ;
// Enum the 16-bit stuff.
lpfVDMEnumTaskWOWEx( lpdwPIDs[dwIndex],
(TASKENUMPROCEX) Enum16,
(LPARAM) &sInfo);
// Did our main enum func say quit?
if(sInfo.bEnd)
break ;
}
}
// Get procedure addresses.
// We are linking to these functions of Kernel32
// explicitly, because otherwise a module using
// this code would fail to load under Windows NT,
// which does not have the Toolhelp32
// functions in the Kernel 32.
lpfCreateToolhelp32Snapshot=
(HANDLE(WINAPI *)(DWORD,DWORD))
GetProcAddress( hInstLib,
"CreateToolhelp32Snapshot" ) ;
lpfProcess32First=
(BOOL(WINAPI *)(HANDLE,LPPROCESSENTRY32))
GetProcAddress( hInstLib, "Process32First" ) ;
lpfProcess32Next=
(BOOL(WINAPI *)(HANDLE,LPPROCESSENTRY32))
GetProcAddress( hInstLib, "Process32Next" ) ;
if( lpfProcess32Next == NULL ||
lpfProcess32First == NULL ||
lpfCreateToolhelp32Snapshot == NULL )
{
FreeLibrary( hInstLib ) ;
return FALSE ;
}
// Get a handle to a Toolhelp snapshot of the systems
// processes.
hSnapShot = lpfCreateToolhelp32Snapshot(
TH32CS_SNAPPROCESS, 0 ) ;
if( hSnapShot == INVALID_HANDLE_VALUE )
{
FreeLibrary( hInstLib ) ;
return FALSE ;
}
// Get the first process' information.
procentry.dwSize = sizeof(PROCESSENTRY32) ;
bFlag = lpfProcess32First( hSnapShot, &procentry ) ;
// While there are processes, keep looping.
while( bFlag )
{
// Call the enum func with the filename and ProcID.
if(lpProc( procentry.th32ProcessID, 0,
procentry.szExeFile, lParam ))
{
procentry.dwSize = sizeof(PROCESSENTRY32) ;
bFlag = lpfProcess32Next( hSnapShot, &procentry );
}else
bFlag = FALSE ;
}
BOOL WINAPI Enum16( DWORD dwThreadId, WORD hMod16, WORD hTask16,
PSZ pszModName, PSZ pszFileName, LPARAM lpUserDefined ) ;
// The EnumProcs function takes a pointer to a callback function
// that will be called once per process in the system providing
// process EXE filename and process ID.
// Callback function definition:
// BOOL CALLBACK Proc( DWORD dw, LPCSTR lpstr, LPARAM lParam ) ;
//
// lpProc -- Address of callback routine.
//
// lParam -- A user-defined LPARAM value to be passed to
// the callback routine.
BOOL WINAPI EnumProcs( PROCENUMPROC lpProc, LPARAM lParam )
{
OSVERSIONINFO osver ;
HINSTANCE hInstLib ;
HINSTANCE hInstLib2 ;
HANDLE hSnapShot ;
PROCESSENTRY32 procentry ;
BOOL bFlag ;
LPDWORD lpdwPIDs ;
DWORD dwSize, dwSize2, dwIndex ;
HMODULE hMod ;
HANDLE hProcess ;
char szFileName[ MAX_PATH ] ;
EnumInfoStruct sInfo ;
// VDMDBG Function Pointers.
INT (WINAPI *lpfVDMEnumTaskWOWEx)( DWORD,
TASKENUMPROCEX fp, LPARAM );
// Check to see if were running under Windows95 or
// Windows NT.
osver.dwOSVersionInfoSize = sizeof( osver ) ;
if( !GetVersionEx( &osver ) )
{
return FALSE ;
}
Parameters
dwFlags
Specifies portions of the system to include in the snapshot. This parameter can be one of the following: Value Meaning
TH32CS_INHERIT Indicates that the snapshot handle is to be inheritable.
TH32CS_SNAPALL Equivalent to specifying TH32CS_SNAPHEAPLIST, TH32CS_SNAPMODULE, TH32CS_SNAPPROCESS, and TH32CS_SNAPTHREAD.
TH32CS_SNAPHEAPLIST Includes the heap list of the specified process in the snapshot.
TH32CS_SNAPMODULE Includes the module list of the specified process in the snapshot.
TH32CS_SNAPPROCESS Includes the process list in the snapshot.
TH32CS_SNAPTHREAD Includes the thread list in the snapshot.
th32ProcessID
Specifies the process identifier. This parameter can be zero to indicate the current process. This parameter is used when the TH32CS_SNAPHEAPLIST or TH32CS_SNAPMODULE value is specified. Otherwise, it is ignored.