I'm building a C# Win Form application with Visual Studio 2019, that aims to communicate with a SmartCards (ACR 122U).
To be short: the type of tags I'm working with are passive tags that aren't recognized by the reader. The only way to work with these tags is to send direct commands to the chip inside the reader.
Using winscard.dll I managed to do it.
I'm trying to make a backup of the tag: the procedure have to read and store 128 blocks (so 128 SCardControl will be called).
If I do it in the UI thread, it works like a charm (5 seconds max, 30MB of memory usage for the process during the procedure). But if I try to do it in a background thread, it takes forever (25 seconds min, and 150MB of memory usage for the process during the procedure).
Why it goes like that?
EDIT:
Here's some code of the thread
//All the DllImport directives:
[DllImport("winscard.dll")]
public static extern int SCardEstablishContext(uint dwScope, IntPtr notUsed1, IntPtr notUsed2, out IntPtr phContext);
[DllImport("winscard.dll", EntryPoint = "SCardListReadersA", CharSet = CharSet.Ansi)]
public static extern int SCardListReaders(IntPtr hContext, byte[] mszGroups, byte[] mszReaders, ref UInt32 pcchReaders);
//... Other working method delcarations
//Declaration of the "slow" method SCardControl
[DllImport("winscard.dll")]
public static extern int SCardControl(IntPtr hCard, int dwControlCode, byte[] lpInBuffer, uint cbInBufferSize, byte[] lpOutBuffer, ref uint cbOutBufferSize, ref int lpBytesReturned);
//... Other declarations.
private void btnBackup_Click(object sender, EventArgs e)
{
Thread t = new Thread(bgWorker);
t.Start();
//bgWorker();
}
public void bgWorker() {
int res;
uint SystemScope = 2; //From the documentation. Tried both 1 and 2 (User scope and System Scope)
uint readerNum = 0;
uint controlMode = 3; //Using SCARD_SHARE_DIRECT as control mode in order to communicate with the reader
uint protocolToUse = 0; //Using SCARD_PROTOCOL_UNDEFINED as protocol (must use it in order to use SCARD_SHARE_DIRECT)
int EscapeCode = 3225264; //Suggested by ACR 122 U: Escape code in order to send commands to the reader, computes as SCARD_CTL_CODE(3500) in C.
string ReadBlockCmd = "FF000000..." //Standard read command in hex for the tag from dtatasheet
IntPtr context = IntPtr.Zero;
IntPtr simulatedCard = IntPtr.Zero;
IntPtr protocolEstablished = IntPtr.Zero;
byte[] readerStream;
string[] readerList;
byte[] retStream = new byte[1000];
uint sizeRetStream = 0;
int sizeResponse = 0;
List<string> cardBlocks = new List<string>();
//NOTE: "res" is always = 0 when everything works. I cutted off the parts where i check the value of "res".
//Establishing context
res = SCardEstablishContext(SystemScope, IntPtr.Zero, IntPtr.Zero, out context);
//Getting the reader list (the return is in "readerStream", with a multistring value)
res = SCardListReaders(context, null, null, ref readerNum);
readerStream = new byte[readerNum];
res = SCardListReaders(context, null, readerStream, ref readerNum);
readerList = Encoding.ASCII.GetString(readerStream).Split('\0');
//Connect to the reader
res = SCardConnect(context, readerList[0], controlMode, protocolToUse, ref simulatedCard, ref protocolEstablished);
/*
* Some calls to SCardControl to configure the reader in order to work with my tags
*/
//Backup procedure
for(int i = 0; i < 128; i++)
{
SCardControl(simulatedCard, EscapeCode, HexStrToByteArray(ReadBlockCmd + i.ToString("X2")), (uint)ReadBlockCmd.Length / 2 + 1, retStream, ref sizeRetStream, ref sizeResponse);
cardBlocks.Add(ByteArrayToHexStr(retStream, sizeResponse));
}
//Here it supposed to do the backup on file, but i removed it in order to limit the IO ops
}
If you comment the thread launching part and uncomment the call to bgWorker() the procedure lasts like 2.1 seconds. If you keep it like this (using the thread), the procedure lasts more than 20 seconds (no matter if in debug mode, in release, within Visual Studio or outside).