Windows服务下Java RDP会话筛选当前用户重定向打印机
Windows服务下筛选当前用户专属打印机的方案
问题根源
Windows服务以系统账户运行时,默认会枚举所有登录用户会话里的打印机资源。要筛选出当前进程所属用户的打印机,关键是把打印机和Windows会话ID关联匹配。
具体实现步骤
1. 获取当前进程的会话ID
Java标准库没提供直接拿会话ID的方法,得用JNA调用Windows API:
import com.sun.jna.platform.win32.Kernel32; import com.sun.jna.platform.win32.WinNT; public class SessionHelper { public static int getCurrentSessionId() { WinNT.HANDLE processHandle = Kernel32.INSTANCE.GetCurrentProcess(); int[] sessionId = new int[1]; Kernel32.INSTANCE.ProcessIdToSessionId(Kernel32.INSTANCE.GetProcessId(processHandle), sessionId); return sessionId[0]; } }
2. 查询打印机对应的会话ID并筛选
通过WMI查询每个打印机的会话ID属性,再和当前进程的会话ID匹配:
import java.util.ArrayList; import java.util.List; import java.util.Set; import javax.management.MBeanServerConnection; import javax.management.ObjectInstance; import javax.management.ObjectName; import javax.management.remote.JMXConnector; import javax.management.remote.JMXConnectorFactory; import javax.management.remote.JMXServiceURL; public class PrinterFilter { public static List<String> getCurrentSessionPrinters() throws Exception { int targetSessionId = SessionHelper.getCurrentSessionId(); List<String> matchedPrinters = new ArrayList<>(); // 连接本地WMI服务 JMXServiceURL wmiUrl = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:9999/wmi"); JMXConnector connector = JMXConnectorFactory.connect(wmiUrl); MBeanServerConnection mBeanConn = connector.getMBeanServerConnection(); // 查询所有Win32_Printer实例 ObjectName printerMBean = new ObjectName("Win32_Printer"); Set<ObjectInstance> allPrinters = mBeanConn.queryMBeans(printerMBean, null); for (ObjectInstance printer : allPrinters) { ObjectName objName = printer.getObjectName(); Integer printerSessionId = (Integer) mBeanConn.getAttribute(objName, "SessionId"); String printerName = (String) mBeanConn.getAttribute(objName, "Name"); if (printerSessionId != null && printerSessionId == targetSessionId) { matchedPrinters.add(printerName); } } connector.close(); return matchedPrinters; } }
3. 整合到原有代码
修改你原来的findPrinters方法,加入筛选逻辑:
public void findPrinters() { try { List<String> sessionPrinters = PrinterFilter.getCurrentSessionPrinters(); PrintService[] allServices = PrinterJob.lookupPrintServices(); for (PrintService service : allServices) { if (sessionPrinters.contains(service.getName())) { log.info("当前会话打印机: {}", service.getName()); } } } catch (Exception e) { log.error("筛选打印机失败", e); } }
注意点
- 要引入JNA依赖(比如
net.java.dev.jna:jna-platform)才能调用Windows API。 - Windows服务得有足够权限访问WMI,不然查不到打印机的会话信息。
- 本地打印机的SessionId可能是0,要是你的场景包含这类打印机,得调整匹配逻辑。
内容的提问来源于stack exchange,提问作者Jake N
相关产品推荐
相关产品推荐

