Flutter Windows应用如何获取当前活动窗口/进程的PID?
获取Windows平台下其他应用的PID(Flutter/Dart实现)
你当前的代码只能获取自身进程PID,要实现切换到其他应用时获取对应PID,可以通过调用Windows原生API实现,以下是两种可行方案:
方案一:获取当前前台应用的PID(切换应用时自动对应)
当你切换到目标应用时,该应用会成为前台窗口,通过user32.dll的API可以直接获取前台窗口对应的进程ID,无需遍历所有进程,效率更高。
代码实现
import 'dart:ffi'; import 'package:ffi/ffi.dart'; // 绑定Windows user32.dll中的核心函数 final user32 = DynamicLibrary.open('user32.dll'); // 获取前台窗口句柄 typedef GetForegroundWindowC = Pointer<Void> Function(); typedef GetForegroundWindowDart = Pointer<Void> Function(); final getForegroundWindow = user32.lookupFunction<GetForegroundWindowC, GetForegroundWindowDart>('GetForegroundWindow'); // 通过窗口句柄获取进程ID typedef GetWindowThreadProcessIdC = Uint32 Function(Pointer<Void> hWnd, Pointer<Uint32> lpdwProcessId); typedef GetWindowThreadProcessIdDart = int Function(Pointer<Void> hWnd, Pointer<Uint32> lpdwProcessId); final getWindowThreadProcessId = user32.lookupFunction<GetWindowThreadProcessIdC, GetWindowThreadProcessIdDart>('GetWindowThreadProcessId'); // 获取当前前台进程的PID int getForegroundProcessId() { final hWnd = getForegroundWindow(); if (hWnd.address == 0) return -1; // 无前台窗口时返回-1 final pidPtr = calloc<Uint32>(); try { getWindowThreadProcessId(hWnd, pidPtr); return pidPtr.value; } finally { calloc.free(pidPtr); // 释放内存 } } // 使用示例:定时获取前台PID void main() async { while (true) { final pid = getForegroundProcessId(); print('当前前台应用PID: $pid'); await Future.delayed(const Duration(seconds: 1)); } }
方案二:根据应用名称获取PID(如Skype、记事本)
如果需要主动根据进程名查找PID,可以通过psapi.dll枚举所有进程并匹配名称,适合需要精准定位特定应用的场景。
代码实现
import 'dart:ffi'; import 'package:ffi/ffi.dart'; final user32 = DynamicLibrary.open('user32.dll'); final psapi = DynamicLibrary.open('psapi.dll'); // 打开进程获取句柄 typedef OpenProcessC = Pointer<Void> Function(Uint32 dwDesiredAccess, Int32 bInheritHandle, Uint32 dwProcessId); typedef OpenProcessDart = Pointer<Void> Function(int dwDesiredAccess, int bInheritHandle, int dwProcessId); final openProcess = user32.lookupFunction<OpenProcessC, OpenProcessDart>('OpenProcess'); // 关闭进程句柄 typedef CloseHandleC = Int32 Function(Pointer<Void> hObject); typedef CloseHandleDart = int Function(Pointer<Void> hObject); final closeHandle = user32.lookupFunction<CloseHandleC, CloseHandleDart>('CloseHandle'); // 枚举所有进程ID typedef EnumProcessesC = Int32 Function(Pointer<Uint32> lpidProcess, Uint32 cb, Pointer<Uint32> lpcbNeeded); typedef EnumProcessesDart = int Function(Pointer<Uint32> lpidProcess, int cb, Pointer<Uint32> lpcbNeeded); final enumProcesses = psapi.lookupFunction<EnumProcessesC, EnumProcessesDart>('EnumProcesses'); // 获取进程模块名称(即进程名) typedef GetModuleBaseNameWC = Uint32 Function(Pointer<Void> hProcess, Pointer<Void> hModule, Pointer<Utf16> lpBaseName, Uint32 nSize); typedef GetModuleBaseNameWDart = int Function(Pointer<Void> hProcess, Pointer<Void> hModule, Pointer<Utf16> lpBaseName, int nSize); final getModuleBaseNameW = psapi.lookupFunction<GetModuleBaseNameWC, GetModuleBaseNameWDart>('GetModuleBaseNameW'); // 进程访问权限常量 const int PROCESS_QUERY_INFORMATION = 0x0400; const int PROCESS_VM_READ = 0x0010; // 根据进程名获取PID(需传入带.exe后缀的名称,如notepad.exe) int getProcessIdByName(String processName) { final pidList = calloc<Uint32>(1024); // 预分配1024个进程ID的空间 final bytesNeeded = calloc<Uint32>(); try { if (enumProcesses(pidList, 1024 * sizeOf<Uint32>(), bytesNeeded) == 0) { return -1; // 枚举进程失败 } final processCount = bytesNeeded.value ~/ sizeOf<Uint32>(); for (int i = 0; i < processCount; i++) { final pid = pidList[i]; if (pid == 0) continue; // 打开进程获取句柄 final hProcess = openProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, pid); if (hProcess.address == 0) continue; final nameBuffer = calloc<Utf16>(256); try { getModuleBaseNameW(hProcess, nullptr, nameBuffer, 256); final currentName = nameBuffer.toDartString(); if (currentName.toLowerCase() == processName.toLowerCase()) { return pid; } } finally { calloc.free(nameBuffer); closeHandle(hProcess); // 必须关闭进程句柄,避免资源泄漏 } } return -1; // 未找到目标进程 } finally { calloc.free(pidList); calloc.free(bytesNeeded); } } // 使用示例:获取记事本的PID void main() { final notepadPid = getProcessIdByName('notepad.exe'); print('记事本PID: $notepadPid'); final skypePid = getProcessIdByName('skype.exe'); print('Skype PID: $skypePid'); }
注意事项
- 以上方案仅适用于Windows平台,因为调用的是Windows专属API
- 普通应用获取PID无需特殊系统权限,系统进程可能需要管理员权限
- 使用dart:ffi时必须手动管理内存(如
calloc.free),避免内存泄漏
内容的提问来源于stack exchange,提问作者Sharif Ahamed
相关产品推荐
相关产品推荐

