title: PCSC.InvalidContextException when running as a Windows service
body: <p>I've been working on a small smart card scanner application using the pcsc-sharp library. The application works fine when running as a console application, the code is as follows:</p>
  
  <pre><code>    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 &amp; static defined methods below.
                  monitor.CardInserted += (sender, args0) =&gt; DisplayEvent("CardInserted", args0);
                  //monitor.CardRemoved += (sender, args0) =&gt; DisplayEvent("CardRemoved", args0);
                  //monitor.Initialized += (sender, args0) =&gt; 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("&gt;&gt; {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("&gt;&gt; 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));
          }
      }
  }
  </code></pre>
  
  <p>However, when trying to run it as a Windows service - to allow scanning of cards to update a database - the event never fires and it appears to crash when the service is started. The event log shows a PCSC.InvalidContextException error. The code for the service is near enough identical, but here is the sample.</p>
  
  <pre><code>    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 &amp; static defined methods below.
                  monitor.CardInserted += (sender, args0) =&gt; DisplayEvent("CardInserted", args0);
                  //monitor.CardRemoved += (sender, args0) =&gt; DisplayEvent("CardRemoved", args0);
                  //monitor.Initialized += (sender, args0) =&gt; 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", "&gt;&gt; " + 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("&gt;&gt; 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));
          }
      }
  }
  </code></pre>
  
  <p>I have stripped out the actual database logic as that appears to work fine, I believe it is crashing when trying to either release the context variable or attaching the monitor to the smart cards.</p>
  
  <p>It must also be stated that I have tried changing the service from starting using the Local System account to using Local Service, in case it was some sort of access permissions error.</p>
  
  <p>If anyone can shed some light on where I'm going wrong I'd greatly appreciate the help. I'm relatively new to working with PC/SC and appear to have hit a brick wall with this project for now.</p>
  
  <p><strong>UPDATE</strong></p>
  
  <p>I have now solved the issue; it turns out Windows services don't like using statements. The variables are disposed at the end of the block and therefore the context was becoming invalid.</p>
  
  <p>The using blocks were commented out and declarations for the variables were done in their place. New code for the OnStart method is a is as follows:</p>
  
  <pre><code>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 &amp; static defined methods below.
                  monitor.CardInserted += (sender, args0) =&gt; DisplayEvent("CardInserted", args0);
                  //monitor.CardRemoved += (sender, args0) =&gt; DisplayEvent("CardRemoved", args0);
                  //monitor.Initialized += (sender, args0) =&gt; 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());
          }
  </code></pre>
  
  <p>Hopefully this information helps someone else out.</p>