使用ctypes枚举Windows进程时遭遇报错问题求助
解决Windows进程遍历与名称获取的报错问题
错误原因分析
- 进程ID 0:系统空闲进程,无实际可打开的进程对象,直接跳过即可。
- 错误码5(拒绝访问):
PROCESS_QUERY_INFORMATION权限要求过高,部分系统进程无法获取该权限,需改用更宽松的PROCESS_QUERY_LIMITED_INFORMATION权限(Windows Vista及以上系统支持)。 - 错误码299(部分完成):部分系统进程(如PID4)受保护,无法通过
EnumProcessModules枚举模块,应改用无需枚举模块的API直接获取进程镜像名称。
修正后的代码
import ctypes import ctypes.wintypes from pathlib import Path # Library initializations psapi = ctypes.windll.psapi kernel32 = ctypes.windll.kernel32 FORMAT_MESSAGE_FROM_SYSTEM = 0x1000 # 改用更易获取的权限 PROCESS_QUERY_LIMITED_INFORMATION = 0x10000000 MAX_PROCESS_COUNT = 4096 FLAGGED_PROCESSES = ["test.exe"] def get_last_error(): """获取最后错误码及描述""" error_code = ctypes.GetLastError() buffer = ctypes.create_unicode_buffer(256) kernel32.FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, None, error_code, 0, buffer, len(buffer), None) return error_code, buffer.value.strip() def _get_process_name(process_id): # 跳过系统空闲进程 if process_id == 0: return None h_process = kernel32.OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, False, process_id) if not h_process: # 可选择性打印错误,避免过多日志 # print(f"打开进程 {process_id} 失败。错误: {get_last_error()}") return None try: # 使用QueryFullProcessImageNameW直接获取进程镜像路径 exe_path = ctypes.create_unicode_buffer(ctypes.wintypes.MAX_PATH) size = ctypes.wintypes.DWORD(ctypes.sizeof(exe_path) // 2) if kernel32.QueryFullProcessImageNameW(h_process, 0, exe_path, ctypes.byref(size)): # 从路径中提取文件名 return Path(exe_path.value).name else: # print(f"获取进程 {process_id} 路径失败。错误: {get_last_error()}") return None finally: kernel32.CloseHandle(h_process) def is_flagged_process_running(): DWORD = ctypes.wintypes.DWORD DWORD_ARRAY = DWORD * MAX_PROCESS_COUNT process_ids = DWORD_ARRAY() bytes_returned = DWORD() if not psapi.EnumProcesses(ctypes.byref(process_ids), ctypes.sizeof(process_ids), ctypes.byref(bytes_returned)): print(f"枚举进程失败。错误: {get_last_error()}") return False number_of_processes = bytes_returned.value // ctypes.sizeof(DWORD) for index in range(number_of_processes): process_name = _get_process_name(process_ids[index]) if process_name and process_name.lower() in FLAGGED_PROCESSES: return True return False print(is_flagged_process_running())
关键修改点
- 跳过PID 0:直接判断进程ID为0时返回None,避免无效的打开操作。
- 替换权限常量:用
PROCESS_QUERY_LIMITED_INFORMATION替代PROCESS_QUERY_INFORMATION,降低权限要求,减少拒绝访问错误。 - 更换API:使用
QueryFullProcessImageNameW直接从进程句柄获取完整路径,无需枚举模块,避免299错误。 - 提取文件名:用
pathlib.Path从完整路径中提取进程文件名,符合需求。 - 可选日志关闭:注释掉部分错误打印,避免过多无关日志干扰,如需调试可取消注释。
内容的提问来源于stack exchange,提问作者zizzie
相关产品推荐
相关产品推荐

