最近做一個讀市民卡的項目,讀卡器公司提供的讀市民卡dll是用C++寫的。
下面記錄一些自己的心得,供需要的朋友參考。
聲明dll函數要加上stdcall關鍵字,否則可能會報地址非法的錯誤。
代碼:
unit cMain; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, DB, ADODB, StdCtrls, ComCtrls,ActiveX, ExtCtrls; type TForm1 = class(TForm) btnReadICard: TButton; Memo1: TMemo; procedure btnReadICardClick(Sender: TObject); private { Private declarations } public { Public declarations } end; //2014-12-11 type PICC_CONFIG=^ICC_CONFIG; ICC_CONFIG=record port:Integer; baud:Integer; timeout:Integer; PSAMSlot:Integer; ICCSlot:Integer; end; // ICC_CONFIG=record // port:Cardinal; // baud:Cardinal; // timeout:Cardinal; // PSAMSlot:longword; // ICCSlot:longword; // end; //2014-12-11 function SIReaderInit(icc_Config0:PICC_CONFIG; hDevReader:PHandle):Integer;stdcall;external 'SI_ICCReader.dll'; //功能:初始化讀卡器設備 //參數:icc_Config0 -- 讀卡器參數指針 ICC_CONFIG指針為NULL,則采用默認參數初始化,ICC_CONFIG具體定義參考結構定義 // hDevReader 返回讀卡器操作句柄 //返回:=0:正常完成初始化 <>0:初始化出錯,調用SIGetErrMessage獲取具體的錯誤信息 function SISelectIFD (hDevReader: THandle; IFDType: Integer):Integer;stdcall;external 'SI_ICCReader.dll'; //功能:選擇CPU卡(包括社會保障卡/PSAM卡) //參數:hDevReader -- 通過SIReaderInit函數獲得的讀卡器句柄 // IFDType -- CPU卡類型,參照標准IC卡類型代碼表(0x0c:社保卡槽;0x0d:附卡座PSAM卡槽;0x0E為第一個SAM1卡座,0x0F為第二個SAM2卡座) //返回: =0:表示操作成功 <>0:表示操作失敗,調用SIGetErrMessage獲取具體的錯誤信息 function GetReaderStatus(hDevReader: THandle;status: PChar):Integer;stdcall;external 'SI_ICCReader.dll'; //功能:獲取讀卡器狀態 給卡片進行上電 //參數:hDevReader -- 通過SIReaderInit函數獲得的讀卡器句柄 // status: '2' 讀卡器已連接並已插入社會保障卡 //返回:=0:表示操作成功 <>0:表示操作失敗,調用SIGetErrMessage獲取具體的錯誤信息 function SIReadInfo(hDevReader: THandle;const sDF:PChar; const sEF:PChar; const cRecNo: Byte; sBuffer:PChar):Integer;stdcall;external 'SI_ICCReader.dll'; //功能:讀取社保卡記錄文件信息 //參數:hDevReader -- 通過SIReaderInit函數獲得的讀卡器句柄 // sDF:[IN] :對應目錄名稱如"DF01","3F00"(MF)。 // sEF:[IN] :對應文件名稱如"EF01","EF0C"。 // cRecNo:[IN] :對應文件記錄號(不是記錄標識),如果為0,則表示讀取該文件內所有記錄,如果為01-n,則表示讀取該文件內某一條記錄。 // sBuffer[OUT] :返回讀取數據,需要預先分配對應文件內的長度,長度為∑(每個記錄字節數) + 1 //返回:=0:表示操作成功 <>0:表示操作失敗,調用SIGetErrMessage獲取具體的錯誤信息 procedure SIGetErrMessage(nErrNo:Integer;sErrMessage:PChar);stdcall;external 'SI_ICCReader.dll'; //功能:根據錯誤代碼獲取詳細錯誤信息 //參數: NErrNo[IN]:錯誤代碼,見附錄錯誤代碼命名方式。 // SErrMessage[OUT]:錯誤代碼所對應的錯誤信息,已預先分配201個字節長度 var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.btnReadICardClick(Sender: TObject); var nRet:Integer; sBuffer: array[0..200] of Char; sData: array[0..10] of Char; sStatus: array[0..10] of Char; sErrMsg: array[0..50] of Char; icc_Config0:ICC_CONFIG; g_Handle: THandle; begin //端口信息 icc_Config0.port := 100; icc_Config0.baud := 9600; icc_Config0.ICCSlot := 0; icc_Config0.PSAMSlot := 0; icc_Config0.timeout := 0; Memo1.Lines.Clear; nRet := SIReaderInit(@icc_Config0,@g_Handle); if nRet <> 0 then begin // ZeroMemory(@sErrMsg,SizeOf(sErrMsg)); // SIGetErrMessage(nRet, sErrMsg); Memo1.Lines.Add('讀卡器初始化失敗!,錯誤代碼:') ; end else begin Memo1.Lines.Add('讀卡器初始化成功' ); end; //切換卡槽號 nRet := SISelectIFD(g_Handle, $0C); if nRet <> 0 then begin Memo1.Lines.Add('選擇社保卡槽失敗!') ; end else begin Memo1.Lines.Add('選擇社保卡槽成功!'); end; // 獲取讀卡器狀態 給卡片進行上電 FillChar(sStatus,SizeOf(sStatus),#0);//用0填充sStatus nRet := GetReaderStatus(g_Handle, @sStatus[0]); if (nRet = 0)and(sStatus = '2') then begin //附錄1:溫州市社會保障卡結構 FillChar(sBuffer,SizeOf(sBuffer),#0);//用0填充緩沖區sBuffer nRet := SIReadInfo(g_Handle, '3F00','EF05', 1, sBuffer); Memo1.Lines.Add('卡的識別碼:' + sBuffer); FillChar(sBuffer,SizeOf(sBuffer),#0);//用0填充緩沖區sBuffer nRet := SIReadInfo(g_Handle, '3F00','EF05',2, sBuffer); Memo1.Lines.Add('卡的類別:' + sBuffer); FillChar(sBuffer,SizeOf(sBuffer),#0);//用0填充緩沖區sBuffer nRet := SIReadInfo(g_Handle, '3F00','EF05', 3, sBuffer); Memo1.Lines.Add('規范版本:' + sBuffer); FillChar(sBuffer,SizeOf(sBuffer),#0);//用0填充緩沖區sBuffer nRet := SIReadInfo (g_Handle, '3F00','EF05', 4, sBuffer); Memo1.Lines.Add('初始化機構編號:' + sBuffer); FillChar(sBuffer,SizeOf(sBuffer),#0);//用0填充緩沖區sBuffer nRet := SIReadInfo(g_Handle, '3F00','EF05', 5, sBuffer); Memo1.Lines.Add('發卡日期:' + sBuffer); FillChar(sBuffer,SizeOf(sBuffer),#0);//用0填充緩沖區sBuffer nRet := SIReadInfo(g_Handle, '3F00','EF05', 6, sBuffer); Memo1.Lines.Add('卡有效期:' + sBuffer); FillChar(sBuffer,SizeOf(sBuffer),#0);//用0填充緩沖區sBuffer nRet := SIReadInfo(g_Handle, '3F00','EF05', 7, sBuffer); Memo1.Lines.Add('卡號:' + sBuffer); FillChar(sBuffer,SizeOf(sBuffer),#0);//用0填充緩沖區sBuffer nRet := SIReadInfo(g_Handle, '3F00','EF06', 1, sBuffer); Memo1.Lines.Add('公民身份證號碼:' + sBuffer); FillChar(sBuffer,SizeOf(sBuffer),#0);//用0填充緩沖區sBuffer nRet := SIReadInfo(g_Handle, '3F00','EF06',2, sBuffer); Memo1.Lines.Add('姓名:' + sBuffer); FillChar(sBuffer,SizeOf(sBuffer),#0);//用0填充緩沖區sBuffer nRet := SIReadInfo(g_Handle, '3F00','EF06', 3, sBuffer); Memo1.Lines.Add('性別:' + sBuffer); FillChar(sBuffer,SizeOf(sBuffer),#0);//用0填充緩沖區sBuffer nRet := SIReadInfo (g_Handle, '3F00','EF06', 4, sBuffer); Memo1.Lines.Add('民族:' + sBuffer); FillChar(sBuffer,SizeOf(sBuffer),#0);//用0填充緩沖區sBuffer nRet := SIReadInfo(g_Handle, '3F00','EF06', 5, sBuffer); Memo1.Lines.Add('出生地:' + sBuffer); FillChar(sBuffer,SizeOf(sBuffer),#0);//用0填充緩沖區sBuffer nRet := SIReadInfo(g_Handle, '3F00','EF06', 6, sBuffer); Memo1.Lines.Add('出生日期:' + sBuffer); end; end; end.