You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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');
}

注意事项

  1. 以上方案仅适用于Windows平台,因为调用的是Windows专属API
  2. 普通应用获取PID无需特殊系统权限,系统进程可能需要管理员权限
  3. 使用dart:ffi时必须手动管理内存(如calloc.free),避免内存泄漏

内容的提问来源于stack exchange,提问作者Sharif Ahamed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 18:10:36