如何使用Java获取仅包含当前已打开程序的列表(排除后台进程)
获取Windows上已打开的可见程序列表(Java实现)
嗨,我懂你要的是用户能看到的已打开程序(带可见窗口的),而不是tasklist.exe返回的所有后台进程——之前的代码确实会把系统服务、后台守护进程这类进程都列出来,完全不符合需求。下面给你两个实用的解决方案:
方案1:用PowerShell命令过滤(快速实现)
Windows的PowerShell可以直接筛选出有主窗口标题的进程,这正是我们要的“已打开程序”。Java里可以调用PowerShell命令来实现:
import java.io.BufferedReader; import java.io.InputStreamReader; public class OpenProgramsList { public static void main(String[] args) { try { // 调用PowerShell,筛选有主窗口标题的进程,并格式化输出 Process p = Runtime.getRuntime().exec(new String[]{ "powershell.exe", "-Command", "Get-Process | Where-Object {$_.MainWindowTitle -ne \"\"} | Select-Object Name, MainWindowTitle, Id | Format-Table -AutoSize" }); // 注意指定UTF-8编码,避免中文窗口标题乱码 BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream(), "UTF-8")); String line; while ((line = input.readLine()) != null) { // 跳过空行,让输出更整洁 if (!line.trim().isEmpty()) { System.out.println(line); } } input.close(); p.waitFor(); } catch (Exception e) { e.printStackTrace(); } } }
说明:
- 这个命令会过滤掉
MainWindowTitle为空的进程(也就是没有可见窗口的后台进程) - 返回的信息包括进程名、窗口标题、进程ID,格式清晰易读
- 一定要指定
UTF-8编码,否则中文窗口标题会出现乱码问题
方案2:用JNA调用Windows API(精准控制)
如果不想依赖PowerShell,或者需要更精细的窗口筛选逻辑(比如排除最小化窗口),可以用JNA直接调用Windows的User32和Kernel32 API,枚举所有可见顶层窗口并获取对应的进程信息:
第一步:引入JNA依赖(Maven)
<dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna</artifactId> <version>5.13.0</version> </dependency> <dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna-platform</artifactId> <version>5.13.0</version> </dependency>
第二步:实现代码
import com.sun.jna.Native; import com.sun.jna.Pointer; import com.sun.jna.platform.win32.User32; import com.sun.jna.platform.win32.WinDef; import com.sun.jna.platform.win32.WinNT; import com.sun.jna.ptr.IntByReference; import java.util.HashSet; import java.util.Set; public class VisibleAppsLister { public static void main(String[] args) { Set<String> visibleApps = getVisibleApplications(); System.out.println("已打开的可见程序:"); for (String app : visibleApps) { System.out.println("- " + app); } } private static Set<String> getVisibleApplications() { Set<String> appNames = new HashSet<>(); User32 user32 = User32.INSTANCE; // 枚举所有顶层窗口 user32.EnumWindows((hWnd, data) -> { // 只保留可见且有窗口标题的窗口 if (user32.IsWindowVisible(hWnd) && user32.GetWindowTextLength(hWnd) > 0) { IntByReference pid = new IntByReference(); // 获取窗口对应的进程ID user32.GetWindowThreadProcessId(hWnd, pid); // 打开进程以获取进程名 WinNT.HANDLE hProcess = Kernel32.INSTANCE.OpenProcess( WinNT.PROCESS_QUERY_INFORMATION | WinNT.PROCESS_VM_READ, false, pid.getValue() ); if (hProcess != null) { char[] buffer = new char[1024]; Kernel32.INSTANCE.GetModuleBaseName(hProcess, null, buffer, buffer.length); String appName = Native.toString(buffer); if (!appName.isEmpty()) { appNames.add(appName); } // 记得关闭进程句柄,避免资源泄漏 Kernel32.INSTANCE.CloseHandle(hProcess); } } return true; // 继续枚举下一个窗口 }, null); return appNames; } // 自定义Kernel32接口,补充需要的方法 public interface Kernel32 extends com.sun.jna.platform.win32.Kernel32 { Kernel32 INSTANCE = Native.load("kernel32", Kernel32.class); WinNT.HANDLE OpenProcess(int dwDesiredAccess, boolean bInheritHandle, int dwProcessId); int GetModuleBaseName(WinNT.HANDLE hProcess, Pointer hModule, char[] lpBaseName, int nSize); } }
说明:
- 这个方法直接和Windows系统交互,结果更精准,能捕获所有可见窗口对应的程序
- 你可以修改判断条件,比如加上
user32.IsIconic(hWnd) == false来排除最小化的窗口 - 注意要关闭进程句柄,避免系统资源泄漏
内容的提问来源于stack exchange,提问作者Parzavil
相关产品推荐
相关产品推荐

