最近用到了PC/SC編程,這篇文章寫的非常好浊服。
另:自己編寫的用實物測試過的程序源碼:http://download.csdn.net/detail/jixuxiangqianzou/5633553
VC中PC/SC智能卡接口的編程
[摘要]本文介紹了如何在VC中通過PC/SC接口實現(xiàn)對智能卡讀寫器的操作角虫,并給出了詳細(xì)的例子代碼。
[關(guān)鍵詞] 智能卡、PC/SC茬故、智能卡讀寫器
1 引言
完整的智能卡應(yīng)用系統(tǒng)由后臺服務(wù)程序、主機(jī)或終端應(yīng)用程序和智能卡等組成蚁鳖,如圖1所示磺芭。其中,后臺服務(wù)程序提供了支持智能卡的服務(wù)醉箕。例如钾腺,在一個電子付款系統(tǒng)中,后臺服務(wù)程序可以提供到信用卡和帳戶信息的訪問讥裤;主機(jī)或終端應(yīng)用程序一般存在于臺式機(jī)或者終端放棒、電子付款終端、手機(jī)或者一個安全子系統(tǒng)中坞琴,終端應(yīng)用程序要處理用戶哨查、智能卡和后臺服務(wù)程序之間的通訊;智能卡則存儲用戶的一些信息剧辐。
終端應(yīng)用程序需要通過讀卡器來訪問智能卡寒亥,在一個系統(tǒng)中邮府,通常存在多家廠商提供的讀卡器,因此需要一個統(tǒng)一的讀卡器設(shè)備驅(qū)動接口溉奕。
隨著智能卡的廣泛應(yīng)用褂傀,為解決計算機(jī)與各種讀卡器之間的互操作性問題,人們提出了PC/SC(Personal Computer/Smart Card)規(guī)范加勤,PC/SC規(guī)范作為讀卡器和卡與計算機(jī)之間有一個標(biāo)準(zhǔn)接口仙辟,實現(xiàn)不同生產(chǎn)商的卡和讀卡器之間的互操作性,其獨立于設(shè)備的 API使得應(yīng)用程序開發(fā)人員不必考慮當(dāng)前實現(xiàn)形式和將來實現(xiàn)形式之間的差異鳄梅,并避免了由于基本硬件改變而引起的應(yīng)用程序變更叠国,從而降低了軟件開發(fā)成本。
Microsoft在其Platform SDK中實現(xiàn)了PC/SC戴尸,作為連接智能卡讀卡器與計算機(jī)的一個標(biāo)準(zhǔn)模型粟焊,提供了獨立于設(shè)備的 API,并與Windows平臺集成孙蒙。因此项棠,我們可以用PC/SC接口來訪問智能卡。
2 PC/SC概述
PC/SC接口包含30多個以Scard為前綴的函數(shù)挎峦,所有函數(shù)的原型都在winscard.h中聲明香追,應(yīng)用程序需要包含winscard.lib,所有函數(shù)的正常返回值都是SCARD_S_SUCCESS坦胶。在這30多個函數(shù)中透典,常用的函數(shù)只有幾個,與智能卡的訪問流程(圖2)對應(yīng)迁央,下面將詳細(xì)介紹這些常用函數(shù)掷匠。
3 PC/SC的使用
3.1建立資源管理器的上下文
函數(shù)ScardEstablishContext()用于建立將在其中進(jìn)行設(shè)備數(shù)據(jù)庫操作的資源管理器上下文(范圍)。
函數(shù)原型:
LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1, LPCVOID pvReserved2, LPSCARDCONTEXT phContext);
各個參數(shù)的含義:(1)dwScope:輸入類型岖圈;表示資源管理器上下文范圍,取值為:SCARD_SCOPE_USER(在用戶域中完成設(shè)備數(shù)據(jù)庫操作)钙皮、SCARD_SCOPE_SYSTEM(在系統(tǒng)域中完成設(shè)備數(shù)據(jù)庫操作)蜂科。要求應(yīng)用程序具有相應(yīng)的操作權(quán)限。(2)pvReserved1:輸入類型短条;保留导匣,必須為NULL。(3)pvReserved2:輸入類型茸时;保留贡定,必須為NULL。(4)phContext:輸出類型可都;建立的資源管理器上下文的句柄缓待。
下面是建立資源管理器上下文的代碼:
SCARDCONTEXT hSC;
LONG lReturn;
lReturn = SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &hSC);
if ( lReturn!=SCARD_S_SUCCESS )
printf("Failed SCardEstablishContext\n");
3.2 獲得系統(tǒng)中安裝的讀卡器列表
函數(shù)ScardListReaders()可以列出系統(tǒng)中安裝的讀卡器的名字蚓耽。
函數(shù)原型:
LONG SCardListReaders(SCARDCONTEXT hContext, LPCTSTR mszGroups, LPTSTR mszReaders, LPDWORD pcchReaders);
各個參數(shù)的含義:(1)hContext:輸入類型;ScardEstablishContext()建立的資源管理器上下文的句柄旋炒,不能為NULL步悠。(2)mszGroups:輸入類型;讀卡器組名瘫镇,為NULL時鼎兽,表示列出所有讀卡器。(3)mszReaders:輸出類型铣除;系統(tǒng)中安裝的讀卡器的名字谚咬,各個名字之間用’\0’分隔,最后一個名字后面為兩個連續(xù)的’\0’尚粘。(4)pcchReaders:輸入輸出類型择卦;mszReaders的長度。
系統(tǒng)中可能安裝多個讀卡器背苦,因此互捌,需要保存各個讀卡器的名字,以便以后與需要的讀卡器建立連接行剂。
下面是獲得系統(tǒng)中安裝的讀卡器列表的代碼:
char mszReaders[1024];
LPTSTR pReader, pReaderName[2];
DWORD dwLen=sizeof(mzsReaders);
int nReaders=0;
lReturn = SCardListReaders(hSC, NULL, (LPTSTR)mszReaders, &dwLen);
if ( lReturn==SCARD_S_SUCCESS )
{
pReader = (LPTSTR)pmszReaders;
while (*pReader !='\0' )
{
if ( nReaders<2 ) //使用系統(tǒng)中前2個讀卡器
pReaderName[nReaders++]=pReader;
printf("Reader: %S\n", pReader );
//下一個讀卡器名
pReader = pReader + strlen(pReader) + 1;
}
}
3.3 與讀卡器(智能卡)連接
函數(shù)ScardConnect()在應(yīng)用程序與讀卡器上的智能卡之間建立一個連接秕噪。
函數(shù)原型:
LONG SCardConnect(SCARDCONTEXT hContext, LPCTSTR szReader, DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard, LPDWORD pdwActiveProtocol);
各個參數(shù)的含義:(1)hContext:輸入類型;ScardEstablishContext()建立的資源管理器上下文的句柄厚宰。(2)szReader:輸入類型腌巾;包含智能卡的讀卡器名稱(讀卡器名稱由ScardListReaders()給出)。(3)dwShareMode:輸入類型铲觉;應(yīng)用程序?qū)χ悄芸ǖ牟僮鞣绞匠候琒CARD_SHARE_SHARED(多個應(yīng)用共享同一個智能卡)、SCARD_SHARE_EXCLUSIVE(應(yīng)用獨占智能卡)撵幽、SCARD_SHARE_DIRECT(應(yīng)用將智能卡作為私有用途灯荧,直接操縱智能卡,不允許其它應(yīng)用訪問智能卡)盐杂。(4)dwPreferredProtocols:輸入類型逗载;連接使用的協(xié)議,SCARD_PROTOCOL_T0(使用T=0協(xié)議)链烈、SCARD_PROTOCOL_T1(使用T=1協(xié)議)厉斟。(5)phCard:輸出類型;與智能卡連接的句柄强衡。(6)PdwActiveProtocol:輸出類型擦秽;實際使用的協(xié)議。
下面是與智能卡建立連接的代碼:
SCARDHANDLE hCardHandle[2];
DWORD dwAP;
lReturn = SCardConnect( hContext, pReaderName[0], SCARD_SHARE_SHARED,
SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCardHandle[0], &dwAP );
if ( lReturn!=SCARD_S_SUCCESS )
{
printf("Failed SCardConnect\n");
exit(1);
}
與智能卡建立連接后,就可以向智能卡發(fā)送指令感挥,與其交換數(shù)據(jù)了缩搅。