Correct thread/memory leak issue where two main threads were created/running. (bad juju!) #90
187 lines
6.4 KiB
C#
187 lines
6.4 KiB
C#
using PCSC;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.ServiceProcess;
|
|
using System.Text;
|
|
using System.Threading;
|
|
|
|
namespace CardReaderService
|
|
{
|
|
public partial class Service1 : ServiceBase
|
|
{
|
|
private Thread _mainWorkThread;
|
|
private bool _stopMainWorkerThread;
|
|
private AutoResetEvent _mainWorkerTerminationSignal;
|
|
private string _readerName = "";
|
|
private SCardMonitor _cardMonitor;
|
|
private bool _initialised=false;
|
|
|
|
public Service1()
|
|
{
|
|
InitializeComponent();
|
|
}
|
|
|
|
public void Start()
|
|
{
|
|
OnStart(new string[] { });
|
|
}
|
|
|
|
protected override void OnStart(string[] args)
|
|
{
|
|
StartWorkerThread();
|
|
}
|
|
|
|
private bool WeHaveValidCardReader()
|
|
{
|
|
if (_cardMonitor == null)
|
|
{
|
|
return false;
|
|
}
|
|
Console.WriteLine(_cardMonitor.GetCurrentState(0));
|
|
if (_cardMonitor.GetCurrentState(0) == SCRState.Unknown
|
|
|| _cardMonitor.GetCurrentState(0) == SCRState.Unavailable
|
|
|| _cardMonitor.GetCurrentState(0) == (SCRState.Ignore | SCRState.Unavailable)
|
|
//|| _cardMonitor.GetCurrentState(0) == SCRState.Unaware //if we say this is an invalid state, we cause a memory leak where we create a duplicate card monitor, subscribe and overwrite.
|
|
)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public void Stop()
|
|
{
|
|
OnStop();
|
|
}
|
|
|
|
protected override void OnStop()
|
|
{
|
|
_stopMainWorkerThread = true;
|
|
_mainWorkerTerminationSignal.Set();
|
|
if (_mainWorkThread != null && _mainWorkThread.IsAlive)
|
|
{
|
|
_mainWorkThread.Interrupt();
|
|
}
|
|
if (_cardMonitor != null)
|
|
{
|
|
_cardMonitor.Cancel();
|
|
_cardMonitor.Dispose();
|
|
_cardMonitor = null;
|
|
}
|
|
}
|
|
|
|
private void StartWorkerThread()
|
|
{
|
|
_stopMainWorkerThread = false;
|
|
_mainWorkThread = new Thread(MainWorkerThread)
|
|
{
|
|
Name = "CardServiceMainThread",
|
|
IsBackground = false
|
|
};
|
|
_mainWorkerTerminationSignal = new AutoResetEvent(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();
|
|
byte[] rcvBuffer = new byte[256];
|
|
|
|
if (_readerName == string.Empty)
|
|
{
|
|
Console.WriteLine("Reader name is somehow empty... WTF!");
|
|
_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)
|
|
{
|
|
var uid = ConvertByteUIDToString(rcvBuffer);
|
|
var atrString = ConvertByteUIDToString(e.Atr);
|
|
Console.WriteLine("Card Inserted, ATR: " + atrString + ", and UID is: " + uid);
|
|
|
|
CardDataPost postObj = new CardDataPost { CardUId = uid };
|
|
DataCenterHelper.PostAsync(postObj, "/api/swipedata");
|
|
Console.WriteLine("Posted to Server");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("Reader failed to connect, error: " + Enum.GetName(typeof(SCardError), err));
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
private void MainWorkerThread()
|
|
{
|
|
while (!_stopMainWorkerThread)
|
|
{
|
|
if (!WeHaveValidCardReader())
|
|
{ //only do this if we don't have a valid card reader
|
|
if (_initialised)
|
|
{
|
|
//card reader no longer available, tidy up.
|
|
_cardMonitor.Cancel();
|
|
_cardMonitor.CardInserted -= _cardMonitor_CardInserted;
|
|
_cardMonitor.Dispose();
|
|
_cardMonitor = null;
|
|
_initialised = false;
|
|
}
|
|
Console.WriteLine("Starting.. Getting available readers");
|
|
var ctxFactory = ContextFactory.Instance;
|
|
using (var context = ctxFactory.Establish(SCardScope.System))
|
|
{
|
|
var readerNames = context.GetReaders();
|
|
if (!NoReaderAvailable(readerNames))
|
|
{
|
|
//we have a reader available, so initialise!
|
|
Console.WriteLine("Choosing first available reader: " + readerNames.First());
|
|
_readerName = readerNames.First();
|
|
_cardMonitor = new SCardMonitor(ctxFactory, SCardScope.System);
|
|
_cardMonitor.CardInserted += _cardMonitor_CardInserted;
|
|
_cardMonitor.Start(_readerName);
|
|
|
|
_initialised = true;
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("No Card Reader is available..");
|
|
}
|
|
}
|
|
}
|
|
_mainWorkerTerminationSignal.WaitOne(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<string> readerNames)
|
|
{
|
|
return readerNames == null || readerNames.Count < 1;
|
|
}
|
|
}
|
|
}
|