作为Windows服务运行时,PCSC.InvalidContextException

我一直在使用pcsc-sharp库来开发一个小型智能卡扫描器应用程序。 作为控制台应用程序运行时,该应用程序工作正常,代码如下所示:

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Configuration; using System.IO; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Text; using System.Drawing.Printing; using System.Net; using System.Net.Sockets; using System.Data.SqlClient; using System.Threading; using System.IO.Ports; using System.Text.RegularExpressions; using System.Speech.Synthesis; using System.Diagnostics; using PCSC; using System.Media; namespace MeterTestingApplication { class Program { static void Main(string[] args) { // Retrieve the names of all installed readers. string[] readerNames; using (var context = new SCardContext()) { context.Establish(SCardScope.System); readerNames = context.GetReaders(); context.Release(); } if (readerNames == null || readerNames.Length == 0) { Console.WriteLine("There are currently no readers installed."); return; } // Create a monitor object with its own PC/SC context. // The context will be released after monitor.Dispose() using (var monitor = new SCardMonitor(new SCardContext(), SCardScope.System)) { // Point the callback function(s) to the anonymous & static defined methods below. monitor.CardInserted += (sender, args0) => DisplayEvent("CardInserted", args0); //monitor.CardRemoved += (sender, args0) => DisplayEvent("CardRemoved", args0); //monitor.Initialized += (sender, args0) => DisplayEvent("Initialized", args0); //monitor.StatusChanged += StatusChanged; monitor.MonitorException += MonitorException; monitor.Start(readerNames); // Keep the window open Console.ReadLine(); } } private static void DisplayEvent(string eventName, CardStatusEventArgs unknown) { Console.WriteLine(">> {0} Event for reader: {1}", eventName, unknown.ReaderName); Console.WriteLine("ATR: {0}", BitConverter.ToString(unknown.Atr ?? new byte[0])); Console.WriteLine("State: {0}\n", unknown.State); //Works fine here } private static void StatusChanged(object sender, StatusChangeEventArgs args) { //Console.WriteLine(">> StatusChanged Event for reader: {0}", args.ReaderName); //Console.WriteLine("ATR: {0}", BitConverter.ToString(args.Atr ?? new byte[0])); //Console.WriteLine("Last state: {0}\nNew state: {1}\n", args.LastState, args.NewState); } private static void MonitorException(object sender, PCSCException ex) { Console.WriteLine("Monitor exited due an error:"); Console.WriteLine(SCardHelper.StringifyError(ex.SCardError)); } } } 

但是,当试图将其作为Windows服务运行时(为了允许扫描卡来更新数据库),该事件从不会触发,并且在服务启动时似乎会崩溃。 事件日志显示PCSC.InvalidContextException错误。 该服务的代码接近相同,但这里是示例。

  using System; using System.Diagnostics; using System.ServiceProcess; using System.Timers; using System.Configuration; using System.Linq; using System.Data.SqlClient; using System.Collections.Generic; using System.IO; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Text; using System.Drawing.Printing; using System.Threading; using System.Speech.Synthesis; using System.IO.Ports; using System.Text.RegularExpressions; using PCSC; using System.Media; using log4net; namespace CardScannerService { public partial class CardScanner : ServiceBase { private ILog logger; private SCardContext context; private string[] readerNames; private SCardMonitor monitor; private static System.Timers.Timer aTimer; public CardScanner() { InitializeComponent(); } static void Main() { ServiceBase.Run(new CardScanner()); } // // Start Service // protected override void OnStart(string[] args) { aTimer = new System.Timers.Timer(); aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent); aTimer.Interval = (1000 * 60 * 60 * 24); // Once a day; 1000ms * 60s * 60m * 24h aTimer.Enabled = true; //// Entry point using (context = new SCardContext()) { context.Establish(SCardScope.System); readerNames = context.GetReaders(); context.Release(); } if (readerNames == null || readerNames.Length == 0) { EventLog.WriteEntry("CardReaderService", "There are currently no readers installed."); return; } // Create a monitor object with its own PC/SC context. // The context will be released after monitor.Dispose() using (monitor = new SCardMonitor(new SCardContext(), SCardScope.System)) { // Point the callback function(s) to the anonymous & static defined methods below. monitor.CardInserted += (sender, args0) => DisplayEvent("CardInserted", args0); //monitor.CardRemoved += (sender, args0) => DisplayEvent("CardRemoved", args0); //monitor.Initialized += (sender, args0) => DisplayEvent("Initialized", args0); //monitor.StatusChanged += StatusChanged; monitor.MonitorException += MonitorException; monitor.Start(readerNames); // Keep the window open //Console.ReadLine(); } logger.InfoFormat("CardScannerService Started at {0}", DateTime.Now.ToLongTimeString()); } // // Stop Service // protected override void OnStop() { logger.InfoFormat("CardScannerService Stopped at {0}", DateTime.Now.ToLongTimeString()); } // // Execute timed event every hour and half hour // void OnTimedEvent(object source, ElapsedEventArgs e) { // Card scanner service entry point for timed event - any cleanup code can go here } private static void DisplayEvent(string eventName, CardStatusEventArgs unknown) { EventLog.WriteEntry("CardReaderService", ">> " + eventName + "v Event for Reader: " + unknown.ReaderName); EventLog.WriteEntry("CardReaderService", "ATR: " + BitConverter.ToString(unknown.Atr ?? new byte[0])); EventLog.WriteEntry("CardReaderService", "State: " + unknown.State); //Not firing } private static void StatusChanged(object sender, StatusChangeEventArgs args) { //Console.WriteLine(">> StatusChanged Event for reader: {0}", args.ReaderName); //Console.WriteLine("ATR: {0}", BitConverter.ToString(args.Atr ?? new byte[0])); //Console.WriteLine("Last state: {0}\nNew state: {1}\n", args.LastState, args.NewState); } private static void MonitorException(object sender, PCSCException ex) { EventLog.WriteEntry("CardReaderService", "Monitor exited due an error:"); EventLog.WriteEntry("CardReaderService", SCardHelper.StringifyError(ex.SCardError)); } } } 

我已经剥离了实际的数据库逻辑,因为看起来工作正常,我相信当试图释放上下文variables或将显示器连接到智能卡时会崩溃。

还必须说明,我曾尝试将服务从开始使用本地系统帐户更改为使用本地服务,以防万一某种访问权限错误。

如果任何人都可以指出我要出错的地方,我将非常感谢帮助。 我和PC / SC合作比较新,而且现在看来这个项目已经碰到了一堵砖墙。

UPDATE

我现在已经解决了这个问题。 原来Windows服务不喜欢使用语句。 variables被放置在块的末尾,因此上下文变得无效。

使用块被注释掉,variables的声明是在他们的地方完成的。 OnStart方法的新代码如下所示:

 protected override void OnStart(string[] args) { logger = LogManager.GetLogger(this.GetType().Name); aTimer = new System.Timers.Timer(); aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent); aTimer.Interval = (1000 * 60 * 60 * 24); // Once a day; 1000ms * 60s * 60m * 24h aTimer.Enabled = true; // Entry point //using (context = new SCardContext()) //{ context = new SCardContext(); context.Establish(SCardScope.System); readerNames = context.GetReaders(); context.Release(); //} if (readerNames == null || readerNames.Length == 0) { EventLog.WriteEntry("CardReaderService", "There are currently no readers installed."); return; } // Create a monitor object with its own PC/SC context. // The context will be released after monitor.Dispose() //using (monitor = new SCardMonitor(new SCardContext(), SCardScope.System)) //{ monitor = new SCardMonitor(new SCardContext(), SCardScope.System); // Point the callback function(s) to the anonymous & static defined methods below. monitor.CardInserted += (sender, args0) => DisplayEvent("CardInserted", args0); //monitor.CardRemoved += (sender, args0) => DisplayEvent("CardRemoved", args0); //monitor.Initialized += (sender, args0) => DisplayEvent("Initialized", args0); //monitor.StatusChanged += StatusChanged; monitor.MonitorException += MonitorException; monitor.Start(readerNames); // Keep the window open //Console.ReadLine(); //} logger.InfoFormat("CardScannerService Started at {0}", DateTime.Now.ToLongTimeString()); } 

希望这个信息可以帮助别人。

我设法解决了这个问题 – 问题已经更新,以反映这些变化。