如何用CreateToolhelp32Snapshot和Python ctypes枚举线程?代码为何输出0?
问题分析与修复
你的代码始终打印0的原因主要有两点:
1. 未检查快照创建是否成功
CreateToolhelp32Snapshot调用可能因权限不足、目标进程不存在等原因失败,返回INVALID_HANDLE_VALUE无效句柄。此时调用Thread32First会导致结构体未被正确填充,th32ThreadID保持初始的0值;如果函数因类型不匹配等问题错误返回True,就会打印出0。
2. 未过滤目标进程的线程
使用TH32CS_SNAPTHREAD标志创建的快照会包含系统中所有线程,Thread32First返回的第一个线程大概率不属于目标进程,你需要手动筛选th32OwnerProcessID与目标PID一致的线程。
另外,代码还存在资源泄漏问题:未调用CloseHandle释放快照句柄。
修复后的代码
import ctypes from ctypes import wintypes pid = 1234 TH32CS_SNAPTHREAD = 0x00000004 INVALID_HANDLE_VALUE = wintypes.HANDLE(-1).value kernel32 = ctypes.WinDLL('kernel32', use_last_error=True) class THREADENTRY32(ctypes.Structure): _fields_ = [ ('dwSize', wintypes.DWORD), ('cntUsage', wintypes.DWORD), ('th32ThreadID', wintypes.DWORD), ('th32OwnerProcessID', wintypes.DWORD), ('tpBasePri', wintypes.LONG), ('tpDeltaPri', wintypes.LONG), ('dwFlags', wintypes.DWORD) ] # 定义函数参数和返回值类型 CreateToolhelp32Snapshot = kernel32.CreateToolhelp32Snapshot CreateToolhelp32Snapshot.argtypes = (wintypes.DWORD, wintypes.DWORD) CreateToolhelp32Snapshot.restype = wintypes.HANDLE Thread32First = kernel32.Thread32First Thread32First.argtypes = (wintypes.HANDLE, ctypes.POINTER(THREADENTRY32)) Thread32First.restype = wintypes.BOOL Thread32Next = kernel32.Thread32Next Thread32Next.argtypes = (wintypes.HANDLE, ctypes.POINTER(THREADENTRY32)) Thread32Next.restype = wintypes.BOOL CloseHandle = kernel32.CloseHandle CloseHandle.argtypes = (wintypes.HANDLE,) CloseHandle.restype = wintypes.BOOL # 创建线程快照 h_snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, pid) if h_snapshot == INVALID_HANDLE_VALUE: print(f"创建快照失败,错误码: {ctypes.get_last_error()}") else: thread_entry = THREADENTRY32() thread_entry.dwSize = ctypes.sizeof(THREADENTRY32) # 枚举线程并过滤目标进程 if Thread32First(h_snapshot, ctypes.byref(thread_entry)): found = False while True: if thread_entry.th32OwnerProcessID == pid: print(f"找到目标进程的线程ID: {thread_entry.th32ThreadID}") found = True break if not Thread32Next(h_snapshot, ctypes.byref(thread_entry)): break if not found: print("未找到目标进程的线程") else: print(f"枚举线程失败,错误码: {ctypes.get_last_error()}") # 释放快照句柄 CloseHandle(h_snapshot)
内容的提问来源于stack exchange,提问作者Utkonos
相关产品推荐
相关产品推荐

