#include <winscard.h>
#include <stdio.h>

#define CHECK_RV(method, rv) if (rv != SCARD_S_SUCCESS) { \
    printf("%s: %s (0x%lX)\n", method, pcsc_stringify_error(rv), rv); \
    if (mszReaders != NULL)  free(mszReaders); \
    return rv; \
  }

static char *pcsc_stringify_error(LONG rv) {
 static char out[20];
 sprintf_s(out, sizeof(out), "0x%08X", rv);

 return out;
}

int main() {
  SCARDCONTEXT hContext;
  SCARDHANDLE hCard;
  DWORD dwActiveProtocol;
  LONG rv;
  SCARD_IO_REQUEST pioSendPci;
  BYTE pbRecvBuffer[258];
  DWORD dwRecvLength;
  DWORD dwReaders;
  LPTSTR mszReaders = NULL;
  BYTE serial_cmd[] = { 0x90, 0xB8, 0x00, 0x00, 0x07 }; // serial number apdu
  int i;

  // establish the context
  rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
  CHECK_RV("SCardEstablishContext", rv);

  // detect the reader
  rv = SCardListReaders(hContext, NULL, NULL, &dwReaders);
  CHECK_RV("SCardListReaders", rv);
  mszReaders = calloc(dwReaders, sizeof(char));
  rv = SCardListReaders(hContext, NULL, mszReaders, &dwReaders);
  CHECK_RV("SCardListReaders", rv);
  printf("reader name: %s\n", mszReaders);

  // connect to my reader
  // opensc can be configured SCARD_SHARE_SHARED or SCARD_SHARE_EXCLUSIVE
  rv = SCardConnect(hContext, mszReaders, SCARD_SHARE_SHARED, 
    SCARD_PROTOCOL_T0|SCARD_PROTOCOL_T1, &hCard, &dwActiveProtocol);
  CHECK_RV("SCardConnect", rv);

  // just start a transaction
  rv = SCardBeginTransaction(hCard);
  CHECK_RV("SCardBeginTransaction", rv);

  // send apdu to get the serial number => DNIe is T0
  dwRecvLength = sizeof(pbRecvBuffer);
  rv = SCardTransmit(hCard, SCARD_PCI_T0, serial_cmd, sizeof(serial_cmd), NULL, pbRecvBuffer, &dwRecvLength);
  CHECK_RV("SCardTransmit", rv);
  printf("response: ");
  for (i = 0; i < dwRecvLength; i++) {
    printf("%02X ", pbRecvBuffer[i]);
  }
  printf("\n");

  // perform the reconnect
  // opensc can be configured SCARD_SHARE_SHARED or SCARD_SHARE_EXCLUSIVE
  // opensc uses SCARD_UNPOWER_CARD or SCARD_RESET_CARD
  rv = SCardReconnect(hCard, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0|SCARD_PROTOCOL_T1,
          SCARD_RESET_CARD, &dwActiveProtocol);
  CHECK_RV("SCardReconnect", rv);

  // send apdu to get the serial number => DNIe is T0
  dwRecvLength = sizeof(pbRecvBuffer);
  rv = SCardTransmit(hCard, SCARD_PCI_T0, serial_cmd, sizeof(serial_cmd), NULL, pbRecvBuffer, &dwRecvLength);
  CHECK_RV("SCardTransmit", rv);
  printf("response: ");
  for (i = 0; i < dwRecvLength; i++) {
    printf("%02X ", pbRecvBuffer[i]);
  }
  printf("\n");

  // end the transaction
  rv = SCardEndTransaction(hCard, SCARD_LEAVE_CARD);
  CHECK_RV("SCardEndTransaction", rv);

  // disconnect
  rv = SCardDisconnect(hCard, SCARD_UNPOWER_CARD);
  CHECK_RV("SCardDisconnect", rv);

  // release
  rv = SCardReleaseContext(hContext);
  CHECK_RV("SCardReleaseContext", rv);

  free(mszReaders);

  return rv;
}