Click here to Skip to main content
15,880,905 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
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.

RELEVANT INFORMATION

  • I am using Visual Studio C++ 2013
  • Operating system is Windows 8.1
  • Reader used is ACR122U[^]
  • MVCE that reproduces the problem:

C++
#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:

  • Reader is not plugged in
  • Reader is plugged in, and program is terminated by pressing ENTER as instructed

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 0x120C is the SmartCardListener from the demo.

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.  
First-chance exception at 0x76DD5EF8 in SO_Demo.exe: Microsoft C++ exception: unsigned long at memory location 0x0139F6D0.  
The thread 0x1d2c has exited with code 0 (0x0).

Thread ox1D2C is the SmartCardListener from the demo.

QUESTION

  • Is my conclusion correct ? Was this just a false alarm ?
  • If my conclusion is false, can you instruct me on how to solve this problem ?


What I have tried:

In both cases I did the following:


  • Went to Visual Studio menu Debug -> Exceptions and checked Thrown checkbox
  • Walked the code in Debug mode by pressing F10
  • Each time it would break at Smart Card API
  • A popup "First chance exception..." would come out
  • I would choose Continue (Break and Cancel were also offered)
  • Popup would appear again, and I would choose again 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).

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.

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.
Posted
Updated 27-Jul-18 11:58am

1 solution

What's "SO_Demo.exe"?

IMO, "Demo" is not handling the startup / com / shut down sequence properly; and only the "manual" will tell you that.

All / most devices have a protocol that includes "wait times", etc, before you can expect a response and so forth. Ignore that and things will start choking; whether it's your app or "the vendor's".
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900