using PCSC; using System; using System.Collections.Generic; using System.Configuration; using System.Linq; using System.ServiceProcess; using System.Text; using System.Threading; using Interfaces; namespace CardReaderService { public partial class CardReaderService : ServiceBase { private Thread _mainWorkThread; private bool _stopMainWorkerThread; private string _readerName = ""; private SCardMonitor _cardMonitor; private ILogger _logger; public CardReaderService() { InitializeComponent(); } public void Start() { OnStart(new string[] {}); } protected override void OnStart(string[] args) { _logger = NinjectHelper.GetInstance().Get(); _logger.Trace("Starting Service.. Getting available readers"); var ctxFactory = ContextFactory.Instance; using(var context = ctxFactory.Establish(SCardScope.System)) { var readerNames = context.GetReaders(); if (NoReaderAvailable(readerNames)) { _logger.Trace("No Card Reader is available, Exiting.."); throw new ApplicationException("A card reader must be provided in order to operate."); } foreach (var reader in readerNames) { _logger.Trace("Found reader: {0}", reader); } var readerNameConfig = ConfigurationManager.AppSettings["ReaderName"]; if (string.IsNullOrEmpty(readerNameConfig)) { if (!readerNames.Contains(readerNameConfig)) { _logger.Warn("No reader found with the name: {0}, defaulting to first available reader {1}", readerNameConfig, readerNames.First()); readerNameConfig=readerNames.First(); } } _logger.Trace("Choosing reader: {0}", readerNameConfig); _readerName = readerNameConfig; _cardMonitor = new SCardMonitor(ctxFactory, SCardScope.System); _cardMonitor.CardInserted += _cardMonitor_CardInserted; _cardMonitor.Start(_readerName); StartWorkerThread(); } } public void StopService() { OnStop(); } protected override void OnStop() { _stopMainWorkerThread = true; if (_mainWorkThread!= null && _mainWorkThread.IsAlive) { _mainWorkThread.Join(3000); if (_mainWorkThread.IsAlive) { _mainWorkThread.Interrupt(); } } if (_cardMonitor == null) return; _cardMonitor.Cancel(); _cardMonitor.Dispose(); _cardMonitor = null; } private void StartWorkerThread() { _stopMainWorkerThread = false; _mainWorkThread = new Thread(MainWorkerThread) { Name = "CardServiceMainThread", IsBackground = false }; _mainWorkThread.Start(); } private void _cardMonitor_CardInserted(object sender, CardStatusEventArgs e) { var ctxFac = ContextFactory.Instance; using (var ctx = ctxFac.Establish(SCardScope.System)) { var reader = new SCardReader(ctx); var pioSendPci = new IntPtr(); var rcvBuffer = new byte[256]; if (_readerName == string.Empty) { _logger.Fatal("Reader name is somehow empty...exiting"); _stopMainWorkerThread = true; return; } var err = reader.Connect(_readerName, SCardShareMode.Shared, SCardProtocol.T0 | SCardProtocol.T1); if (err == SCardError.Success) { var uIdcmd = new byte[] { 0xFF, 0xCA, 0x00, 0x00, 0x00 }; err = reader.Transmit(pioSendPci, uIdcmd, ref rcvBuffer); if (err != SCardError.Success) return; var uid = ConvertByteUIDToString(rcvBuffer); var atrString = ConvertByteUIDToString(e.Atr); _logger.Trace("Card Inserted, ATR: " + atrString + ", and UID is: " + uid); var postObj = new CardDataPost {CardUId = uid}; DataCenterHelper.PostAsync(postObj, "/api/swipedata"); _logger.Trace("Posted to Server"); } else { _logger.Trace("Reader failed to connect, error: " + Enum.GetName(typeof(SCardError), err)); } } } private void MainWorkerThread() { while (!_stopMainWorkerThread) { //dont actually need to do anything.. but cannot exit right away? Thread.Sleep(3000); } } private string ConvertByteUIDToString(byte[] uid) { var sb = new StringBuilder(); foreach(var b in uid) { sb.AppendFormat("{0:X2}", b); } return sb.ToString(); } private bool NoReaderAvailable(ICollection readerNames) { return readerNames == null || readerNames.Count < 1; } } }