Version: Smart Feature Phone 2.6

winscard-nfc

WinSCard & NFC API Documentation#

Overview#

The WinSCard API provides applications with the ability to interact with both contact-based smart cards and NFC (Near Field Communication) cards and readers through the PC/SC Resource Manager. This API allows applications to establish connections with smart cards, send commands, manage transactions, and work with NFC-enabled devices.

Important Note on SCardStatus Timeout Behavior#

⚠️ SCardStatus Synchronous Operation with 15-Second Timeout#

The SCardStatus function operates as a synchronous blocking call with an internal 15-second timeout. Applications should be aware of this behavior when implementing card detection logic.

Critical Behavior:

  • 15-second timeout: If no card is detected within 15 seconds, the function will return with an error
  • Blocking operation: The call will block the executing thread until either:
    • A card is detected
    • The 15-second timeout expires
    • An error occurs

NFC-Specific Considerations#

NFC Reader Detection#

NFC readers appear as standard PC/SC readers in the system. Applications can detect NFC-enabled readers using the same SCardListReaders function:

// NFC readers will appear in the reader list alongside contact-based readers
ret = SCardListReaders(hContext, NULL, NULL, &dwReaders);

NFC Card Protocols#

When working with NFC cards, the following protocols are commonly used:

  • ISO 14443 Type A/B (MIFARE, DESFire, etc.)
  • ISO 15693 (Vicinity cards)
  • FeliCa (Sony proprietary)

Establishing Context#

SCardEstablishContext#

Creates an Application Context to the PC/SC Resource Manager. This must be the first WinSCard function called for both contact and NFC card operations.

DWORD SCardEstablishContext(DWORD dwScope, const void* pvReserved1, const void* pvReserved2, SCARDCONTEXT* phContext);

NFC-Specific Notes:

  • Works identically for both contact-based and NFC smart cards
  • No special initialization required for NFC readers

Reader Management#

SCardListReaders#

Returns a list of currently available readers, including NFC-enabled readers.

DWORD SCardListReaders(SCARDCONTEXT hContext, const char* mszGroups, char* mszReaders, DWORD* pcchReaders);

NFC-Specific Usage:

DWORD dwReaders = 0;
char *mszReaders = NULL;
// Get all readers including NFC readers
ret = SCardListReaders(hContext, NULL, NULL, &dwReaders);
if (ret == SCARD_S_SUCCESS) {
mszReaders = (char*)malloc(dwReaders);
ret = SCardListReaders(hContext, NULL, mszReaders, &dwReaders);
// Identify NFC readers (often contain "NFC" in their name)
char *readerName = mszReaders;
while (*readerName != '\0') {
if (strstr(readerName, "NFC") != NULL) {
printf("Found NFC reader: %s\n", readerName);
}
readerName += strlen(readerName) + 1;
}
}

NFC Card Connection Management#

SCardConnect#

Establishes a connection to NFC readers and cards. The connection process for NFC cards is similar to contact cards but may involve different protocols.

DWORD SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader, DWORD dwShareMode, DWORD dwPreferredProtocols, SCARDHANDLE* phCard, DWORD* pdwActiveProtocol);

NFC-Specific Parameters:

  • szReader - Name of the NFC reader
  • dwPreferredProtocols - For NFC cards, typically use:
    • SCARD_PROTOCOL_T1 - Commonly used for NFC communications
    • SCARD_PROTOCOL_RAW - For direct access to NFC card data

NFC Connection Example:

SCARDHANDLE hCard = 0;
DWORD dwActiveProtocol = 0;
// Connect to NFC reader - use T1 protocol common for NFC
ret = SCardConnect(hContext, nfcReaderName,
SCARD_SHARE_SHARED,
SCARD_PROTOCOL_T1, // Typical for NFC
&hCard, &dwActiveProtocol);
if (ret == SCARD_S_SUCCESS) {
printf("Connected to NFC card with protocol: 0x%08X\n", dwActiveProtocol);
}

NFC Card Status Monitoring with Timeout Considerations#

SCardStatus#

Retrieves the current status of NFC readers and cards. Important: This is a synchronous call with a 15-second internal timeout.

DWORD SCardStatus(SCARDHANDLE hCard, char* szReaderName, DWORD* pcchReaderLen, DWORD* pdwState, DWORD* pdwProtocol, unsigned char* pbAtr, DWORD* pcbAtrLen);

Timeout Behavior:

  • Blocks for up to 15 seconds waiting for card detection
  • Returns error if no card is detected within the timeout period
  • CARD DETECTED ERROR may occur if timeout expires

Best Practices for NFC Status Monitoring:

// Non-blocking approach for NFC card monitoring
DWORD CheckNFCCardStatusNonBlocking(SCARDHANDLE hCard) {
DWORD dwState, dwProtocol, cbAtrLen = 0;
char szReaderName[256];
DWORD cchReaderLen = sizeof(szReaderName);
unsigned char pbAtr[36];
// Use short timeout or implement asynchronous checking
DWORD ret = SCardStatus(hCard, szReaderName, &cchReaderLen,
&dwState, &dwProtocol, pbAtr, &cbAtrLen);
if (ret == SCARD_S_SUCCESS) {
if (dwState & SCARD_PRESENT) {
printf("NFC card detected\n");
return PROCESS_CARD_DETECTED;
} else {
printf("No NFC card present\n");
return NO_CARD_PRESENT;
}
} else if (ret == SCARD_E_NO_SMARTCARD) {
printf("No NFC card detected within timeout period\n");
return NO_CARD_TIMEOUT;
} else {
printf("SCardStatus error: 0x%08X\n", ret);
return STATUS_ERROR;
}
}

Alternative Approach Using Threading:

// Thread function to monitor NFC status without blocking main thread
DWORD WINAPI NFCStatusMonitorThread(LPVOID lpParam) {
SCARDHANDLE hCard = *(SCARDHANDLE*)lpParam;
BOOL monitoring = TRUE;
while (monitoring) {
DWORD dwState, dwProtocol, cbAtrLen = 0;
char szReaderName[256];
DWORD cchReaderLen = sizeof(szReaderName);
unsigned char pbAtr[36];
DWORD ret = SCardStatus(hCard, szReaderName, &cchReaderLen,
&dwState, &dwProtocol, pbAtr, &cbAtrLen);
if (ret == SCARD_S_SUCCESS) {
if (dwState & SCARD_PRESENT) {
printf("NFC card detected in background thread\n");
// Notify main thread
PostMessage(hMainWindow, WM_NFC_CARD_DETECTED, 0, 0);
}
}
// Shorter sleep to check more frequently
Sleep(2000); // Check every 2 seconds instead of blocking for 15
}
return 0;
}

Handling SCardStatus Timeout in Applications:

// Robust NFC card detection with timeout handling
BOOL DetectNFCCardWithTimeout(SCARDHANDLE hCard, DWORD maxWaitMs) {
DWORD startTime = GetTickCount();
while ((GetTickCount() - startTime) < maxWaitMs) {
DWORD dwState, dwProtocol, cbAtrLen = 0;
char szReaderName[256];
DWORD cchReaderLen = sizeof(szReaderName);
unsigned char pbAtr[36];
DWORD ret = SCardStatus(hCard, szReaderName, &cchReaderLen,
&dwState, &dwProtocol, pbAtr, &cbAtrLen);
if (ret == SCARD_S_SUCCESS && (dwState & SCARD_PRESENT)) {
printf("NFC card detected after %lu ms\n", GetTickCount() - startTime);
return TRUE;
}
// Short delay before retry to avoid excessive CPU usage
Sleep(500);
}
printf("NFC card detection timeout after %lu ms\n", maxWaitMs);
return FALSE;
}

NFC Card Communication#

SCardTransmit#

Sends APDU commands to NFC cards. The APDU structure for NFC cards follows the same standard as contact cards but may use different command sets.

DWORD SCardTransmit(SCARDHANDLE hCard, LPCSCARD_IO_REQUEST pioSendPci, const unsigned char* pbSendBuffer, DWORD cbSendLength, LPCSCARD_IO_REQUEST pioRecvPci, unsigned char* pbRecvBuffer, DWORD* pcbRecvLength);

NFC-Specific APDU Examples:

// SELECT command for NFC cards (ISO 14443)
unsigned char SELECT_NFC_APDU[] = {
0x00, 0xA4, 0x04, 0x00, // SELECT command
0x07, // Length
0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01 // NFC application ID
};
// READ BINARY command for NFC memory
unsigned char READ_NFC_APDU[] = {
0x00, 0xB0, 0x00, 0x00, // READ BINARY
0x10 // Read 16 bytes
};
unsigned char pbRecvBuffer[256];
DWORD pcbRecvLength = sizeof(pbRecvBuffer);
// Send command to NFC card
ret = SCardTransmit(hCard, NULL, SELECT_NFC_APDU,
sizeof(SELECT_NFC_APDU), NULL,
pbRecvBuffer, &pcbRecvLength);

Common NFC Card Operations#

Reading NFC Card Data:

// Function to read data from NFC card
DWORD ReadNFCCardData(SCARDHANDLE hCard, BYTE blockNumber, BYTE* data, DWORD* dataLength) {
unsigned char readApdu[] = {
0xFF, 0xB0, 0x00, blockNumber, // READ BINARY for NFC
0x10 // Read 16 bytes
};
unsigned char response[256];
DWORD responseLength = sizeof(response);
DWORD ret = SCardTransmit(hCard, NULL, readApdu, sizeof(readApdu),
NULL, response, &responseLength);
if (ret == SCARD_S_SUCCESS && responseLength >= 2) {
// Check SW1/SW2 for success (0x90 0x00)
if (response[responseLength-2] == 0x90 && response[responseLength-1] == 0x00) {
memcpy(data, response, responseLength-2);
*dataLength = responseLength-2;
return SCARD_S_SUCCESS;
}
}
return ret;
}

Writing to NFC Card:

// Function to write data to NFC card
DWORD WriteNFCCardData(SCARDHANDLE hCard, BYTE blockNumber, const BYTE* data, DWORD dataLength) {
unsigned char writeApdu[5 + 16] = { // Header + max 16 bytes data
0xFF, 0xD6, 0x00, blockNumber, // UPDATE BINARY for NFC
(BYTE)dataLength // Data length
};
memcpy(&writeApdu[5], data, dataLength);
unsigned char response[256];
DWORD responseLength = sizeof(response);
DWORD ret = SCardTransmit(hCard, NULL, writeApdu, 5 + dataLength,
NULL, response, &responseLength);
if (ret == SCARD_S_SUCCESS && responseLength >= 2) {
// Check SW1/SW2 for success (0x90 0x00)
if (response[responseLength-2] == 0x90 && response[responseLength-1] == 0x00) {
return SCARD_S_SUCCESS;
}
}
return ret;
}

Transaction Management for NFC#

SCardBeginTransaction / SCardEndTransaction#

Provides exclusive access to NFC cards during multiple operations, ensuring data consistency.

// NFC transaction example
DWORD PerformNFCTransaction(SCARDHANDLE hCard) {
DWORD ret = SCardBeginTransaction(hCard);
if (ret != SCARD_S_SUCCESS) {
return ret;
}
// Perform multiple NFC operations
BYTE data[16];
DWORD dataLength;
ret = ReadNFCCardData(hCard, 0x00, data, &dataLength);
if (ret == SCARD_S_SUCCESS) {
// Modify data
data[0] = 0xAA;
ret = WriteNFCCardData(hCard, 0x00, data, dataLength);
}
// Always end transaction
SCardEndTransaction(hCard, SCARD_LEAVE_CARD);
return ret;
}

Complete NFC Workflow Example with Timeout Handling#

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include "winscard.h"
#define CHECK_ERROR(func, ret) \
if (ret != SCARD_S_SUCCESS) { \
printf("NFC Error in %s: 0x%08X\n", #func, ret); \
goto cleanup; \
}
// Function to detect NFC card with custom timeout
BOOL WaitForNFCCard(SCARDHANDLE hCard, DWORD timeoutMs) {
DWORD startTime = GetTickCount();
printf("Waiting for NFC card (timeout: %lu ms)...\n", timeoutMs);
while ((GetTickCount() - startTime) < timeoutMs) {
DWORD dwState, dwProtocol, cbAtrLen = 0;
char szReaderName[256];
DWORD cchReaderLen = sizeof(szReaderName);
unsigned char pbAtr[36];
DWORD ret = SCardStatus(hCard, szReaderName, &cchReaderLen,
&dwState, &dwProtocol, pbAtr, &cbAtrLen);
if (ret == SCARD_S_SUCCESS) {
if (dwState & SCARD_PRESENT) {
DWORD elapsed = GetTickCount() - startTime;
printf("NFC card detected after %lu ms\n", elapsed);
return TRUE;
}
} else if (ret != SCARD_E_NO_SMARTCARD) {
printf("SCardStatus error: 0x%08X\n", ret);
}
// Avoid busy waiting
Sleep(100);
}
printf("NFC card detection timeout after %lu ms\n", timeoutMs);
return FALSE;
}
int main() {
SCARDCONTEXT hContext = 0;
SCARDHANDLE hCard = 0;
DWORD dwActiveProtocol = 0;
DWORD dwReaders = 0;
char *mszReaders = NULL;
char *nfcReaderName = NULL;
DWORD ret = SCARD_S_SUCCESS;
// 1. Establish context for NFC operations
ret = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
CHECK_ERROR(SCardEstablishContext, ret);
printf("NFC Context established successfully.\n");
// 2. Find NFC readers
ret = SCardListReaders(hContext, NULL, NULL, &dwReaders);
CHECK_ERROR(SCardListReaders, ret);
mszReaders = (char*)malloc(dwReaders);
ret = SCardListReaders(hContext, NULL, mszReaders, &dwReaders);
CHECK_ERROR(SCardListReaders, ret);
// Look for NFC readers
char *readerName = mszReaders;
while (*readerName != '\0') {
if (strstr(readerName, "NFC") != NULL) {
nfcReaderName = readerName;
printf("Found NFC reader: %s\n", nfcReaderName);
break;
}
readerName += strlen(readerName) + 1;
}
if (nfcReaderName == NULL) {
printf("No NFC reader found\n");
goto cleanup;
}
// 3. Connect to NFC card
ret = SCardConnect(hContext, nfcReaderName,
SCARD_SHARE_SHARED,
SCARD_PROTOCOL_T1, // Typical for NFC
&hCard, &dwActiveProtocol);
CHECK_ERROR(SCardConnect, ret);
printf("Connected to NFC card with protocol: 0x%08X\n", dwActiveProtocol);
// 4. Wait for NFC card with custom timeout (avoid 15-second block)
if (!WaitForNFCCard(hCard, 10000)) { // 10 second custom timeout
printf("No NFC card detected within custom timeout period\n");
goto cleanup;
}
// 5. Begin transaction for NFC operations
ret = SCardBeginTransaction(hCard);
CHECK_ERROR(SCardBeginTransaction, ret);
printf("NFC transaction started.\n");
// 6. Perform NFC operations
printf("NFC card is present, performing operations...\n");
// Example: Send SELECT command to NFC card
unsigned char SELECT_NFC_APDU[] = {
0x00, 0xA4, 0x04, 0x00, 0x07, 0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01
};
unsigned char pbRecvBuffer[256];
DWORD pcbRecvLength = sizeof(pbRecvBuffer);
ret = SCardTransmit(hCard, NULL, SELECT_NFC_APDU,
sizeof(SELECT_NFC_APDU), NULL,
pbRecvBuffer, &pcbRecvLength);
CHECK_ERROR(SCardTransmit, ret);
printf("NFC APDU response (%d bytes):\n", pcbRecvLength);
for (DWORD i = 0; i < pcbRecvLength; i++) {
printf("%02X ", pbRecvBuffer[i]);
}
printf("\n");
// 7. End NFC transaction
ret = SCardEndTransaction(hCard, SCARD_LEAVE_CARD);
CHECK_ERROR(SCardEndTransaction, ret);
printf("NFC transaction ended.\n");
cleanup:
if (hCard != 0) {
SCardDisconnect(hCard, SCARD_LEAVE_CARD);
printf("Disconnected from NFC card.\n");
}
if (mszReaders != NULL) {
free(mszReaders);
}
if (hContext != 0) {
SCardReleaseContext(hContext);
printf("NFC Context released.\n");
}
return (ret == SCARD_S_SUCCESS) ? 0 : 1;
}

NFC-Specific Error Handling with Timeout Considerations#

When working with NFC cards, pay special attention to timeout-related errors:

// Enhanced error handling for NFC with timeout awareness
void HandleNFCError(DWORD ret) {
switch (ret) {
case SCARD_E_NO_SMARTCARD:
printf("No NFC card detected - 15-second timeout may have occurred\n");
break;
case SCARD_W_REMOVED_CARD:
printf("NFC card was removed during operation\n");
break;
case SCARD_E_PROTO_MISMATCH:
printf("NFC protocol mismatch - try SCARD_PROTOCOL_T1\n");
break;
case SCARD_E_TIMEOUT:
printf("NFC operation timeout - card may be unresponsive\n");
break;
default:
printf("NFC operation error: 0x%08X\n", ret);
}
}
// Function to handle SCardStatus with timeout awareness
DWORD SafeSCardStatus(SCARDHANDLE hCard, DWORD* pdwState, DWORD timeoutMs) {
DWORD startTime = GetTickCount();
while ((GetTickCount() - startTime) < timeoutMs) {
DWORD dwState, dwProtocol, cbAtrLen = 0;
char szReaderName[256];
DWORD cchReaderLen = sizeof(szReaderName);
unsigned char pbAtr[36];
DWORD ret = SCardStatus(hCard, szReaderName, &cchReaderLen,
&dwState, &dwProtocol, pbAtr, &cbAtrLen);
if (ret == SCARD_S_SUCCESS) {
*pdwState = dwState;
return ret;
} else if (ret != SCARD_E_NO_SMARTCARD) {
return ret;
}
Sleep(100); // Short delay before retry
}
return SCARD_E_TIMEOUT;
}

This extended documentation provides comprehensive guidance for using the WinSCard API with NFC-enabled readers and cards, including specific handling of the 15-second synchronous timeout in SCardStatus and best practices for NFC technology integration with proper timeout management.