www.pudn.com > agsm2-1.2_src.zip > PcScCtrl.cpp


// PcScCtrl.cpp: implementation of the CPcScCtrl class. 
// 
////////////////////////////////////////////////////////////////////// 
 
#include "stdafx.h" 
#include "agsm2.h" 
#include "PcScCtrl.h" 
#include "Helper.h" 
 
#ifdef _DEBUG 
#undef THIS_FILE 
static char THIS_FILE[]=__FILE__; 
#define new DEBUG_NEW 
#endif 
 
ISO7816_CMD SimCmd = 
{ 
	0xA0,	//GSM SIM CLASS 
	0xa4,	//Select 
	0xf2,	//Status 
	0xb0,	//Read Binary 
	0xd6,	//UpdateBinary; 
	0xb2,	//ReadRecord; 
	0xdc,	//UpdateRecord; 
	0xa2,	//Seek; 
	0x32,	//Increase; 
	0x20,	//VerifyChv; 
	0x24,	//ChangeChv; 
	0x26,	//DisableChv; 
	0x28,	//EnableChv; 
	0x2c,	//UnblockChv; 
	0x04,	//Invalidate; 
	0x44,	//Rehabilitate; 
	0x88,	//RunGsmAlgorithm; 
	0xfa,	//Sleep; 
	0xc0,	//GetResponse; 
}; 
 
 
////////////////////////////////////////////////////////////////////// 
// Construction/Destruction 
////////////////////////////////////////////////////////////////////// 
CPcScCtrl::CPcScCtrl() 
{ 
	m_bGetRes = TRUE; 
	m_nCurReader = 0; 
	hCard = NULL; 
	hContext = NULL; 
	LONG lResult = EstablishContext(); 
	if(lResult != SCARD_S_SUCCESS) 
			Helper::ShowLastError(lResult); 
 
} 
 
CPcScCtrl::~CPcScCtrl() 
{ 
	LONG lReturn; 
	if(hCard) 
	{ 
		lReturn = SCardDisconnect(hCard, SCARD_LEAVE_CARD); 
		ASSERT(lReturn == SCARD_S_SUCCESS); 
	} 
 
	if (hContext != NULL) 
	{ 
		lReturn = SCardReleaseContext(hContext); 
		ASSERT(lReturn == SCARD_S_SUCCESS); 
	} 
 
} 
 
LONG CPcScCtrl::ListReaders() 
{ 
    LONG	lResult; 
	LPTSTR	lpmszReaderNames; 
	LONG	nReaders = 0;	 
 
	m_asReaderNames.RemoveAll(); 
	 
	EstablishContext(); 
	if(hContext == NULL) 
		return nReaders; 
    //__try 
    { 
        // 
        // Get the list of registered readers associated with the specified 
        // group(s). 
        // Note: The buffer is automatically allocated and must be freed 
        //       by SCFree(). 
        // 
        lResult = SCListReaders(hContext, 
                                NULL, 
                                (LPTSTR *) &lpmszReaderNames); 
		//Helper::ShowLastError(lResult); 
        if (lResult != SCARD_S_SUCCESS) 
        { 
            //__leave; 
        }else{ 
			DWORD  dwNumReaders   = 0; 
			LPTSTR lpszReaderName = lpmszReaderNames; 
 
			TRACE(_T("\n")); 
			TRACE(_T("Registered Reader(s)\n")); 
			TRACE(_T("====================\n")); 
 
			// 
			// Walk through the list of readers and print out some information. 
			// Note: The list of readers are in a multi-string structure. 
			// 
			while (*lpszReaderName != _T('\0')) 
			{ 
				++dwNumReaders; 
				TRACE(_T("%02d: %s\n"), dwNumReaders, lpszReaderName); 
				CString ts(lpszReaderName);  
				m_asReaderNames.Add(ts); 
				lpszReaderName += lstrlen(lpszReaderName) + 1; 
				nReaders++; 
			} 
 
			// 
			// Inform the user if no reader was found. 
			// 
			if (dwNumReaders == 0) 
			{ 
				TRACE(_T("No registered reader was found")); 
				AfxMessageBox(_T("No registered reader was found")); 
			} 
		} 
    } 
	// Don't forget to release memory, if allocated. 
	// 
	if (lpmszReaderNames != NULL) 
		SCFree((LPVOID) lpmszReaderNames); 
	return nReaders; 
} 
 
LONG CPcScCtrl::DoAPDU(LPBYTE cmdAPDU, DWORD len, LPBYTE resAPDU,DWORD &reslen) 
{ 
    LONG lResult; 
	 
	if(hCard == NULL) 
	{ 
		lResult = SCARD_E_NO_SMARTCARD; 
		throw lResult; 
	} 
 
    // 
    // Send APDU to card 
    // 
    lResult = SCardTransmit(hCard, 
                            SCARD_PCI_T0, 
                            cmdAPDU, 
                            len, 
                            NULL, 
                            resAPDU, 
                            &reslen); 
    // 
    // If API successful but card operation failed, then 
    // return SW1 and SW2 as error code 
    // 
    if (lResult == SCARD_S_SUCCESS) 
    { 
		// 
		// Sanity check 
		// 
		if(len == 5)//Must be Read 
		{ 
			ASSERT(reslen >= 2); 
		}else{ 
			//ASSERT(reslen == 2); 
		} 
 
		if(reslen == 2) 
		{ 
			if ( m_bGetRes && 
				 (resAPDU[0] == 0x61 || resAPDU[0] == 0x9f) 
			   ) 
			{ 
				BYTE len = resAPDU[1]; 
				DWORD dwStatusLen = len + 2; 
				//BYTE apdu[5] = {0xa0, 0xc0, 0x00, 0x00, len}; 
				CMDAPDU cmdApdu; 
				cmdApdu.klass = SimCmd.Klass; 
				cmdApdu.inc = SimCmd.GetResponse; 
				cmdApdu.p1 = 0; 
				cmdApdu.p2 = 0; 
				cmdApdu.p3 = len; 
 
				// 
				// Send APDU to card. 
				// 
				lResult = SCardTransmit(hCard, 
                            SCARD_PCI_T0, 
                            (LPBYTE)&cmdApdu, 
                            5, 
                            NULL, 
                            resAPDU, 
                            &dwStatusLen); 
				if (lResult == SCARD_S_SUCCESS) 
				{ 
					reslen = dwStatusLen; 
					TRACE(_T("%d response bytes available\n"),reslen); 
				} 
			} 
		} 
		#ifdef _DEBUG 
		if (reslen>=2) 
		{ 
			BYTE errseq[2]; 
			errseq[0] = resAPDU[reslen-2]; 
			errseq[1] = resAPDU[reslen-1]; 
			TRACE("%s\n",FormatErrMsg(errseq)); 
		} 
		#endif 
		if(reslen >= 2) 
		{ 
			UCHAR SW1 = resAPDU[reslen-2]; 
			LONG lRet = MAKELONG(MAKEWORD(resAPDU[reslen-1],SW1), 0x0000); 
			if(SW1 != 0x90 && SW1 != 0x9f && SW1 != 0x61) 
				throw lRet; 
			else 
				return lRet; 
		} 
    } 
	throw lResult; 
	return lResult; 
} 
 
LPVOID CPcScCtrl::SCMalloc(DWORD dwSize) 
{ 
	return(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize)); 
} 
 
LONG CPcScCtrl::SCFree(LPVOID lpMemory) 
{ 
    LONG lResult; 
 
    // 
    // Parameters sanity check. 
    // 
    ASSERT(lpMemory != NULL); 
 
    if (HeapFree(GetProcessHeap(), 0, lpMemory)) 
    { 
        lResult = SCARD_S_SUCCESS; 
    } 
    else 
    { 
        lResult = GetLastError(); 
    } 
 
    return lResult; 
 
} 
 
LONG CPcScCtrl::SCListReaders(SCARDCONTEXT hContext, LPCTSTR lpmszReaderGroups, LPTSTR *lplpmszReaderNames) 
{ 
    LONG  lResult; 
    DWORD dwReaders; 
 
    // 
    // Parameters sanity check. 
    // 
    ASSERT(lplpmszReaderNames != NULL); 
 
    // 
    // Initialize returned info. 
    // 
    * lplpmszReaderNames = NULL; 
 
    // 
    // First find the required buffer length. 
    // 
    lResult = SCardListReaders(hContext, 
                               lpmszReaderGroups, 
                               NULL,         // NULL to indicate we want to 
                               &dwReaders);  // know the length of the buffer 
    if (lResult != SCARD_S_SUCCESS) 
    { 
        return lResult; 
    } 
 
    // 
    // Allocate memory. 
    // 
    LPTSTR lpmszReaderNames = (LPTSTR) SCMalloc(dwReaders * sizeof(_TCHAR)); 
 
    if (lpmszReaderNames == NULL) 
    { 
        return ERROR_OUTOFMEMORY; 
    } 
 
    // 
    // Now actually get the list of reader names. 
    // 
    lResult = SCardListReaders(hContext, 
                               lpmszReaderGroups, 
                               lpmszReaderNames, 
                               &dwReaders); 
    if (lResult == SCARD_S_SUCCESS) 
    { 
        // 
        // Successful, so return pointer to reader names. 
        // 
        *lplpmszReaderNames = lpmszReaderNames; 
    } 
    else 
    { 
        // 
        // Error occurred, so free memory. 
        // 
        SCFree((LPVOID) lpmszReaderNames); 
    } 
 
    return lResult; 
 
} 
 
DWORD CPcScCtrl::TrackingCard(DWORD dwCurrentState) 
{ 
	LONG lResult; 
 
	EstablishContext(); 
	if(m_asReaderNames.GetSize() == 0 || hContext == NULL) 
		return SCARD_STATE_UNKNOWN; 
 
	SCARD_READERSTATE rsReaders; 
	ZeroMemory((LPVOID)&rsReaders, sizeof(rsReaders)); 
 
	rsReaders.szReader = (LPCTSTR)m_asReaderNames[m_nCurReader]; 
	rsReaders.dwCurrentState = dwCurrentState; 
	// 
	// Now check state of the current reader 
	// 
	lResult = SCardGetStatusChange(hContext, 
                                       INFINITE, 
                                       &rsReaders, 
                                       1); 
	if (lResult != SCARD_S_SUCCESS) 
		return SCARD_STATE_UNKNOWN; 
 
	return rsReaders.dwEventState; 
} 
 
LONG CPcScCtrl::SetCurReader(INT n) 
{ 
	if (m_asReaderNames.GetSize() == 0 || m_asReaderNames.GetSize() < n) 
		return -1; 
	m_nCurReader = n; 
	if(hCard) 
	{ 
			LONG lResult = SCardEndTransaction( 
											hCard,   
											SCARD_LEAVE_CARD  
											); 
//			if(lResult != SCARD_S_SUCCESS) 
//			{ 
//				Helper::ShowLastError(lResult); 
//				return lResult; 
//			} 
 
			lResult = SCardDisconnect(hCard, SCARD_LEAVE_CARD); 
			if(lResult != SCARD_S_SUCCESS) 
			{ 
				Helper::ShowLastError(lResult); 
				return lResult; 
			} 
			hCard = NULL; 
	} 
	DWORD dwActiveProtocol; 
	// 
	// Connect to the card 
	// 
	LONG lResult = SCardConnect(hContext, 
							m_asReaderNames[m_nCurReader], 
							SCARD_SHARE_SHARED, 
							SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, 
							&hCard, 
							&dwActiveProtocol); 
	//if(lResult != SCARD_S_SUCCESS) 
	//	Helper::ShowLastError(lResult); 
	if(lResult == SCARD_S_SUCCESS) 
		lResult = SCardBeginTransaction(hCard); 
 
	return lResult; 
} 
 
INT CPcScCtrl::GetCurReader() 
{ 
	return m_nCurReader; 
} 
 
 
void CPcScCtrl::SetCLA(UCHAR cla) 
{ 
	SimCmd.Klass = 	cla; 
} 
 
LONG CPcScCtrl::Select(UCHAR id[],RESAPDU &resApdu, UCHAR P1, UCHAR P2 ) 
{ 
	CMDAPDU cmdApdu; 
	cmdApdu.klass = SimCmd.Klass; 
	cmdApdu.inc = SimCmd.Select; 
	cmdApdu.p1 = P1; 
	cmdApdu.p2 = P2; 
	cmdApdu.p3 = 2; 
	cmdApdu.data[0] = id[0]; 
	cmdApdu.data[1] = id[1]; 
	return DoAPDU((LPBYTE)&cmdApdu,5+2,resApdu.data,resApdu.len); 
} 
 
LONG CPcScCtrl::Select(ULONG id, RESAPDU &resApdu, UCHAR P1, UCHAR P2) 
{ 
	UCHAR aid[2]; 
	aid[0] = (UCHAR)((id >> 8) & 0xff); 
	aid[1] = (UCHAR)(id & 0xff); 
	return Select(aid,resApdu,P1,P2); 
} 
 
LONG CPcScCtrl::Status(RESAPDU &resApdu) 
{ 
	CMDAPDU cmdApdu; 
	cmdApdu.klass = SimCmd.Klass; 
	cmdApdu.inc = SimCmd.Status; 
	cmdApdu.p1 = 0; 
	cmdApdu.p2 = 0; 
	cmdApdu.p3 = (BYTE)(resApdu.len-2); 
	return DoAPDU((LPBYTE)&cmdApdu,5,resApdu.data,resApdu.len); 
} 
 
LONG CPcScCtrl::ReadBinary(UCHAR OffHi, UCHAR OffLo, RESAPDU &resApdu) 
{ 
	CMDAPDU cmdApdu; 
	cmdApdu.klass = SimCmd.Klass; 
	cmdApdu.inc = SimCmd.ReadBinary; 
	cmdApdu.p1 = OffHi; 
	cmdApdu.p2 = OffLo; 
	cmdApdu.p3 = (BYTE)(resApdu.len-2); 
	return DoAPDU((LPBYTE)&cmdApdu,5,resApdu.data,resApdu.len); 
} 
 
LONG CPcScCtrl::UpdateBinary(UCHAR OffHi, UCHAR OffLo, LPBYTE data, UCHAR len) 
{ 
	CMDAPDU cmdApdu; 
	cmdApdu.klass = SimCmd.Klass; 
	cmdApdu.inc = SimCmd.UpdateBinary; 
	cmdApdu.p1 = OffHi; 
	cmdApdu.p2 = OffLo; 
	cmdApdu.p3 = len; 
	memcpy(cmdApdu.data,data,len); 
	BYTE sw[2]; 
	RESAPDU resApdu; 
	resApdu.data = sw; 
	resApdu.len = 2; 
	return DoAPDU((LPBYTE)&cmdApdu,5+len,resApdu.data,resApdu.len); 
 
} 
 
LONG CPcScCtrl::ReadRecord(UCHAR RecNo, UCHAR mode, RESAPDU &resApdu) 
{ 
	CMDAPDU cmdApdu; 
	cmdApdu.klass = SimCmd.Klass; 
	cmdApdu.inc = SimCmd.ReadRecord; 
	cmdApdu.p1 = RecNo; 
	cmdApdu.p2 = mode; 
	cmdApdu.p3 = (BYTE)(resApdu.len-2); 
	return DoAPDU((LPBYTE)&cmdApdu,5,resApdu.data,resApdu.len); 
} 
 
LONG CPcScCtrl::UpdateRecord(UCHAR RecNo, UCHAR mode, LPBYTE Rec, UCHAR len) 
{ 
	CMDAPDU cmdApdu; 
	cmdApdu.klass = SimCmd.Klass; 
	cmdApdu.inc = SimCmd.UpdateRecord; 
	cmdApdu.p1 = RecNo; 
	cmdApdu.p2 = mode; 
	cmdApdu.p3 = len; 
	memcpy(cmdApdu.data,Rec,len); 
	BYTE sw[2]; 
	RESAPDU resApdu; 
	resApdu.data = sw; 
	resApdu.len = 2; 
	return DoAPDU((LPBYTE)&cmdApdu,5+len,resApdu.data,resApdu.len); 
} 
 
LONG CPcScCtrl::Seek(UCHAR mode, LPBYTE patten, UCHAR len,RESAPDU &resApdu) 
{ 
	CMDAPDU cmdApdu; 
	cmdApdu.klass = SimCmd.Klass; 
	cmdApdu.inc = SimCmd.Seek; 
	cmdApdu.p1 = 0; 
	cmdApdu.p2 = mode; 
	cmdApdu.p3 = len; 
	memcpy(cmdApdu.data,patten,len); 
	return DoAPDU((LPBYTE)&cmdApdu,5+len,resApdu.data,resApdu.len); 
} 
 
LONG CPcScCtrl::Increase(LPBYTE data, UCHAR len,RESAPDU &resApdu) 
{ 
	CMDAPDU cmdApdu; 
	cmdApdu.klass = SimCmd.Klass; 
	cmdApdu.inc = SimCmd.Increase; 
	cmdApdu.p1 = 0; 
	cmdApdu.p2 = 0; 
	cmdApdu.p3 = len; 
	memcpy(cmdApdu.data,data,len); 
	return DoAPDU((LPBYTE)&cmdApdu,5+len,resApdu.data,resApdu.len); 
 
} 
 
LONG CPcScCtrl::VerifyChv(UCHAR ChvNo, LPBYTE data, UCHAR len) 
{ 
	ASSERT(len == 8); 
	return DoChv(SimCmd.VerifyChv,ChvNo,data,len); 
} 
 
LONG CPcScCtrl::ChangeChv(UCHAR ChvNo, LPBYTE data, UCHAR len) 
{ 
	ASSERT(len == 16); 
	return DoChv(SimCmd.ChangeChv,ChvNo,data,len); 
} 
 
LONG CPcScCtrl::UnblockChv(UCHAR ChvNo, LPBYTE data, UCHAR len) 
{ 
	ASSERT(len == 16); 
	return DoChv(SimCmd.UnblockChv,ChvNo,data,len); 
} 
 
 
LONG CPcScCtrl::DisableChv(UCHAR ChvNo, LPBYTE data, UCHAR len) 
{ 
	ASSERT(len == 8); 
	return DoChv(SimCmd.DisableChv,ChvNo,data,len); 
 
} 
 
LONG CPcScCtrl::EnableChv(UCHAR ChvNo, LPBYTE data, UCHAR len) 
{ 
	ASSERT(len == 8); 
	return DoChv(SimCmd.EnableChv,ChvNo,data,len); 
 
} 
 
LONG CPcScCtrl::Invalidate() 
{ 
	CMDAPDU cmdApdu; 
	cmdApdu.klass = SimCmd.Klass; 
	cmdApdu.inc = SimCmd.Invalidate; 
	cmdApdu.p1 = 0; 
	cmdApdu.p2 = 0; 
	cmdApdu.p3 = 0; 
	 
	BYTE sw[2]; 
	RESAPDU resApdu; 
	resApdu.data = sw; 
	resApdu.len = 2; 
 
	return DoAPDU((LPBYTE)&cmdApdu,5,resApdu.data,resApdu.len); 
	 
} 
 
LONG CPcScCtrl::Rehabilitate() 
{ 
	CMDAPDU cmdApdu; 
	cmdApdu.klass = SimCmd.Klass; 
	cmdApdu.inc = SimCmd.Rehabilitate; 
	cmdApdu.p1 = 0; 
	cmdApdu.p2 = 0; 
	cmdApdu.p3 = 0; 
	 
	BYTE sw[2]; 
	RESAPDU resApdu; 
	resApdu.data = sw; 
	resApdu.len = 2; 
 
	return DoAPDU((LPBYTE)&cmdApdu,5,resApdu.data,resApdu.len); 
 
} 
 
LONG CPcScCtrl::RunGsmAlgorithm(LPBYTE rnd, UCHAR len,RESAPDU &resApdu) 
{ 
	ASSERT(len == 16); 
	CMDAPDU cmdApdu; 
	cmdApdu.klass = SimCmd.Klass; 
	cmdApdu.inc = SimCmd.RunGsmAlgorithm; 
	cmdApdu.p1 = 0; 
	cmdApdu.p2 = 0; 
	cmdApdu.p3 = 16; 
	memcpy(cmdApdu.data,rnd,len); 
 
	return DoAPDU((LPBYTE)&cmdApdu,5+len,resApdu.data,resApdu.len); 
} 
 
LONG CPcScCtrl::GetResponse(RESAPDU &resApdu) 
{ 
	CMDAPDU cmdApdu; 
	cmdApdu.klass = SimCmd.Klass; 
	cmdApdu.inc = SimCmd.GetResponse; 
	cmdApdu.p1 = 0; 
	cmdApdu.p2 = 0; 
	cmdApdu.p3 = (BYTE)(resApdu.len - 2); 
 
	return DoAPDU((LPBYTE)&cmdApdu,5,resApdu.data,resApdu.len); 
 
} 
 
 
LONG CPcScCtrl::DoChv(UCHAR cmd, UCHAR ChvNo, LPBYTE data, UCHAR len) 
{ 
	CMDAPDU cmdApdu; 
	cmdApdu.klass = SimCmd.Klass; 
	cmdApdu.inc = cmd; 
	cmdApdu.p1 = 0; 
	cmdApdu.p2 = ChvNo; 
	cmdApdu.p3 = len; 
	memcpy(cmdApdu.data,data,len); 
 
	BYTE sw[2]; 
	RESAPDU resApdu; 
	resApdu.data = sw; 
	resApdu.len = 2; 
 
	return DoAPDU((LPBYTE)&cmdApdu,5+len,resApdu.data,resApdu.len); 
 
} 
 
LONG CPcScCtrl::SCardControl(DWORD dwControlCode, LPCVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned) 
{ 
	ULONG lReturn = ::SCardControl( hCard, 
                        dwControlCode, 
                        lpInBuffer, 
                        nInBufferSize, 
                        lpOutBuffer, 
                        nOutBufferSize, 
                        lpBytesReturned ); 
	if ( SCARD_S_SUCCESS != lReturn ) 
		TRACE("Failed SCardControl\n"); 
	return lReturn; 
 
} 
 
LONG CPcScCtrl::SCardStatus(LPTSTR szReaderName, LPDWORD pcchReaderLen, LPDWORD pdwState, LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen) 
{ 
	ULONG lReturn = ::SCardStatus(hCard, 
                      szReaderName, 
                      pcchReaderLen, 
                      pdwState, 
                      pdwProtocol, 
                      pbAtr, 
                      pcbAtrLen);  
 
	if ( SCARD_S_SUCCESS != lReturn ) 
	{ 
		TRACE("Failed SCardStatus\n"); 
	} 
	return lReturn; 
 
} 
 
LONG CPcScCtrl::SCardGetAttrib(DWORD dwAttrId, LPBYTE pbAttr, LPDWORD pcbAttrLen) 
{ 
 
	LONG     lReturn; 
 
	// Retrieve an attribute. 
	// hCardHandle was set by a previous call to SCardConnect. 
	lReturn = ::SCardGetAttrib(hCard, 
							 dwAttrId, 
							 pbAttr, 
							 pcbAttrLen); 
	if ( SCARD_S_SUCCESS != lReturn ) 
	{ 
		TRACE("Failed SCardGetAttrib\n"); 
	} 
	return lReturn; 
 
} 
 
LONG CPcScCtrl::SCardSetAttrib(DWORD dwAttrId, LPCBYTE pbAttr, DWORD cbAttrLen) 
{ 
	LONG     lReturn; 
 
	// Retrieve an attribute. 
	// hCardHandle was set by a previous call to SCardConnect. 
	lReturn = ::SCardSetAttrib(hCard, 
							 dwAttrId, 
							 pbAttr, 
							 cbAttrLen); 
	if ( SCARD_S_SUCCESS != lReturn ) 
	{ 
		TRACE("Failed SCardSetAttrib\n"); 
	} 
	return lReturn; 
	 
} 
 
CString CPcScCtrl::GetCardState() 
{ 
 
	if(hCard == NULL || m_asReaderNames.GetSize() == 0) 
		return (LPCSTR)IDS_STRING_ABSENT; 
 
	TCHAR           szReader[200]; 
	DWORD           cch = 200; 
	BYTE            bAttr[32]; 
	DWORD           cByte = 32; 
	DWORD           dwState, dwProtocol; 
	LONG            lReturn; 
	// Determine the status. 
	// hCardHandle was set by an earlier call to SCardConnect. 
	lReturn = ::SCardStatus(hCard, 
						  szReader, 
						  &cch, 
						  &dwState, 
						  &dwProtocol, 
						  (LPBYTE)&bAttr, 
						  &cByte);  
 
	if ( SCARD_S_SUCCESS != lReturn ) 
	{ 
		Helper::ShowLastError(lReturn); 
		return (LPCSTR)IDS_STRING_ABSENT; 
	} 
 
	// Examine retrieved status elements. 
	// Here, we'll look at the reader name and card state. 
	switch ( dwState ) 
	{ 
		case SCARD_ABSENT: 
			return (LPCSTR)IDS_STRING_ABSENT; 
		case SCARD_PRESENT: 
			return (LPCSTR)IDS_STRING_PRESENT; 
		case SCARD_SWALLOWED: 
			return (LPCSTR)IDS_STRING_SWALLOWED; 
		case SCARD_POWERED: 
			return (LPCSTR)IDS_STRING_POWERD; 
		case SCARD_NEGOTIABLE: 
			return (LPCSTR)IDS_STRING_NEGOTIABLE; 
		case SCARD_SPECIFIC: 
			{ 
				CString str; 
				switch(dwProtocol) 
				{ 
					case SCARD_PROTOCOL_UNDEFINED: 
						str = (LPCSTR)IDS_STRING_UNDEFINED; 
						break; 
					case SCARD_PROTOCOL_T0: 
						str = _T("(T0)"); 
						break; 
					case SCARD_PROTOCOL_T1: 
						str = _T("(T1)"); 
						break; 
					case SCARD_PROTOCOL_RAW: 
						str = _T("(RAW)"); 
						break; 
				} 
				 return (LPCSTR)IDS_STRING_PROTOCOL+str; 
			} 
	} 
	return IDS_STRING_UNKNOWN; 
 
} 
 
CString CPcScCtrl::FormatErrMsg(LONG errcode) 
{ 
		BYTE errseq[2] = { ((errcode >> 8) & 0xff), (errcode & 0xff) }; 
		return FormatErrMsg(errseq); 
} 
 
CString CPcScCtrl::FormatErrMsg(BYTE errseq[]) 
{ 
		for(int j=0; j< sizeof(C_response)/sizeof(C_response[0]); j++) 
		{ 
			for(int i=sizeof(C_response[j].MASK)-1; i>=0; i--) 
				if (C_response[j].SW[i] != (C_response[j].MASK[i] & errseq[i])) 
					break; 
 
			if (i==-1) 
			{ 
				CString str; 
				CString strsw; 
				strsw.Format("(%02x%02x)",errseq[0],errseq[1]); 
				str.Format(C_response[j].text, (int)errseq[1]); 
				return str+strsw; 
			} 
		} 
		return _T("Unknow error."); 
} 
 
 
LONG CPcScCtrl::EstablishContext() 
{ 
	LONG lResult = SCARD_S_SUCCESS; 
	if(hContext == NULL) 
	{ 
		lResult = SCardEstablishContext(SCARD_SCOPE_USER, 
                                    NULL, 
                                    NULL, 
                                    &hContext); 
	} 
	 
	return lResult; 
} 
 
LONG CPcScCtrl::ConnectCurCard() 
{ 
	if (m_asReaderNames.GetSize() == 0 || m_asReaderNames.GetSize() < m_nCurReader) 
		return -1; 
	if(hCard == NULL) 
	{ 
		DWORD dwActiveProtocol; 
		// 
		// Connect to the card 
		// 
		LONG lResult = SCardConnect(hContext, 
								m_asReaderNames[m_nCurReader], 
								SCARD_SHARE_SHARED, 
								SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, 
								&hCard, 
								&dwActiveProtocol); 
		if(lResult != SCARD_S_SUCCESS) 
			Helper::ShowLastError(lResult); 
		return lResult; 
	} 
	return 0; 
} 
 
LONG CPcScCtrl::DisconnectCurCard() 
{ 
	LONG lResult; 
	if(hCard) 
	{ 
			lResult = SCardDisconnect(hCard, SCARD_LEAVE_CARD); 
			if(lResult != SCARD_S_SUCCESS) 
				Helper::ShowLastError(lResult); 
			hCard = NULL; 
	} 
	return lResult; 
}