控制台正常,Windows服务无法识别Digital Persona U.are.U 4500指纹采集器
问题描述
我尝试使用Topshelf将Digital Persona U.are.U 4500指纹采集器集成到Windows服务中,该程序在控制台模式下运行正常,但安装为Windows服务后,无法识别设备,也无法采集并保存指纹图像。当前使用的是U.are.U 3.2.0.89版本驱动,相关代码如下:
Program.cs
using System; using System.Drawing.Imaging; using System.Drawing; using DPUruNet; using DPXUru; using System.Threading; using Topshelf; using DigitalPersonaConsole; using log4net; // 使用4500 U.are.U 3.2.0.89驱动 namespace FingerprintReaderApp { class Program { private static readonly ILog _log = LogManager.GetLogger(typeof(Program)); static void Main(string[] args) { HostFactory.Run(x => { // x.DependsOn("DpHost"); x.Service<MyService>(s => { s.ConstructUsing(service => new MyService()); s.WhenStarted(service => service.Start()); s.WhenStopped(service => service.Stop()); }); x.RunAsLocalSystem(); x.SetServiceName("DigitalPersonaService"); x.SetDisplayName("Digital Persona Service"); x.SetDescription("This is Digital persona service test"); }); } } }
MyService.cs
using DPUruNet; using System; using System.Collections.Generic; using System.Drawing.Imaging; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using FingerprintReaderApp; using log4net; namespace DigitalPersonaConsole { public class MyService { private readonly ILog _log = LogManager.GetLogger(typeof(MyService)); public Thread thread = null; public Reader currentReader; private ManualResetEventSlim fingerprintCapturedEvent = new ManualResetEventSlim(false); public MyService() { thread = new Thread(new ThreadStart(initService)); } public void Start() { _log.Info("Start service...."); thread.Start(); } public void Stop() { _log.Info("Stop service...."); thread.Join(); } public void initService() { // 指纹阅读器索引 int selectedReader = 1; // 初始化阅读器 var readers = ReaderCollection.GetReaders(); _log.Info($"No of connceted readers: {readers.Count}"); currentReader = readers[selectedReader]; foreach (Reader reader in readers) { _log.Info(reader.Description.SerialNumber); } if (!OpenReader(currentReader)) { //this.Close(); } if (!StartCaptureAsync(OnCaptured)) { //this.Close(); } fingerprintCapturedEvent.Wait(); } public bool OpenReader(Reader currentReader) { Constants.ResultCode result = Constants.ResultCode.DP_DEVICE_FAILURE; // 打开阅读器 result = currentReader.Open(Constants.CapturePriority.DP_PRIORITY_EXCLUSIVE); if (result != Constants.ResultCode.DP_SUCCESS) { _log.Info("Error: " + result); return false; } return true; } public void OnCaptured(CaptureResult captureResult) { try { // 检查采集质量,不合格则返回 if (!CheckCaptureResult(captureResult)) return; // 创建位图 foreach (Fid.Fiv fiv in captureResult.Data.Views) { _log.Info($"Finger print captured:::::"); string outputPath = "fingerprint.bmp"; Bitmap bmp = CreateBitmap(fiv.RawImage, fiv.Width, fiv.Height); bmp.Save(outputPath, ImageFormat.Bmp); } } catch (Exception ex) { _log.Info("Error: " + ex.Message); } } public bool CheckCaptureResult(CaptureResult captureResult) { if (captureResult.Data == null || captureResult.ResultCode != Constants.ResultCode.DP_SUCCESS) { if (captureResult.ResultCode != Constants.ResultCode.DP_SUCCESS) { throw new Exception(captureResult.ResultCode.ToString()); } // 如果质量检测到假指纹则抛出错误 if ((captureResult.Quality != Constants.CaptureQuality.DP_QUALITY_CANCELED)) { throw new Exception("Quality - " + captureResult.Quality); } return false; } return true; } public bool CaptureFingerAsync() { try { GetStatus(); Constants.ResultCode captureResult = currentReader.CaptureAsync(Constants.Formats.Fid.ANSI, Constants.CaptureProcessing.DP_IMG_PROC_DEFAULT, currentReader.Capabilities.Resolutions[0]); if (captureResult != Constants.ResultCode.DP_SUCCESS) { throw new Exception("" + captureResult); } return true; } catch (Exception ex) { _log.Info("Error: " + ex.Message); return false; } } public Bitmap CreateBitmap(byte[] bytes, int width, int height) { byte[] rgbBytes = new byte[bytes.Length * 3]; for (int i = 0; i <= bytes.Length - 1; i++) { rgbBytes[(i * 3)] = bytes[i]; rgbBytes[(i * 3) + 1] = bytes[i]; rgbBytes[(i * 3) + 2] = bytes[i]; } Bitmap bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb); BitmapData data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb); for (int i = 0; i <= bmp.Height - 1; i++) { IntPtr p = new IntPtr(data.Scan0.ToInt64() + data.Stride * i); System.Runtime.InteropServices.Marshal.Copy(rgbBytes, i * bmp.Width * 3, p, bmp.Width * 3); } bmp.UnlockBits(data); return bmp; } public bool StartCaptureAsync(Reader.CaptureCallback OnCaptured) { // 激活采集回调 currentReader.On_Captured += new Reader.CaptureCallback(OnCaptured); // 调用采集方法 if (!CaptureFingerAsync()) { return false; } return true; } public void GetStatus() { Constants.ResultCode result = currentReader.GetStatus(); if ((result != Constants.ResultCode.DP_SUCCESS)) { throw new Exception("" + result); } if ((currentReader.Status.Status == Constants.ReaderStatuses.DP_STATUS_BUSY)) { Thread.Sleep(50); } else if ((currentReader.Status.Status == Constants.ReaderStatuses.DP_STATUS_NEED_CALIBRATION)) { currentReader.Calibrate(); } else if ((currentReader.Status.Status != Constants.ReaderStatuses.DP_STATUS_READY)) { throw new Exception("Reader Status - " + currentReader.Status.Status); } } public void CancelCaptureAndCloseReader(Reader.CaptureCallback OnCaptured) { if (currentReader != null) { currentReader.CancelCapture(); // 释放阅读器句柄并解绑事件 currentReader.Dispose(); } } } }
解决方案
这个问题核心是Windows服务默认运行在Session 0隔离环境,而USB设备通常绑定到用户会话(如Session 1),Digital Persona驱动无法在Session 0访问用户会话的设备。结合代码问题,以下是具体修复步骤:
1. 解决Session隔离问题
临时测试方案:允许服务与桌面交互
在Topshelf配置中添加交互权限:
x.RunAsLocalSystem(); x.EnableInteractive(); // 新增该行
安装服务后,在服务属性的「登录」选项卡勾选「允许服务与桌面交互」。此方法能临时解决设备访问问题,但存在安全风险,不适合生产环境。
生产环境方案:让服务运行在用户会话
- 修改Topshelf运行身份,使用当前登录用户(需有设备访问权限):
// 直接指定用户 x.RunAs(@"DOMAIN\Username", "Password"); // 或让用户在安装时输入凭证 x.RunAsPrompt();
- 设置服务延迟启动,确保用户登录后设备已加载到会话:
x.StartAutomaticallyDelayed();
2. 修复代码中的潜在问题
问题1:硬编码阅读器索引
代码中selectedReader = 1硬编码索引,若只有一个设备会导致空引用。修改为:
int selectedReader = 0; var readers = ReaderCollection.GetReaders(); _log.Info($"No of connected readers: {readers.Count}"); if(readers.Count == 0) { _log.Error("未找到指纹阅读器!"); return; } currentReader = readers[selectedReader];
问题2:未处理设备重连
服务运行中设备可能断开,添加设备变化监听:
// 在initService方法开头添加 ReaderCollection.OnReaderAdded += ReaderCollection_OnReaderAdded; ReaderCollection.OnReaderRemoved += ReaderCollection_OnReaderRemoved; // 实现事件处理方法 private void ReaderCollection_OnReaderRemoved(object sender, ReaderEventArgs e) { _log.Info($"阅读器已移除: {e.Reader.Description.SerialNumber}"); if(currentReader == e.Reader) { CancelCaptureAndCloseReader(OnCaptured); currentReader = null; } } private void ReaderCollection_OnReaderAdded(object sender, ReaderEventArgs e) { _log.Info($"阅读器已添加: {e.Reader.Description.SerialNumber}"); if(currentReader == null) { currentReader = e.Reader; OpenReader(currentReader); StartCaptureAsync(OnCaptured); } }
问题3:指纹保存路径错误
服务工作目录不是控制台程序目录,"fingerprint.bmp"会保存到C:\Windows\System32,需指定绝对路径:
// 先添加引用using System.IO; string outputPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "fingerprint.bmp");
3. 验证驱动模式
确保Digital Persona驱动安装为服务模式而非仅用户模式。打开设备管理器,查看U.are.U 4500的驱动属性,确认支持Session 0访问;若不支持,重新安装驱动时选择「服务安装」选项。
内容的提问来源于stack exchange,提问作者Walulya francis
相关产品推荐
相关产品推荐

