You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
887 lines
18 KiB
887 lines
18 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1998 - 1999
|
|
//
|
|
// File: ifdrdr.cpp
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <conio.h>
|
|
|
|
#include <afx.h>
|
|
#include <afxtempl.h>
|
|
|
|
#include <winioctl.h>
|
|
#include <winsmcrd.h>
|
|
|
|
#include "ifdtest.h"
|
|
|
|
ULONG CReaderList::m_uRefCount;
|
|
ULONG CReaderList::m_uNumReaders;
|
|
CReaderList **CReaderList::m_pList;
|
|
static CString l_CEmpty("");
|
|
|
|
void
|
|
DumpData(
|
|
PCHAR in_pchCaption,
|
|
ULONG in_uIndent,
|
|
PBYTE in_pbData,
|
|
ULONG in_uLength)
|
|
{
|
|
ULONG l_uIndex, l_uLine, l_uCol;
|
|
|
|
printf("%s\n%*s%04x: ", in_pchCaption, in_uIndent, "", 0);
|
|
|
|
for (l_uLine = 0, l_uIndex = 0;
|
|
l_uLine < ((in_uLength - 1) / 8) + 1;
|
|
l_uLine++) {
|
|
|
|
for (l_uCol = 0, l_uIndex = l_uLine * 8;
|
|
l_uCol < 8; l_uCol++,
|
|
l_uIndex++) {
|
|
|
|
printf(
|
|
l_uIndex < in_uLength ? "%02x " : " ",
|
|
in_pbData[l_uIndex]
|
|
);
|
|
}
|
|
|
|
putchar(' ');
|
|
|
|
for (l_uCol = 0, l_uIndex = l_uLine * 8;
|
|
l_uCol < 8; l_uCol++,
|
|
l_uIndex++) {
|
|
|
|
printf(
|
|
l_uIndex < in_uLength ? "%c" : " ",
|
|
isprint(in_pbData[l_uIndex]) ? in_pbData[l_uIndex] : '.'
|
|
);
|
|
}
|
|
|
|
putchar('\n');
|
|
if (l_uIndex < in_uLength) {
|
|
|
|
printf("%*s%04x: ", in_uIndent, "", l_uIndex + 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
CReaderList::CReaderList(
|
|
CString &in_CDeviceName,
|
|
CString &in_CPnPType,
|
|
CString &in_CVendorName,
|
|
CString &in_CIfdType
|
|
)
|
|
{
|
|
m_CDeviceName += in_CDeviceName;
|
|
m_CPnPType += in_CPnPType;
|
|
m_CVendorName += in_CVendorName;
|
|
m_CIfdType += in_CIfdType;
|
|
}
|
|
|
|
CString &
|
|
CReaderList::GetDeviceName(
|
|
ULONG in_uIndex
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Retrieves the device name of a reader
|
|
|
|
Arguments:
|
|
in_uIndex - index to reader list
|
|
|
|
Return Value:
|
|
The device name that can be used to open the reader
|
|
|
|
--*/
|
|
{
|
|
if (in_uIndex >= m_uNumReaders) {
|
|
|
|
return l_CEmpty;
|
|
}
|
|
|
|
return m_pList[in_uIndex]->m_CDeviceName;
|
|
}
|
|
|
|
CString &
|
|
CReaderList::GetIfdType(
|
|
ULONG in_uIndex
|
|
)
|
|
{
|
|
if (in_uIndex >= m_uNumReaders) {
|
|
|
|
return l_CEmpty;
|
|
}
|
|
|
|
return m_pList[in_uIndex]->m_CIfdType;
|
|
}
|
|
|
|
CString &
|
|
CReaderList::GetPnPType(
|
|
ULONG in_uIndex
|
|
)
|
|
{
|
|
if (in_uIndex >= m_uNumReaders) {
|
|
|
|
return l_CEmpty;
|
|
}
|
|
|
|
return m_pList[in_uIndex]->m_CPnPType;
|
|
}
|
|
|
|
CString &
|
|
CReaderList::GetVendorName(
|
|
ULONG in_uIndex
|
|
)
|
|
{
|
|
if (in_uIndex >= m_uNumReaders) {
|
|
|
|
return l_CEmpty;
|
|
}
|
|
|
|
return m_pList[in_uIndex]->m_CVendorName;
|
|
}
|
|
|
|
void
|
|
CReaderList::AddDevice(
|
|
CString in_CDeviceName,
|
|
CString in_CPnPType
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This functions tries to open the reader device supplied by
|
|
in_pchDeviceName. If the device exists it adds it to the list
|
|
of installed readers
|
|
|
|
Arguments:
|
|
in_pchDeviceName - reader device name
|
|
in_pchPnPType - type of reader (wdm-pnp, nt, win9x)
|
|
|
|
--*/
|
|
{
|
|
CReader l_CReader;
|
|
|
|
if (l_CReader.Open(in_CDeviceName)) {
|
|
|
|
if (l_CReader.GetVendorName().IsEmpty()) {
|
|
|
|
LogMessage(
|
|
"VendorName of reader device %s is NULL",
|
|
(LPCSTR) in_CDeviceName
|
|
);
|
|
|
|
} else if (l_CReader.GetIfdType().IsEmpty()) {
|
|
|
|
LogMessage(
|
|
"IfdType of reader device %s is NULL",
|
|
(LPCSTR) in_CDeviceName
|
|
);
|
|
|
|
} else {
|
|
|
|
CReaderList *l_CReaderList = new CReaderList(
|
|
in_CDeviceName,
|
|
in_CPnPType,
|
|
l_CReader.GetVendorName(),
|
|
l_CReader.GetIfdType()
|
|
);
|
|
|
|
// extend the device list array by one
|
|
CReaderList **l_pList =
|
|
new CReaderList *[m_uNumReaders + 1];
|
|
|
|
if (m_pList) {
|
|
|
|
// copy old list of readers to new list of readers
|
|
memcpy(
|
|
l_pList,
|
|
m_pList,
|
|
m_uNumReaders * sizeof(CReaderList *)
|
|
);
|
|
|
|
delete m_pList;
|
|
}
|
|
|
|
m_pList = l_pList;
|
|
m_pList[m_uNumReaders++] = l_CReaderList;
|
|
}
|
|
|
|
l_CReader.Close();
|
|
}
|
|
}
|
|
|
|
CReaderList::CReaderList()
|
|
/*++
|
|
|
|
Routine Description:
|
|
Constructor for CReaderList.
|
|
Builds a list of currently installed and running smart card readers.
|
|
It first tries to find all WDM PnP drivers. These should be registered
|
|
in the registry under the class guid for smart card readers.
|
|
|
|
Then it looks for all 'old style' reader names like \\.\SCReaderN
|
|
|
|
And then it looks for all Windows 9x VxD style readers, which are
|
|
registered in the registry through smclib.vxd
|
|
|
|
--*/
|
|
{
|
|
HKEY l_hKey;
|
|
ULONG l_uIndex;
|
|
|
|
m_uCurrentReader = (ULONG) -1;
|
|
|
|
if (m_uRefCount++ != 0) {
|
|
|
|
return;
|
|
}
|
|
|
|
// look up all WDM PnP smart card readers
|
|
if (RegOpenKey(
|
|
HKEY_LOCAL_MACHINE,
|
|
"System\\CurrentControlSet\\Control\\DeviceClasses\\{50DD5230-BA8A-11D1-BF5D-0000F805F530}",
|
|
&l_hKey) == ERROR_SUCCESS) {
|
|
|
|
ULONG l_uStatus, l_uIndex;
|
|
|
|
for (l_uIndex = 0; ;l_uIndex++) {
|
|
|
|
HKEY l_hDeviceTypeKey;
|
|
UCHAR l_rgchDeviceTypeKey[128];
|
|
ULONG l_uDeviceTypeInstance = 0;
|
|
|
|
// look up 'device type subkey'
|
|
l_uStatus = RegEnumKey(
|
|
l_hKey,
|
|
l_uIndex,
|
|
(PCHAR) l_rgchDeviceTypeKey,
|
|
sizeof(l_rgchDeviceTypeKey)
|
|
);
|
|
|
|
if (l_uStatus != ERROR_SUCCESS) {
|
|
|
|
// no smart card device types found
|
|
break;
|
|
}
|
|
|
|
// open the found 'device type subkey'
|
|
l_uStatus = RegOpenKey(
|
|
l_hKey,
|
|
(PCHAR) l_rgchDeviceTypeKey,
|
|
&l_hDeviceTypeKey
|
|
);
|
|
|
|
if (l_uStatus != ERROR_SUCCESS) {
|
|
|
|
continue;
|
|
}
|
|
|
|
for (l_uDeviceTypeInstance = 0; ; l_uDeviceTypeInstance++) {
|
|
|
|
DWORD l_dwKeyType;
|
|
HKEY l_hDeviceTypeInstanceKey;
|
|
UCHAR l_rgchDeviceName[128];
|
|
UCHAR l_rgchDeviceTypeInstanceKey[128];
|
|
ULONG l_uDeviceNameLen = sizeof(l_rgchDeviceName);
|
|
|
|
// look up device instance subkey
|
|
l_uStatus = RegEnumKey(
|
|
l_hDeviceTypeKey,
|
|
l_uDeviceTypeInstance,
|
|
(PCHAR) l_rgchDeviceTypeInstanceKey,
|
|
sizeof(l_rgchDeviceTypeInstanceKey)
|
|
);
|
|
|
|
if (l_uStatus != ERROR_SUCCESS) {
|
|
|
|
// no instance of the smart card reader type found
|
|
break;
|
|
}
|
|
|
|
// open the found 'device type instance subkey'
|
|
l_uStatus = RegOpenKey(
|
|
l_hDeviceTypeKey,
|
|
(PCHAR) l_rgchDeviceTypeInstanceKey,
|
|
&l_hDeviceTypeInstanceKey
|
|
);
|
|
|
|
if (l_uStatus != ERROR_SUCCESS) {
|
|
|
|
continue;
|
|
}
|
|
|
|
// get the name of the device
|
|
if (RegQueryValueEx(
|
|
l_hDeviceTypeInstanceKey,
|
|
"SymbolicLink",
|
|
NULL,
|
|
&l_dwKeyType,
|
|
l_rgchDeviceName,
|
|
&l_uDeviceNameLen) == ERROR_SUCCESS) {
|
|
|
|
AddDevice(l_rgchDeviceName, READER_TYPE_WDM);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Now look up all non PnP readers
|
|
for (l_uIndex = 0; l_uIndex < MAXIMUM_SMARTCARD_READERS; l_uIndex++) {
|
|
|
|
UCHAR l_rgchDeviceName[128];
|
|
|
|
sprintf(
|
|
(PCHAR) l_rgchDeviceName,
|
|
"\\\\.\\SCReader%d",
|
|
l_uIndex
|
|
);
|
|
|
|
AddDevice(l_rgchDeviceName, READER_TYPE_NT);
|
|
}
|
|
|
|
// Add all Windows95 type readers to the list
|
|
if (RegOpenKey(
|
|
HKEY_LOCAL_MACHINE,
|
|
"System\\CurrentControlSet\\Services\\VxD\\Smclib\\Devices",
|
|
&l_hKey) == ERROR_SUCCESS) {
|
|
|
|
ULONG l_uIndex;
|
|
|
|
for (l_uIndex = 0; l_uIndex < MAXIMUM_SMARTCARD_READERS; l_uIndex++) {
|
|
|
|
UCHAR l_rgchDeviceName[128], l_rgchValueName[128];
|
|
DWORD l_dwValueType;
|
|
ULONG l_uDeviceNameLen = sizeof(l_rgchDeviceName);
|
|
ULONG l_uValueNameLen = sizeof(l_rgchValueName);
|
|
|
|
if (RegEnumValue(
|
|
l_hKey,
|
|
l_uIndex,
|
|
(PCHAR) l_rgchValueName,
|
|
&l_uValueNameLen,
|
|
NULL,
|
|
&l_dwValueType,
|
|
(PUCHAR) l_rgchDeviceName,
|
|
&l_uDeviceNameLen) == ERROR_SUCCESS) {
|
|
|
|
AddDevice(CString("\\\\.\\") + l_rgchDeviceName, READER_TYPE_VXD);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
CReaderList::~CReaderList()
|
|
{
|
|
ULONG l_uIndex;
|
|
|
|
if (--m_uRefCount != 0) {
|
|
|
|
return;
|
|
}
|
|
|
|
for (l_uIndex = 0; l_uIndex < m_uNumReaders; l_uIndex++) {
|
|
|
|
delete m_pList[l_uIndex];
|
|
}
|
|
|
|
if (m_pList) {
|
|
|
|
delete m_pList;
|
|
}
|
|
}
|
|
|
|
// ****************************************************************************
|
|
// CReader methods
|
|
// ****************************************************************************
|
|
|
|
CReader::CReader(
|
|
void
|
|
)
|
|
{
|
|
m_uReplyBufferSize = sizeof(m_rgbReplyBuffer);
|
|
|
|
m_Ovr.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
ResetEvent(m_Ovr.hEvent);
|
|
|
|
m_OvrWait.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
ResetEvent(m_OvrWait.hEvent);
|
|
|
|
m_ScardIoRequest.dwProtocol = 0;
|
|
m_ScardIoRequest.cbPciLength = sizeof(m_ScardIoRequest);
|
|
|
|
m_fDump = FALSE;
|
|
}
|
|
void
|
|
CReader::Close(
|
|
void
|
|
)
|
|
{
|
|
#ifndef SIMULATE
|
|
CloseHandle(m_hReader);
|
|
#endif
|
|
}
|
|
|
|
CString &
|
|
CReader::GetIfdType(
|
|
void
|
|
)
|
|
{
|
|
ULONG l_uAttr = SCARD_ATTR_VENDOR_IFD_TYPE;
|
|
|
|
#ifdef SIMULATE
|
|
m_CIfdType = "DEBUG IfdType";
|
|
#endif
|
|
|
|
if (m_CIfdType.IsEmpty()) {
|
|
|
|
BOOL l_bResult = DeviceIoControl(
|
|
m_hReader,
|
|
IOCTL_SMARTCARD_GET_ATTRIBUTE,
|
|
(void *) &l_uAttr,
|
|
sizeof(ULONG),
|
|
m_rgbReplyBuffer,
|
|
sizeof(m_rgbReplyBuffer),
|
|
&m_uReplyLength,
|
|
&m_Ovr
|
|
);
|
|
|
|
if (l_bResult) {
|
|
|
|
m_rgbReplyBuffer[m_uReplyLength] = '\0';
|
|
m_CIfdType = m_rgbReplyBuffer;
|
|
}
|
|
}
|
|
|
|
return m_CIfdType;
|
|
}
|
|
|
|
LONG
|
|
CReader::GetState(
|
|
PULONG out_puState
|
|
)
|
|
{
|
|
SetLastError(0);
|
|
|
|
BOOL l_bResult = DeviceIoControl(
|
|
m_hReader,
|
|
IOCTL_SMARTCARD_GET_STATE,
|
|
NULL,
|
|
0,
|
|
(void *) out_puState,
|
|
sizeof(ULONG),
|
|
&m_uReplyLength,
|
|
&m_Ovr
|
|
);
|
|
|
|
return GetLastError();
|
|
}
|
|
|
|
CString &
|
|
CReader::GetVendorName(
|
|
void
|
|
)
|
|
{
|
|
ULONG l_uAttr = SCARD_ATTR_VENDOR_NAME;
|
|
|
|
#ifdef SIMULATE
|
|
m_CVendorName = "DEBUG Vendor";
|
|
#endif
|
|
|
|
if (m_CVendorName.IsEmpty()) {
|
|
|
|
BOOL l_bResult = DeviceIoControl(
|
|
m_hReader,
|
|
IOCTL_SMARTCARD_GET_ATTRIBUTE,
|
|
(void *) &l_uAttr,
|
|
sizeof(ULONG),
|
|
m_rgbReplyBuffer,
|
|
sizeof(m_rgbReplyBuffer),
|
|
&m_uReplyLength,
|
|
&m_Ovr
|
|
);
|
|
|
|
if (l_bResult) {
|
|
|
|
m_rgbReplyBuffer[m_uReplyLength] = '\0';
|
|
m_CVendorName = m_rgbReplyBuffer;
|
|
}
|
|
}
|
|
|
|
return m_CVendorName;
|
|
}
|
|
|
|
ULONG
|
|
CReader::GetDeviceUnit(
|
|
void
|
|
)
|
|
{
|
|
ULONG l_uAttr = SCARD_ATTR_DEVICE_UNIT;
|
|
|
|
BOOL l_bResult = DeviceIoControl(
|
|
m_hReader,
|
|
IOCTL_SMARTCARD_GET_ATTRIBUTE,
|
|
(void *) &l_uAttr,
|
|
sizeof(ULONG),
|
|
m_rgbReplyBuffer,
|
|
sizeof(m_rgbReplyBuffer),
|
|
&m_uReplyLength,
|
|
&m_Ovr
|
|
);
|
|
|
|
return (ULONG) *m_rgbReplyBuffer;
|
|
}
|
|
|
|
BOOL
|
|
CReader::Open(
|
|
void
|
|
)
|
|
{
|
|
if (m_CDeviceName.IsEmpty()) {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
// Try to open the reader.
|
|
m_hReader = CreateFile(
|
|
(LPCSTR) m_CDeviceName,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_FLAG_OVERLAPPED,
|
|
NULL
|
|
);
|
|
|
|
if (m_hReader == INVALID_HANDLE_VALUE ) {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
CReader::Open(
|
|
CString & in_CDeviceName
|
|
)
|
|
{
|
|
// save the reader name
|
|
m_CDeviceName += in_CDeviceName;
|
|
|
|
#ifdef SIMULATE
|
|
return TRUE;
|
|
#endif
|
|
|
|
return Open();
|
|
}
|
|
|
|
LONG
|
|
CReader::PowerCard(
|
|
ULONG in_uMinorIoControl
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Cold resets the current card and sets the ATR
|
|
of the card in the reader class.
|
|
|
|
Return Value:
|
|
|
|
Returns the result of the DeviceIoControl call
|
|
|
|
--*/
|
|
{
|
|
BOOL l_bResult;
|
|
ULONG l_uReplyLength;
|
|
CHAR l_rgbAtr[SCARD_ATR_LENGTH];
|
|
|
|
SetLastError(0);
|
|
|
|
l_bResult = DeviceIoControl (
|
|
m_hReader,
|
|
IOCTL_SMARTCARD_POWER,
|
|
&in_uMinorIoControl,
|
|
sizeof(in_uMinorIoControl),
|
|
l_rgbAtr,
|
|
sizeof(l_rgbAtr),
|
|
&l_uReplyLength,
|
|
&m_Ovr
|
|
);
|
|
|
|
if (l_bResult == FALSE && GetLastError() == ERROR_IO_PENDING) {
|
|
|
|
SetLastError(0);
|
|
|
|
l_bResult = GetOverlappedResult(
|
|
m_hReader,
|
|
&m_Ovr,
|
|
&l_uReplyLength,
|
|
TRUE
|
|
);
|
|
}
|
|
|
|
if (GetLastError() == ERROR_SUCCESS) {
|
|
|
|
SetAtr((PBYTE) l_rgbAtr, l_uReplyLength);
|
|
}
|
|
|
|
return GetLastError();
|
|
}
|
|
|
|
LONG
|
|
CReader::SetProtocol(
|
|
const ULONG in_uProtocol
|
|
)
|
|
{
|
|
BOOL l_bResult;
|
|
|
|
m_ScardIoRequest.dwProtocol = in_uProtocol;
|
|
m_ScardIoRequest.cbPciLength = sizeof(SCARD_IO_REQUEST);
|
|
|
|
SetLastError(0);
|
|
|
|
l_bResult = DeviceIoControl (
|
|
m_hReader,
|
|
IOCTL_SMARTCARD_SET_PROTOCOL,
|
|
(void *) &in_uProtocol,
|
|
sizeof(ULONG),
|
|
m_rgbReplyBuffer,
|
|
sizeof(m_rgbReplyBuffer),
|
|
&m_uReplyLength,
|
|
&m_Ovr
|
|
);
|
|
|
|
if (l_bResult == FALSE && GetLastError() == ERROR_IO_PENDING) {
|
|
|
|
SetLastError(0);
|
|
|
|
l_bResult = GetOverlappedResult(
|
|
m_hReader,
|
|
&m_Ovr,
|
|
&m_uReplyLength,
|
|
TRUE
|
|
);
|
|
}
|
|
|
|
return GetLastError();
|
|
}
|
|
|
|
LONG
|
|
CReader::Transmit(
|
|
PUCHAR in_pchApdu,
|
|
ULONG in_uApduLength,
|
|
PUCHAR *out_pchReply,
|
|
PULONG out_puReplyLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Transmits an apdu using the currently connected reader
|
|
|
|
Arguments:
|
|
in_pchApdu - the apdu to send
|
|
in_uApduLength - the length of the apdu
|
|
out_pchReply - result returned from the reader/card
|
|
out_puReplyLength - pointer to store number of bytes returned
|
|
|
|
Return Value:
|
|
The nt-status code returned by the reader
|
|
|
|
--*/
|
|
{
|
|
BOOL l_bResult;
|
|
ULONG l_uBufferLength = m_ScardIoRequest.cbPciLength + in_uApduLength;
|
|
PUCHAR l_pchBuffer = new UCHAR [l_uBufferLength];
|
|
|
|
// Copy io-request header to request buffer
|
|
memcpy(
|
|
l_pchBuffer,
|
|
&m_ScardIoRequest,
|
|
m_ScardIoRequest.cbPciLength
|
|
);
|
|
|
|
// copy io-request header to reply buffer
|
|
memcpy(
|
|
m_rgbReplyBuffer,
|
|
&m_ScardIoRequest,
|
|
m_ScardIoRequest.cbPciLength
|
|
);
|
|
|
|
// append apdu to buffer
|
|
memcpy(
|
|
l_pchBuffer + m_ScardIoRequest.cbPciLength,
|
|
in_pchApdu,
|
|
in_uApduLength
|
|
);
|
|
|
|
if (m_fDump) {
|
|
|
|
DumpData(
|
|
"\n RequestData:",
|
|
3,
|
|
l_pchBuffer,
|
|
l_uBufferLength
|
|
);
|
|
}
|
|
|
|
SetLastError(0);
|
|
// send the request to the card
|
|
l_bResult = DeviceIoControl (
|
|
m_hReader,
|
|
IOCTL_SMARTCARD_TRANSMIT,
|
|
l_pchBuffer,
|
|
l_uBufferLength,
|
|
m_rgbReplyBuffer,
|
|
m_uReplyBufferSize,
|
|
&m_uReplyLength,
|
|
&m_Ovr
|
|
);
|
|
|
|
if (l_bResult == FALSE && GetLastError() == ERROR_IO_PENDING) {
|
|
|
|
// wait for result
|
|
SetLastError(0);
|
|
|
|
l_bResult = GetOverlappedResult(
|
|
m_hReader,
|
|
&m_Ovr,
|
|
&m_uReplyLength,
|
|
TRUE
|
|
);
|
|
}
|
|
|
|
if (m_fDump) {
|
|
|
|
printf(" IOCTL returned %lxh\n", GetLastError());
|
|
|
|
if (l_bResult) {
|
|
|
|
DumpData(
|
|
" ReplyData:",
|
|
3,
|
|
m_rgbReplyBuffer,
|
|
m_uReplyLength
|
|
);
|
|
}
|
|
printf("%*s", 53, "");
|
|
}
|
|
|
|
*out_pchReply = (PUCHAR) m_rgbReplyBuffer + m_ScardIoRequest.cbPciLength;
|
|
*out_puReplyLength = m_uReplyLength - m_ScardIoRequest.cbPciLength;
|
|
|
|
delete l_pchBuffer;
|
|
return GetLastError();
|
|
}
|
|
|
|
LONG
|
|
CReader::VendorIoctl(
|
|
CString &o_Answer
|
|
)
|
|
{
|
|
BOOL l_bResult = DeviceIoControl(
|
|
m_hReader,
|
|
CTL_CODE(FILE_DEVICE_SMARTCARD, 2048, METHOD_BUFFERED, FILE_ANY_ACCESS),
|
|
NULL,
|
|
NULL,
|
|
m_rgbReplyBuffer,
|
|
sizeof(m_rgbReplyBuffer),
|
|
&m_uReplyLength,
|
|
&m_Ovr
|
|
);
|
|
|
|
|
|
if (l_bResult) {
|
|
|
|
m_rgbReplyBuffer[m_uReplyLength] = '\0';
|
|
o_Answer = CString(m_rgbReplyBuffer);
|
|
}
|
|
|
|
return GetLastError();
|
|
}
|
|
|
|
LONG
|
|
CReader::WaitForCard(
|
|
const ULONG in_uWaitFor
|
|
)
|
|
{
|
|
BOOL l_bResult;
|
|
ULONG l_uReplyLength;
|
|
|
|
SetLastError(0);
|
|
|
|
l_bResult = DeviceIoControl (
|
|
m_hReader,
|
|
in_uWaitFor,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
&l_uReplyLength,
|
|
&m_Ovr
|
|
);
|
|
|
|
if (l_bResult == FALSE && GetLastError() == ERROR_IO_PENDING) {
|
|
|
|
SetLastError(0);
|
|
|
|
l_bResult = GetOverlappedResult(
|
|
m_hReader,
|
|
&m_Ovr,
|
|
&l_uReplyLength,
|
|
TRUE
|
|
);
|
|
}
|
|
return GetLastError();
|
|
}
|
|
|
|
LONG
|
|
CReader::StartWaitForCard(
|
|
const ULONG in_uWaitFor
|
|
)
|
|
{
|
|
BOOL l_bResult;
|
|
ULONG l_uReplyLength;
|
|
|
|
ResetEvent(m_OvrWait.hEvent);
|
|
|
|
l_bResult = DeviceIoControl (
|
|
m_hReader,
|
|
in_uWaitFor,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
&l_uReplyLength,
|
|
&m_OvrWait
|
|
);
|
|
|
|
return GetLastError();
|
|
}
|
|
|
|
LONG
|
|
CReader::FinishWaitForCard(
|
|
const BOOL in_bWait
|
|
)
|
|
{
|
|
BOOL l_bResult;
|
|
ULONG l_uReplyLength;
|
|
|
|
SetLastError(0);
|
|
|
|
l_bResult = GetOverlappedResult(
|
|
m_hReader,
|
|
&m_OvrWait,
|
|
&l_uReplyLength,
|
|
in_bWait
|
|
);
|
|
|
|
return GetLastError();
|
|
}
|