Smart Card APIs throw First Chance exceptions but program runs fine
Smart Card APIs throw First Chance exceptions but program runs fine
INTRODUCTION
I am learning how to use Smart Card API in order to obtain card number once it gets inserted into reader.
So far I have managed to create a working application that runs (as far as I can see) without errors.
PROBLEM
During debugging I see various First chance exceptions, but every Smart Card API returns SCARD_S_SUCCESS
and program never crashes nor exhibits any other erroneous behavior.
SCARD_S_SUCCESS
RELEVANT INFORMATION
#include <Windows.h>
#include <iostream>
#include <iomanip>
#include <winscard.h>
#pragma comment(lib, "Winscard.lib")
void f() // helper that transforms error code to meaningful message
{
LPSTR s = NULL;
if (::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, ::GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), s, 0, NULL))
{
if (NULL != s)
{
std::cout << s << std::endl;
::LocalFree(s);
}
}
}
const char* error_code_to_text(LONG error_code) // converts SCARD error code to string
{
switch (error_code)
{
case SCARD_S_SUCCESS:
return "SCARD_S_SUCCESS";
case ERROR_BROKEN_PIPE:
return "ERROR_BROKEN_PIPE";
case SCARD_E_BAD_SEEK:
return "SCARD_E_BAD_SEEK";
case SCARD_E_CANCELLED:
return "SCARD_E_CANCELLED";
case SCARD_E_CANT_DISPOSE:
return "SCARD_E_CANT_DISPOSE";
case SCARD_E_CARD_UNSUPPORTED:
return "SCARD_E_CARD_UNSUPPORTED";
case SCARD_E_CERTIFICATE_UNAVAILABLE:
return "SCARD_E_CERTIFICATE_UNAVAILABLE";
case SCARD_E_COMM_DATA_LOST:
return "SCARD_E_COMM_DATA_LOST";
case SCARD_E_DIR_NOT_FOUND:
return "SCARD_E_DIR_NOT_FOUND";
case SCARD_E_DUPLICATE_READER:
return "SCARD_E_DUPLICATE_READER";
case SCARD_E_FILE_NOT_FOUND:
return "SCARD_E_FILE_NOT_FOUND";
case SCARD_E_ICC_CREATEORDER:
return "SCARD_E_ICC_CREATEORDER";
case SCARD_E_ICC_INSTALLATION:
return "SCARD_E_ICC_INSTALLATION";
case SCARD_E_INSUFFICIENT_BUFFER:
return "SCARD_E_INSUFFICIENT_BUFFER";
case SCARD_E_INVALID_ATR:
return "SCARD_E_INVALID_ATR";
case SCARD_E_INVALID_CHV:
return "SCARD_E_INVALID_CHV";
case SCARD_E_INVALID_HANDLE:
return "SCARD_E_INVALID_HANDLE";
case SCARD_E_INVALID_PARAMETER:
return "SCARD_E_INVALID_PARAMETER";
case SCARD_E_INVALID_TARGET:
return "SCARD_E_INVALID_TARGET";
case SCARD_E_INVALID_VALUE:
return "SCARD_E_INVALID_VALUE";
case SCARD_E_NO_ACCESS:
return "SCARD_E_NO_ACCESS";
case SCARD_E_NO_DIR:
return "SCARD_E_NO_DIR";
case SCARD_E_NO_FILE:
return "SCARD_E_NO_FILE";
case SCARD_E_NO_KEY_CONTAINER:
return "SCARD_E_NO_KEY_CONTAINER";
case SCARD_E_NO_MEMORY:
return "SCARD_E_NO_MEMORY";
case SCARD_E_NO_PIN_CACHE:
return "SCARD_E_NO_PIN_CACHE";
case SCARD_E_NO_READERS_AVAILABLE:
return "SCARD_E_NO_READERS_AVAILABLE";
case SCARD_E_NO_SERVICE:
return "SCARD_E_NO_SERVICE";
case SCARD_E_NO_SMARTCARD:
return "SCARD_E_NO_SMARTCARD";
case SCARD_E_NO_SUCH_CERTIFICATE:
return "SCARD_E_NO_SUCH_CERTIFICATE";
case SCARD_E_NOT_READY:
return "SCARD_E_NOT_READY";
case SCARD_E_NOT_TRANSACTED:
return "SCARD_E_NOT_TRANSACTED";
case SCARD_E_PCI_TOO_SMALL:
return "SCARD_E_PCI_TOO_SMALL";
case SCARD_E_PIN_CACHE_EXPIRED:
return "SCARD_E_PIN_CACHE_EXPIRED";
case SCARD_E_PROTO_MISMATCH:
return "SCARD_E_PROTO_MISMATCH";
case SCARD_E_READ_ONLY_CARD:
return "SCARD_E_READ_ONLY_CARD";
case SCARD_E_READER_UNAVAILABLE:
return "SCARD_E_READER_UNAVAILABLE";
case SCARD_E_READER_UNSUPPORTED:
return "SCARD_E_READER_UNSUPPORTED";
case SCARD_E_SERVER_TOO_BUSY:
return "SCARD_E_SERVER_TOO_BUSY";
case SCARD_E_SERVICE_STOPPED:
return "SCARD_E_SERVICE_STOPPED";
case SCARD_E_SHARING_VIOLATION:
return "SCARD_E_SHARING_VIOLATION";
case SCARD_E_SYSTEM_CANCELLED:
return "SCARD_E_SYSTEM_CANCELLED";
case SCARD_E_TIMEOUT:
return "SCARD_E_TIMEOUT";
case SCARD_E_UNEXPECTED:
return "SCARD_E_UNEXPECTED";
case SCARD_E_UNKNOWN_CARD:
return "SCARD_E_UNKNOWN_CARD";
case SCARD_E_UNKNOWN_READER:
return "SCARD_E_UNKNOWN_READER";
case SCARD_E_UNKNOWN_RES_MNG:
return "SCARD_E_UNKNOWN_RES_MNG";
case SCARD_E_UNSUPPORTED_FEATURE:
return "SCARD_E_UNSUPPORTED_FEATURE";
case SCARD_E_WRITE_TOO_MANY:
return "SCARD_E_WRITE_TOO_MANY";
case SCARD_F_COMM_ERROR:
return "SCARD_F_COMM_ERROR";
case SCARD_F_INTERNAL_ERROR:
return "SCARD_F_INTERNAL_ERROR";
case SCARD_F_UNKNOWN_ERROR:
return "SCARD_F_UNKNOWN_ERROR";
case SCARD_F_WAITED_TOO_LONG:
return "SCARD_F_WAITED_TOO_LONG";
case SCARD_P_SHUTDOWN:
return "SCARD_P_SHUTDOWN";
case SCARD_W_CANCELLED_BY_USER:
return "SCARD_W_CANCELLED_BY_USER";
case SCARD_W_CACHE_ITEM_NOT_FOUND:
return "SCARD_W_CACHE_ITEM_NOT_FOUND";
case SCARD_W_CACHE_ITEM_STALE:
return "SCARD_W_CACHE_ITEM_STALE";
case SCARD_W_CACHE_ITEM_TOO_BIG:
return "SCARD_W_CACHE_ITEM_TOO_BIG";
case SCARD_W_CARD_NOT_AUTHENTICATED:
return "SCARD_W_CARD_NOT_AUTHENTICATED";
case SCARD_W_CHV_BLOCKED:
return "SCARD_W_CHV_BLOCKED";
case SCARD_W_EOF:
return "SCARD_W_EOF";
case SCARD_W_REMOVED_CARD:
return "SCARD_W_REMOVED_CARD";
case SCARD_W_RESET_CARD:
return "SCARD_W_RESET_CARD";
case SCARD_W_SECURITY_VIOLATION:
return "SCARD_W_SECURITY_VIOLATION";
case SCARD_W_UNPOWERED_CARD:
return "SCARD_W_UNPOWERED_CARD";
case SCARD_W_UNRESPONSIVE_CARD:
return "SCARD_W_UNRESPONSIVE_CARD";
case SCARD_W_UNSUPPORTED_CARD:
return "SCARD_W_UNSUPPORTED_CARD";
case SCARD_W_WRONG_CHV:
return "SCARD_W_WRONG_CHV";
default:
return "Unknown error code";
}
}
DWORD WINAPI SmartCardListener(LPVOID arg)
{
// get thread ID to compare it with the one in Output window
std::cout << "SmartCardListener Thread ID = "
<< std::setw(8) << std::setfill('0') << std::hex
<< ::GetCurrentThreadId() << std::endl;
SCARDCONTEXT c = *reinterpret_cast<SCARDCONTEXT *>(arg);
LPTSTR r = NULL;
DWORD cch = SCARD_AUTOALLOCATE;
LONG l = SCardListReaders(c, NULL, (LPTSTR)&r, &cch);
if (SCARD_S_SUCCESS != l)
{
std::cout << "SCardListReaders failed with error code: "
<< error_code_to_text(l) << std::endl;
return 1;
}
SCARD_READERSTATE rs = {};
rs.dwCurrentState = SCARD_STATE_UNAWARE;
rs.szReader = &r[0];
do
{
l = ::SCardGetStatusChange(c, INFINITE, &rs, 1);
rs.dwCurrentState = rs.dwEventState;
}
while (l == SCARD_S_SUCCESS);
if (SCARD_E_CANCELLED != l)
std::cout << "SCardGetStatusChange failed with error code: "
<< error_code_to_text(l) << std::endl;
l = SCardFreeMemory(c, r);
if (SCARD_S_SUCCESS != l)
{
std::cout << "SCardFreeMemory failed with error code: "
<< error_code_to_text(l) << std::endl;
return 1;
}
return 0;
}
int main()
{
// get thread ID to compare it with the one in Output window
std::cout << "Main Thread ID = "
<< std::setw(8)
<< std::setfill('0')
<< std::hex
<< ::GetCurrentThreadId()
<< std::endl;
SCARDCONTEXT c;
LONG l = ::SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &c);
if (SCARD_S_SUCCESS != l)
{
std::cout << "SCardEstablishContext failed with error code: "
<< error_code_to_text(l)
<< std::endl;
return -1;
}
HANDLE t = ::CreateThread(NULL, 0, SmartCardListener, &c, 0, 0);
if (NULL == t)
{
std::cout << "CreateThread failed:" << std::endl;
f();
::SCardReleaseContext(c);
return 0;
}
std::cout << "Press ENTER to quit..." << std::endl;
std::cin.get();
l = ::SCardCancel(c);
if (SCARD_S_SUCCESS != l)
std::cout << "SCardCancel failed with error code: "
<< error_code_to_text(l)
<< std::endl;
DWORD d = ::WaitForSingleObject(t, INFINITE);
switch (d)
{
case WAIT_OBJECT_0:
std::cout << "Graceful exit" << std::endl;
break;
case WAIT_TIMEOUT:
std::cout << "Timeout" << std::endl;
break;
case WAIT_FAILED:
std::cout << "Wait failed: " << std::endl;
f();
::TerminateThread(t, 1); // what else can I do ?
break;
default:
std::cout << "Unknown error" << std::endl;
::TerminateThread(t, 1); // what else can I do ?
break;
}
::CloseHandle(t);
l = ::SCardReleaseContext(c);
if (SCARD_S_SUCCESS != l)
{
std::cout << "Failed to release context" << std::endl;
}
return 0;
}
I have tested 2 cases:
When not plugged in, app properly displays error message, thread exits cleanly, but I get following relevant content from the Output window:
First-chance exception at 0x76DD5EF8 (KernelBase.dll) in SO_Demo.exe: 0x8010002E: Cannot find a smart card reader.
First-chance exception at 0x76DD5EF8 (KernelBase.dll) in SO_Demo.exe: 0x0000071A: The remote procedure call was canceled, or if a call time-out was specified, the call timed out.
First-chance exception at 0x76DD5EF8 in SO_Demo.exe: Microsoft C++ exception: unsigned long at memory location 0x0142F970.
First-chance exception at 0x76DD5EF8 in SO_Demo.exe: Microsoft C++ exception: [rethrow] at memory location 0x00000000.
The thread 0x120c has exited with code 1 (0x1).
Thread ox120C
is the SmartCardListener
from the demo.
ox120C
SmartCardListener
When reader is plugged in, and I press ENTER, code shuts down cleanly.
Notice the relevant portion of the Output window content:
First-chance exception at 0x76DD5EF8 (KernelBase.dll) in SO_Demo.exe: 0x80100002: The action was cancelled by an SCardCancel request.
First-chance exception at 0x76DD5EF8 (KernelBase.dll) in SO_Demo.exe: 0x0000071A: The remote procedure call was canceled, or if a call time-out was specified, the call timed out.
First-chance exception at 0x76DD5EF8 in SO_Demo.exe: Microsoft C++ exception: unsigned long at memory location 0x0139F5E8. // dovde prvi Popup SCGSC
First-chance exception at 0x76DD5EF8 in SO_Demo.exe: Microsoft C++ exception: unsigned long at memory location 0x0139F6D0. // 2gi SCGSC
The thread 0x1d2c has exited with code 0 (0x0).
Thread ox1D2C
is the SmartCardListener
from the demo.
ox1D2C
SmartCardListener
MY EFFORTS
In both cases I did the following:
Thrown
Continue
Break
Cancel
Continue
Again, program would shut down cleanly, inspection of the return values showed SCARD_S_SUCCESS
or expected value (SCARD_E_CANCELLED
when SCardCancel
was called or SCARD_E_NO_READERS_AVAILABLE
when reader was not present).
SCARD_S_SUCCESS
SCARD_E_CANCELLED
SCardCancel
SCARD_E_NO_READERS_AVAILABLE
I have also noticed that the exception always happens on memory location 0x76DD5EF8
but I do not know how to use this information to help me solve the problem.
0x76DD5EF8
I have tried Googling for a solution and the only useful thing I found was this.
Reading through the link provided in the accepted answer, I came to the conclusion that these exceptions might be a false alarm.
QUESTION
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
Have a read: blogs.msdn.microsoft.com/devops/2015/01/07/… In summary every exception starts as a First Chance Exception and is logged by the debugger. If it's caught (and not re-thrown) then it's been handled.
– Richard Critten
17 mins ago