diff --git a/FirstTest.dcu b/FirstTest.dcu new file mode 100644 index 0000000..843d5a9 Binary files /dev/null and b/FirstTest.dcu differ diff --git a/FirstTest.dfm b/FirstTest.dfm index 78630f2..1ba86c3 100644 --- a/FirstTest.dfm +++ b/FirstTest.dfm @@ -1,16 +1,15 @@ object Form1: TForm1 Left = 380 Top = 178 - Width = 356 - Height = 336 Caption = 'Form1' + ClientHeight = 553 + ClientWidth = 811 Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'MS Sans Serif' Font.Style = [] - OldCreateOrder = False PixelsPerInch = 96 TextHeight = 13 object Label1: TLabel @@ -140,7 +139,7 @@ object Form1: TForm1 end object bt_Close: TButton Left = 5 - Top = 65 + Top = 105 Width = 62 Height = 19 Caption = 'Close' @@ -158,7 +157,7 @@ object Form1: TForm1 end object bt_Send: TButton Left = 5 - Top = 105 + Top = 65 Width = 62 Height = 19 Caption = 'Send' @@ -166,12 +165,27 @@ object Form1: TForm1 OnClick = bt_SendClick end object Memo1: TMemo - Left = 75 - Top = 130 - Width = 271 - Height = 176 + Left = 8 + Top = 192 + Width = 793 + Height = 353 + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -13 + Font.Name = 'MS Sans Serif' + Font.Style = [fsBold] + ParentFont = False TabOrder = 6 end + object Button1: TButton + Left = 5 + Top = 155 + Width = 75 + Height = 25 + Caption = 'List' + TabOrder = 7 + OnClick = Button1Click + end object pcsc: TPCSCConnector OnCardInserted = pcscCardInserted OnCardActive = pcscCardActive @@ -180,7 +194,7 @@ object Form1: TForm1 OnReaderWaiting = pcscReaderWaiting OnReaderListChange = pcscReaderListChange OnError = pcscError - Left = 315 - Top = 5 + Left = 227 + Top = 13 end end diff --git a/FirstTest.pas b/FirstTest.pas index 3c41e41..76581fb 100644 --- a/FirstTest.pas +++ b/FirstTest.pas @@ -30,6 +30,7 @@ TForm1 = class(TForm) Memo1: TMemo; Label13: TLabel; Label14: TLabel; + Button1: TButton; procedure pcscCardRemoved(Sender: TObject); procedure pcscError(Sender: TObject; ErrSource: TErrSource; ErrCode: Cardinal); procedure ShowData; @@ -46,6 +47,7 @@ TForm1 = class(TForm) procedure pcscReaderDisconnect(Sender: TObject); procedure pcscReaderListChange(Sender: TObject); procedure pcscReaderWaiting(Sender: TObject); + procedure Button1Click(Sender: TObject); private { Private-Deklarationen } public @@ -63,6 +65,73 @@ implementation HexChars = '0123456789abcdefABCDEF'; +procedure ListSmartCardReaders(Memo: TMemo); +var + hContext: cardinal; + Readers: PChar; + ReaderList: TStringList; + ReaderListSize: integer; + Res: LongInt; + PtrReader: PChar; + qt:LongInt; +begin + Memo.Clear; // Limpa o memo antes de adicionar os leitores + Readers := nil; + ReaderListSize := 0; + ReaderList := TStringList.Create; + + try + // Estabelece o contexto para comunicação com o gerenciador de smartcard + Res := SCardEstablishContext(SCARD_SCOPE_USER, nil, nil, @hContext); + if Res <> SCARD_S_SUCCESS then + begin + Memo.Lines.Add('Erro ao estabelecer contexto: ' + IntToStr(Res)); + Exit; + end; + + // Obtém o tamanho necessário para armazenar os leitores + Res := SCardListReadersW(hContext, nil,nil, ReaderListSize); +// RetVar := SCardListReadersA(FContext, nil, nil, ReaderListSize); + if (Res <> SCARD_S_SUCCESS) or (ReaderListSize = 0) then + begin + Memo.Lines.Add('Nenhum leitor encontrado ou erro: ' + IntToStr(Res)); + Exit; + end; + + // Aloca espaço para armazenar a lista de leitores + GetMem(Readers, ReaderListSize); + + try + // Obtém a lista de leitores + Res := SCardListReadersW(hContext, nil, Pointer(Readers), ReaderListSize); +// SCardListReadersA(FContext, nil, Pointer(ReaderList), ReaderListSize); + if Res <> SCARD_S_SUCCESS then + begin + Memo.Lines.Add('Erro ao listar leitores: ' + IntToStr(Res)); + Exit; + end; + + // Adiciona os leitores à lista + PtrReader := Readers; + while PtrReader^ <> #0 do + begin + ReaderList.Add(PtrReader); + Inc(PtrReader, StrLen(PtrReader) + 1); + end; + + // Exibe os leitores no TMemo + Memo.Lines.AddStrings(ReaderList); + finally + FreeMem(Readers); + end; + + finally + // Libera o contexto + SCardReleaseContext(hContext); + ReaderList.Free; + end; +end; + function Hex2Bin(input: string): string; var hex, output: string; @@ -93,13 +162,24 @@ function Bin2HexExt(const input:string; const spaces, upcase: boolean): string; else result := AnsiLowerCase(hexresult); end; +function AnsiToWide(const AnsiStr: AnsiString; CodePage: Cardinal = CP_ACP ): WideString; +var + Len: Integer; + AnsiReader: AnsiString; +begin + Len := MultiByteToWideChar(CodePage, 0, PAnsiChar(AnsiStr), -1, nil, 0); + SetLength(Result, Len - 1); + MultiByteToWideChar(CodePage, 0, PAnsiChar(AnsiStr), -1, PWideChar(Result), Len); +end; + procedure TForm1.ShowData; begin label3.caption := IntToHex(pcsc.ReaderState,8); label4.caption := pcsc.AttrICCType; label5.caption := pcsc.AttrVendorName; label6.caption := pcsc.AttrVendorSerial; -label14.caption := IntToHex(pcsc.AttrProtocol,8); +label14.caption := IntToHex(pcsc.AttrProtocol,8)+' ATR:'+Bin2HexExt(pcsc.AttrCardATR,true,true); + end; procedure TForm1.pcscCardRemoved(Sender: TObject); @@ -110,17 +190,21 @@ procedure TForm1.pcscCardRemoved(Sender: TObject); procedure TForm1.pcscError(Sender: TObject; ErrSource: TErrSource; ErrCode: Cardinal); begin +if memo1.Lines[memo1.Lines.Count-1]='OnError ' + IntToHex(ErrCode,8) then exit; memo1.Lines.Add('OnError ' + IntToHex(ErrCode,8)); label1.caption := IntToHex(ErrCode,8); ShowData; end; + procedure TForm1.bt_InitClick(Sender: TObject); +var i:integer; begin pcsc.Init; pcsc.UseReaderNum := 0; end; + procedure TForm1.bt_OpenClick(Sender: TObject); begin if pcsc.Open then memo1.lines.add('OPEN: OK') @@ -145,13 +229,22 @@ procedure TForm1.bt_DisconnectClick(Sender: TObject); procedure TForm1.bt_SendClick(Sender: TObject); begin -label2.caption := Bin2HexExt(pcsc.GetResponseFromCard(Hex2Bin('a0f2000016')), true, true); + label2.caption := Bin2HexExt(pcsc.GetResponseFromCard(Hex2Bin('a0f2000016')), true, true); +end; + +procedure TForm1.Button1Click(Sender: TObject); +var i:integer; +begin + memo1.Lines.Add(inttostr(pcsc.ReaderList.Count)); + for i:=0 to pcsc.ReaderList.Count-1 do begin + memo1.Lines.Add(inttostr(i)+':'+pcsc.ReaderList[i]); + end; end; procedure TForm1.pcscCardActive(Sender: TObject); begin -memo1.Lines.Add('OnCardActive'); -ShowData; + memo1.Lines.Add('OnCardActive'); + ShowData; end; procedure TForm1.pcscCardInserted(Sender: TObject); @@ -189,3 +282,4 @@ procedure TForm1.pcscReaderWaiting(Sender: TObject); end; end. + diff --git a/PCSCConnector.dcu b/PCSCConnector.dcu index e565bfd..8b26956 100644 Binary files a/PCSCConnector.dcu and b/PCSCConnector.dcu differ diff --git a/PCSCConnector.pas b/PCSCConnector.pas index 657033c..5df1545 100644 --- a/PCSCConnector.pas +++ b/PCSCConnector.pas @@ -185,7 +185,7 @@ implementation var ActReaderState : cardinal; LastReaderState : cardinal; - SelectedReader : PChar; + SelectedReader : String; ReaderOpen : boolean; NotifyHandle : HWND; @@ -257,12 +257,14 @@ function CardWatcherThread(PContext: pointer): integer; var RetVar : cardinal; RContext : cardinal; + AnsiReader: AnsiString; RStates : array[0..1] of SCARD_READERSTATEA; begin try RContext := cardinal(PContext^); FillChar(RStates,SizeOf(RStates),#0); - RStates[0].szReader := SelectedReader; + AnsiReader := AnsiString(SelectedReader); + RStates[0].szReader := PAnsichar(AnsiReader); RStates[0].pvUserData := nil; RStates[0].dwEventState := ActReaderState; while ReaderOpen do @@ -334,11 +336,11 @@ function TPCSCConnector.Init: boolean; if RetVar = SCARD_S_SUCCESS then begin ReaderListSize := 0; - RetVar := SCardListReadersA(FContext, nil, nil, ReaderListSize); + RetVar := SCardListReadersW(FContext, nil, nil, ReaderListSize); if RetVar = SCARD_S_SUCCESS then begin SetLength(ReaderList, ReaderListSize); - SCardListReadersA(FContext, nil, Pointer(ReaderList), ReaderListSize); + SCardListReadersW(FContext, nil, Pointer(ReaderList), ReaderListSize); FReaderList.Clear; SortOutSubstrings(ReaderList,v,[#0]); for i := 0 to MAXIMUM_SMARTCARD_READERS do @@ -405,8 +407,8 @@ function TPCSCConnector.ConnectSelectedReader: boolean; var RetVar : cardinal; begin - RetVar := SCardConnectA(FContext, - SelectedReader, + RetVar := SCardConnectW(FContext, + PWideChar(SelectedReader), SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_Tx, FCardHandle, diff --git a/PCSCConnectorD2007.bpl b/PCSCConnectorD2007.bpl index f645dd8..e47406a 100644 Binary files a/PCSCConnectorD2007.bpl and b/PCSCConnectorD2007.bpl differ diff --git a/PCSCConnectorD2007.dcp b/PCSCConnectorD2007.dcp index 296fe34..b37a440 100644 Binary files a/PCSCConnectorD2007.dcp and b/PCSCConnectorD2007.dcp differ diff --git a/PCSCConnectorD2007.dpk b/PCSCConnectorD2007.dpk index 484f4e1..a70122b 100644 --- a/PCSCConnectorD2007.dpk +++ b/PCSCConnectorD2007.dpk @@ -1,7 +1,9 @@ package PCSCConnectorD2007; {$R *.res} +{$R *.otares} {$R 'PCSCConnector.dcr'} +{$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} {$ALIGN 8} {$ASSERTIONS ON} {$BOOLEVAL OFF} @@ -23,6 +25,7 @@ package PCSCConnectorD2007; {$WRITEABLECONST OFF} {$MINENUMSIZE 1} {$IMAGEBASE $400000} +{$ENDIF IMPLICITBUILDING} {$DESCRIPTION 'PCSC SmartCard Component D2007'} {$IMPLICITBUILD ON} diff --git a/PCSCConnectorD2007.dproj b/PCSCConnectorD2007.dproj index 1c02bce..7a0230c 100644 --- a/PCSCConnectorD2007.dproj +++ b/PCSCConnectorD2007.dproj @@ -1,204 +1,243 @@ - - - - {aaf26cb8-a556-4121-b6c3-838216141120} - PCSCConnectorD2007.dpk - Debug - AnyCPU - DCC32 - PCSCConnectorD2007.bpl - - - 7.0 - False - False - 0 - RELEASE - - - 7.0 - C:\Users\Johni\Documents\RAD Studio\Projects\PCSC SmartCard Component D2007 - C:\Users\Johni\Documents\RAD Studio\Projects\PCSC SmartCard Component D2007 - C:\Users\Johni\Documents\RAD Studio\Projects\PCSC SmartCard Component D2007 - C:\Users\Johni\Documents\RAD Studio\Projects\PCSC SmartCard Component D2007 - C:\Users\Johni\Documents\RAD Studio\Projects\PCSC SmartCard Component D2007 - C:\Users\Johni\Documents\RAD Studio\Projects\PCSC SmartCard Component D2007 - C:\Users\Johni\Documents\RAD Studio\Projects\PCSC SmartCard Component D2007 - C:\Users\Johni\Documents\RAD Studio\Projects\PCSC SmartCard Component D2007 - C:\Users\Johni\Documents\RAD Studio\Projects\PCSC SmartCard Component D2007 - - - Delphi.Personality - Package - - - False - True - False - - - True - False - False - PCSC SmartCard Component D2007 - - - True - False - 1 - 0 - 0 - 0 - False - False - False - False - False - 1046 - 1252 - - - - - 1.0.0.0 - - - - - - 1.0.0.0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - (untitled) - FastScript 1.9 Components - FastReport 4.0 Components - FastReport 4.0 Client/Server Components - FastScript 1.9 DB Components - FastReport 4.0 DB Components - FastScript 1.9 BDE Components - FastReport 4.0 BDE Components - FastScript 1.9 ADO Components - FastReport 4.0 ADO Components - FastScript 1.9 IBX Components - FastReport 4.0 IBX Components - FastReport 4.0 Exports - FastScript 1.9 Tee Components - Microsoft Office 2000 Sample Automation Server Wrapper Components - Microsoft Office XP Sample Automation Server Wrapper Components - FastReport 4.0 DBX Components - Internet Direct (Indy) for D7 Property and Component Editors - - - PCSCConnectorD2007.dpk - - - - - - - MainSource - - - - - - - - \ No newline at end of file + + + {aaf26cb8-a556-4121-b6c3-838216141120} + PCSCConnectorD2007.dpk + Debug + DCC32 + PCSCConnectorD2007.bpl + VCL + 19.3 + True + Debug + Win32 + 33793 + Package + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + true + Cfg_2 + true + true + + + true + Cfg_2 + true + true + + + true + Cfg_2 + true + true + + + PCSC SmartCard Component D2007 + true + true + PCSCConnectorD2007 + 1 + 00400000 + Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;Winapi;$(DCC_Namespace) + true + 1046 + CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= + + + package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey= + Debug + false + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_192x192.png + annotation-1.2.0.dex.jar;asynclayoutinflater-1.0.0.dex.jar;billing-4.0.0.dex.jar;browser-1.0.0.dex.jar;cloud-messaging.dex.jar;collection-1.0.0.dex.jar;coordinatorlayout-1.0.0.dex.jar;core-1.5.0-rc02.dex.jar;core-common-2.0.1.dex.jar;core-runtime-2.0.1.dex.jar;cursoradapter-1.0.0.dex.jar;customview-1.0.0.dex.jar;documentfile-1.0.0.dex.jar;drawerlayout-1.0.0.dex.jar;firebase-annotations-16.0.0.dex.jar;firebase-common-20.0.0.dex.jar;firebase-components-17.0.0.dex.jar;firebase-datatransport-18.0.0.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.0.0.dex.jar;firebase-installations-interop-17.0.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-22.0.0.dex.jar;fmx.dex.jar;fragment-1.0.0.dex.jar;google-play-licensing.dex.jar;interpolator-1.0.0.dex.jar;javax.inject-1.dex.jar;legacy-support-core-ui-1.0.0.dex.jar;legacy-support-core-utils-1.0.0.dex.jar;lifecycle-common-2.0.0.dex.jar;lifecycle-livedata-2.0.0.dex.jar;lifecycle-livedata-core-2.0.0.dex.jar;lifecycle-runtime-2.0.0.dex.jar;lifecycle-service-2.0.0.dex.jar;lifecycle-viewmodel-2.0.0.dex.jar;listenablefuture-1.0.dex.jar;loader-1.0.0.dex.jar;localbroadcastmanager-1.0.0.dex.jar;play-services-ads-20.1.0.dex.jar;play-services-ads-base-20.1.0.dex.jar;play-services-ads-identifier-17.0.0.dex.jar;play-services-ads-lite-20.1.0.dex.jar;play-services-base-17.5.0.dex.jar;play-services-basement-17.6.0.dex.jar;play-services-cloud-messaging-16.0.0.dex.jar;play-services-drive-17.0.0.dex.jar;play-services-games-21.0.0.dex.jar;play-services-location-18.0.0.dex.jar;play-services-maps-17.0.1.dex.jar;play-services-measurement-base-18.0.0.dex.jar;play-services-measurement-sdk-api-18.0.0.dex.jar;play-services-places-placereport-17.0.0.dex.jar;play-services-stats-17.0.0.dex.jar;play-services-tasks-17.2.0.dex.jar;print-1.0.0.dex.jar;room-common-2.1.0.dex.jar;room-runtime-2.1.0.dex.jar;slidingpanelayout-1.0.0.dex.jar;sqlite-2.0.1.dex.jar;sqlite-framework-2.0.1.dex.jar;swiperefreshlayout-1.0.0.dex.jar;transport-api-3.0.0.dex.jar;transport-backend-cct-3.0.0.dex.jar;transport-runtime-3.0.0.dex.jar;user-messaging-platform-1.0.0.dex.jar;versionedparcelable-1.1.1.dex.jar;viewpager-1.0.0.dex.jar;work-runtime-2.1.0.dex.jar + rtl;$(DCC_UsePackage) + + + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_192x192.png + annotation-1.2.0.dex.jar;asynclayoutinflater-1.0.0.dex.jar;billing-4.0.0.dex.jar;browser-1.0.0.dex.jar;cloud-messaging.dex.jar;collection-1.0.0.dex.jar;coordinatorlayout-1.0.0.dex.jar;core-1.5.0-rc02.dex.jar;core-common-2.0.1.dex.jar;core-runtime-2.0.1.dex.jar;cursoradapter-1.0.0.dex.jar;customview-1.0.0.dex.jar;documentfile-1.0.0.dex.jar;drawerlayout-1.0.0.dex.jar;firebase-annotations-16.0.0.dex.jar;firebase-common-20.0.0.dex.jar;firebase-components-17.0.0.dex.jar;firebase-datatransport-18.0.0.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.0.0.dex.jar;firebase-installations-interop-17.0.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-22.0.0.dex.jar;fmx.dex.jar;fragment-1.0.0.dex.jar;google-play-licensing.dex.jar;interpolator-1.0.0.dex.jar;javax.inject-1.dex.jar;legacy-support-core-ui-1.0.0.dex.jar;legacy-support-core-utils-1.0.0.dex.jar;lifecycle-common-2.0.0.dex.jar;lifecycle-livedata-2.0.0.dex.jar;lifecycle-livedata-core-2.0.0.dex.jar;lifecycle-runtime-2.0.0.dex.jar;lifecycle-service-2.0.0.dex.jar;lifecycle-viewmodel-2.0.0.dex.jar;listenablefuture-1.0.dex.jar;loader-1.0.0.dex.jar;localbroadcastmanager-1.0.0.dex.jar;play-services-ads-20.1.0.dex.jar;play-services-ads-base-20.1.0.dex.jar;play-services-ads-identifier-17.0.0.dex.jar;play-services-ads-lite-20.1.0.dex.jar;play-services-base-17.5.0.dex.jar;play-services-basement-17.6.0.dex.jar;play-services-cloud-messaging-16.0.0.dex.jar;play-services-drive-17.0.0.dex.jar;play-services-games-21.0.0.dex.jar;play-services-location-18.0.0.dex.jar;play-services-maps-17.0.1.dex.jar;play-services-measurement-base-18.0.0.dex.jar;play-services-measurement-sdk-api-18.0.0.dex.jar;play-services-places-placereport-17.0.0.dex.jar;play-services-stats-17.0.0.dex.jar;play-services-tasks-17.2.0.dex.jar;print-1.0.0.dex.jar;room-common-2.1.0.dex.jar;room-runtime-2.1.0.dex.jar;slidingpanelayout-1.0.0.dex.jar;sqlite-2.0.1.dex.jar;sqlite-framework-2.0.1.dex.jar;swiperefreshlayout-1.0.0.dex.jar;transport-api-3.0.0.dex.jar;transport-backend-cct-3.0.0.dex.jar;transport-runtime-3.0.0.dex.jar;user-messaging-platform-1.0.0.dex.jar;versionedparcelable-1.1.1.dex.jar;viewpager-1.0.0.dex.jar;work-runtime-2.1.0.dex.jar + rtl;$(DCC_UsePackage) + + + $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_1024x1024.png + rtl;$(DCC_UsePackage) + + + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + Debug + true + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName) + 1033 + $(BDS)\bin\default_app.manifest + PCSCConnectorD2007_Icon1.ico + true + vcl;rtl;$(DCC_UsePackage) + + + $(BDS)\bin\default_app.manifest + PCSCConnectorD2007_Icon1.ico + true + vcl;rtl;$(DCC_UsePackage) + + + 7.0 + 0 + False + 0 + RELEASE;$(DCC_Define) + + + 1033 + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName) + + + 7.0 + C:\projetos\git\PCSCSmartCardComponent + C:\Users\Johni\Documents\RAD Studio\Projects\PCSC SmartCard Component D2007 + C:\Users\Johni\Documents\RAD Studio\Projects\PCSC SmartCard Component D2007 + C:\projetos\git\PCSCSmartCardComponent + C:\projetos\git\PCSCSmartCardComponent + C:\projetos\git\PCSCSmartCardComponent;$(DCC_UnitSearchPath) + C:\Users\Johni\Documents\RAD Studio\Projects\PCSC SmartCard Component D2007;$(DCC_ResourcePath) + C:\Users\Johni\Documents\RAD Studio\Projects\PCSC SmartCard Component D2007;$(DCC_ObjPath) + C:\Users\Johni\Documents\RAD Studio\Projects\PCSC SmartCard Component D2007;$(DCC_IncludePath) + + + Debug + + + Debug + + + C:\projetos\git\PCSCSmartCardComponent + C:\projetos\git\PCSCSmartCardComponent + C:\projetos\git\PCSCSmartCardComponent;$(DCC_UnitSearchPath) + C:\projetos\git\PCSCSmartCardComponent + 1033 + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName) + C:\projetos\git\PCSCSmartCardComponent + C:\projetos\git\PCSCSmartCardComponent + + + Delphi.Personality.12 + Package + + + + False + True + False + + + True + False + 1 + 0 + 0 + 0 + False + False + False + False + False + 1046 + 1252 + + + + + 1.0.0.0 + + + + + + 1.0.0.0 + + + + Microsoft Office 2000 Sample Automation Server Wrapper Components + Microsoft Office XP Sample Automation Server Wrapper Components + + + PCSCConnectorD2007.dpk + + + + False + True + False + True + False + True + False + + + 12 + + + + + MainSource + + + + + + + Base + + + Cfg_1 + Base + + + Cfg_2 + Base + + + + + diff --git a/PCSCConnectorD2007.dproj.local b/PCSCConnectorD2007.dproj.local index 40b79ac..8ec01fe 100644 --- a/PCSCConnectorD2007.dproj.local +++ b/PCSCConnectorD2007.dproj.local @@ -1,6 +1,6 @@  - + 2010/05/01 17:25:16.727.dproj,C:\Users\Johni\Documents\RAD Studio\Projects\Package1.dproj=C:\Users\Johni\Documents\RAD Studio\Projects\PCSCConnectorD2007.dproj 2010/05/01 17:25:26.281.dproj,C:\Users\Johni\Documents\RAD Studio\Projects\PCSCConnectorD2007.dproj=C:\Users\Johni\Documents\RAD Studio\Projects\PCSC SmartCard Component D2007\PCSCConnectorD2007.dproj diff --git a/PCSCConnectorD2007.identcache b/PCSCConnectorD2007.identcache index dc02926..61a1b02 100644 Binary files a/PCSCConnectorD2007.identcache and b/PCSCConnectorD2007.identcache differ diff --git a/PCSCConnectorD2007.otares b/PCSCConnectorD2007.otares new file mode 100644 index 0000000..a1c335b Binary files /dev/null and b/PCSCConnectorD2007.otares differ diff --git a/PCSCConnectorD2007.res b/PCSCConnectorD2007.res index c2a331a..45a2f9a 100644 Binary files a/PCSCConnectorD2007.res and b/PCSCConnectorD2007.res differ diff --git a/PCSCConnectorD2007.~bpl b/PCSCConnectorD2007.~bpl index 111eb78..5e2c38d 100644 Binary files a/PCSCConnectorD2007.~bpl and b/PCSCConnectorD2007.~bpl differ diff --git a/PCSCConnectorD2007_Icon.ico b/PCSCConnectorD2007_Icon.ico new file mode 100644 index 0000000..379ec80 Binary files /dev/null and b/PCSCConnectorD2007_Icon.ico differ diff --git a/PCSCConnectorD2007_Icon1.ico b/PCSCConnectorD2007_Icon1.ico new file mode 100644 index 0000000..379ec80 Binary files /dev/null and b/PCSCConnectorD2007_Icon1.ico differ diff --git a/PCSCTest.dproj b/PCSCTest.dproj index 889638f..7f47ac1 100644 --- a/PCSCTest.dproj +++ b/PCSCTest.dproj @@ -1,83 +1,207 @@  - - {58280139-5409-4204-84b5-0dc60255eeb5} - PCSCTest.dpr - Debug - AnyCPU - DCC32 - PCSCTest.exe - - - 7.0 - False - False - 0 - RELEASE - - - 7.0 - DEBUG - - - Delphi.Personality - VCLApplication - - - False - True - False - - - True - False - 1 - 0 - 0 - 0 - False - False - False - False - False - 1046 - 1252 - - - - - 1.0.0.0 - - - - - - 1.0.0.0 - - - - - - - - - - Microsoft Office 2000 Sample Automation Server Wrapper Components - Microsoft Office XP Sample Automation Server Wrapper Components - FastReport 4.0 DBX Components - - - PCSCTest.dpr - - - - - - - MainSource - - -
Form1
-
-
- -
\ No newline at end of file + + {58280139-5409-4204-84b5-0dc60255eeb5} + PCSCTest.dpr + Debug + DCC32 + PCSCTest.exe + VCL + 19.3 + True + Debug + Win32 + 33793 + Application + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + true + Cfg_2 + true + true + + + true + Cfg_2 + true + true + + + true + Cfg_2 + true + true + + + PCSCTest + Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;Winapi;$(DCC_Namespace) + true + 1046 + CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= + + + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_192x192.png + annotation-1.2.0.dex.jar;asynclayoutinflater-1.0.0.dex.jar;billing-4.0.0.dex.jar;browser-1.0.0.dex.jar;cloud-messaging.dex.jar;collection-1.0.0.dex.jar;coordinatorlayout-1.0.0.dex.jar;core-1.5.0-rc02.dex.jar;core-common-2.0.1.dex.jar;core-runtime-2.0.1.dex.jar;cursoradapter-1.0.0.dex.jar;customview-1.0.0.dex.jar;documentfile-1.0.0.dex.jar;drawerlayout-1.0.0.dex.jar;firebase-annotations-16.0.0.dex.jar;firebase-common-20.0.0.dex.jar;firebase-components-17.0.0.dex.jar;firebase-datatransport-18.0.0.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.0.0.dex.jar;firebase-installations-interop-17.0.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-22.0.0.dex.jar;fmx.dex.jar;fragment-1.0.0.dex.jar;google-play-licensing.dex.jar;interpolator-1.0.0.dex.jar;javax.inject-1.dex.jar;legacy-support-core-ui-1.0.0.dex.jar;legacy-support-core-utils-1.0.0.dex.jar;lifecycle-common-2.0.0.dex.jar;lifecycle-livedata-2.0.0.dex.jar;lifecycle-livedata-core-2.0.0.dex.jar;lifecycle-runtime-2.0.0.dex.jar;lifecycle-service-2.0.0.dex.jar;lifecycle-viewmodel-2.0.0.dex.jar;listenablefuture-1.0.dex.jar;loader-1.0.0.dex.jar;localbroadcastmanager-1.0.0.dex.jar;play-services-ads-20.1.0.dex.jar;play-services-ads-base-20.1.0.dex.jar;play-services-ads-identifier-17.0.0.dex.jar;play-services-ads-lite-20.1.0.dex.jar;play-services-base-17.5.0.dex.jar;play-services-basement-17.6.0.dex.jar;play-services-cloud-messaging-16.0.0.dex.jar;play-services-drive-17.0.0.dex.jar;play-services-games-21.0.0.dex.jar;play-services-location-18.0.0.dex.jar;play-services-maps-17.0.1.dex.jar;play-services-measurement-base-18.0.0.dex.jar;play-services-measurement-sdk-api-18.0.0.dex.jar;play-services-places-placereport-17.0.0.dex.jar;play-services-stats-17.0.0.dex.jar;play-services-tasks-17.2.0.dex.jar;print-1.0.0.dex.jar;room-common-2.1.0.dex.jar;room-runtime-2.1.0.dex.jar;slidingpanelayout-1.0.0.dex.jar;sqlite-2.0.1.dex.jar;sqlite-framework-2.0.1.dex.jar;swiperefreshlayout-1.0.0.dex.jar;transport-api-3.0.0.dex.jar;transport-backend-cct-3.0.0.dex.jar;transport-runtime-3.0.0.dex.jar;user-messaging-platform-1.0.0.dex.jar;versionedparcelable-1.1.1.dex.jar;viewpager-1.0.0.dex.jar;work-runtime-2.1.0.dex.jar + + + $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_1024x1024.png + + + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + Debug + true + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName) + 1033 + $(BDS)\bin\default_app.manifest + PCSCTest_Icon.ico + true + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png + + + PCSCTest_Icon.ico + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png + + + 7.0 + 0 + False + 0 + RELEASE;$(DCC_Define) + + + true + PerMonitorV2 + + + 7.0 + DEBUG;$(DCC_Define) + + + Debug + + + Debug + + + true + PerMonitorV2 + + + Delphi.Personality.12 + VCLApplication + + + + False + True + False + + + True + False + 1 + 0 + 0 + 0 + False + False + False + False + False + 1046 + 1252 + + + + + 1.0.0.0 + + + + + + 1.0.0.0 + + + + Microsoft Office 2000 Sample Automation Server Wrapper Components + Microsoft Office XP Sample Automation Server Wrapper Components + FastReport 4.0 DBX Components + + + PCSCTest.dpr + + + + True + True + True + False + + + 12 + + + + MainSource + + +
Form1
+
+ + Base + + + Cfg_1 + Base + + + Cfg_2 + Base + +
+ + + + + diff --git a/PCSCTest.exe b/PCSCTest.exe new file mode 100644 index 0000000..2494ccc Binary files /dev/null and b/PCSCTest.exe differ diff --git a/PCSCTest.res b/PCSCTest.res index a98d72b..f264b3d 100644 Binary files a/PCSCTest.res and b/PCSCTest.res differ diff --git a/PCSCTest_Icon.ico b/PCSCTest_Icon.ico new file mode 100644 index 0000000..1998c2d Binary files /dev/null and b/PCSCTest_Icon.ico differ diff --git a/SCardErr.dcu b/SCardErr.dcu index fc89c63..f6fdfd0 100644 Binary files a/SCardErr.dcu and b/SCardErr.dcu differ diff --git a/WinSCard.dcu b/WinSCard.dcu index 918cd52..34a80f9 100644 Binary files a/WinSCard.dcu and b/WinSCard.dcu differ diff --git a/WinSmCrd.dcu b/WinSmCrd.dcu index cacb502..9c91bcc 100644 Binary files a/WinSmCrd.dcu and b/WinSmCrd.dcu differ diff --git a/__history/FirstTest.dfm.~1~ b/__history/FirstTest.dfm.~1~ new file mode 100644 index 0000000..78630f2 --- /dev/null +++ b/__history/FirstTest.dfm.~1~ @@ -0,0 +1,186 @@ +object Form1: TForm1 + Left = 380 + Top = 178 + Width = 356 + Height = 336 + Caption = 'Form1' + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'MS Sans Serif' + Font.Style = [] + OldCreateOrder = False + PixelsPerInch = 96 + TextHeight = 13 + object Label1: TLabel + Left = 155 + Top = 5 + Width = 9 + Height = 13 + Caption = '...' + end + object Label2: TLabel + Left = 155 + Top = 20 + Width = 9 + Height = 13 + Caption = '...' + end + object Label3: TLabel + Left = 155 + Top = 35 + Width = 9 + Height = 13 + Caption = '...' + end + object Label4: TLabel + Left = 155 + Top = 50 + Width = 9 + Height = 13 + Caption = '...' + end + object Label5: TLabel + Left = 155 + Top = 65 + Width = 9 + Height = 13 + Caption = '...' + end + object Label6: TLabel + Left = 155 + Top = 80 + Width = 9 + Height = 13 + Caption = '...' + end + object Label7: TLabel + Left = 85 + Top = 5 + Width = 43 + Height = 13 + Caption = 'last error:' + end + object Label8: TLabel + Left = 85 + Top = 20 + Width = 65 + Height = 13 + Caption = 'last response:' + end + object Label9: TLabel + Left = 85 + Top = 35 + Width = 56 + Height = 13 + Caption = 'readerstate:' + end + object Label10: TLabel + Left = 85 + Top = 50 + Width = 43 + Height = 13 + Caption = 'ICC type:' + end + object Label11: TLabel + Left = 85 + Top = 65 + Width = 65 + Height = 13 + Caption = 'vendor name:' + end + object Label12: TLabel + Left = 85 + Top = 80 + Width = 42 + Height = 13 + Caption = 'serial nr.:' + end + object Label13: TLabel + Left = 85 + Top = 95 + Width = 41 + Height = 13 + Caption = 'protocol:' + end + object Label14: TLabel + Left = 155 + Top = 95 + Width = 9 + Height = 13 + Caption = '...' + end + object bt_Init: TButton + Left = 5 + Top = 5 + Width = 62 + Height = 19 + Caption = 'Init' + TabOrder = 0 + OnClick = bt_InitClick + end + object bt_Open: TButton + Left = 5 + Top = 25 + Width = 62 + Height = 19 + Caption = 'Open' + TabOrder = 1 + OnClick = bt_OpenClick + end + object bt_Connect: TButton + Left = 5 + Top = 45 + Width = 62 + Height = 19 + Caption = 'Connect' + TabOrder = 2 + OnClick = bt_ConnectClick + end + object bt_Close: TButton + Left = 5 + Top = 65 + Width = 62 + Height = 19 + Caption = 'Close' + TabOrder = 3 + OnClick = bt_CloseClick + end + object bt_Disconnect: TButton + Left = 5 + Top = 85 + Width = 62 + Height = 19 + Caption = 'Disconnect' + TabOrder = 4 + OnClick = bt_DisconnectClick + end + object bt_Send: TButton + Left = 5 + Top = 105 + Width = 62 + Height = 19 + Caption = 'Send' + TabOrder = 5 + OnClick = bt_SendClick + end + object Memo1: TMemo + Left = 75 + Top = 130 + Width = 271 + Height = 176 + TabOrder = 6 + end + object pcsc: TPCSCConnector + OnCardInserted = pcscCardInserted + OnCardActive = pcscCardActive + OnCardRemoved = pcscCardRemoved + OnCardInvalid = pcscCardInvalid + OnReaderWaiting = pcscReaderWaiting + OnReaderListChange = pcscReaderListChange + OnError = pcscError + Left = 315 + Top = 5 + end +end diff --git a/__history/FirstTest.dfm.~2~ b/__history/FirstTest.dfm.~2~ new file mode 100644 index 0000000..02a6c26 --- /dev/null +++ b/__history/FirstTest.dfm.~2~ @@ -0,0 +1,185 @@ +object Form1: TForm1 + Left = 380 + Top = 178 + Caption = 'Form1' + ClientHeight = 553 + ClientWidth = 811 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'MS Sans Serif' + Font.Style = [] + PixelsPerInch = 96 + TextHeight = 13 + object Label1: TLabel + Left = 155 + Top = 5 + Width = 9 + Height = 13 + Caption = '...' + end + object Label2: TLabel + Left = 155 + Top = 20 + Width = 9 + Height = 13 + Caption = '...' + end + object Label3: TLabel + Left = 155 + Top = 35 + Width = 9 + Height = 13 + Caption = '...' + end + object Label4: TLabel + Left = 155 + Top = 50 + Width = 9 + Height = 13 + Caption = '...' + end + object Label5: TLabel + Left = 155 + Top = 65 + Width = 9 + Height = 13 + Caption = '...' + end + object Label6: TLabel + Left = 155 + Top = 80 + Width = 9 + Height = 13 + Caption = '...' + end + object Label7: TLabel + Left = 85 + Top = 5 + Width = 43 + Height = 13 + Caption = 'last error:' + end + object Label8: TLabel + Left = 85 + Top = 20 + Width = 65 + Height = 13 + Caption = 'last response:' + end + object Label9: TLabel + Left = 85 + Top = 35 + Width = 56 + Height = 13 + Caption = 'readerstate:' + end + object Label10: TLabel + Left = 85 + Top = 50 + Width = 43 + Height = 13 + Caption = 'ICC type:' + end + object Label11: TLabel + Left = 85 + Top = 65 + Width = 65 + Height = 13 + Caption = 'vendor name:' + end + object Label12: TLabel + Left = 85 + Top = 80 + Width = 42 + Height = 13 + Caption = 'serial nr.:' + end + object Label13: TLabel + Left = 85 + Top = 95 + Width = 41 + Height = 13 + Caption = 'protocol:' + end + object Label14: TLabel + Left = 155 + Top = 95 + Width = 9 + Height = 13 + Caption = '...' + end + object bt_Init: TButton + Left = 5 + Top = 5 + Width = 62 + Height = 19 + Caption = 'Init' + TabOrder = 0 + OnClick = bt_InitClick + end + object bt_Open: TButton + Left = 5 + Top = 25 + Width = 62 + Height = 19 + Caption = 'Open' + TabOrder = 1 + OnClick = bt_OpenClick + end + object bt_Connect: TButton + Left = 5 + Top = 45 + Width = 62 + Height = 19 + Caption = 'Connect' + TabOrder = 2 + OnClick = bt_ConnectClick + end + object bt_Close: TButton + Left = 5 + Top = 65 + Width = 62 + Height = 19 + Caption = 'Close' + TabOrder = 3 + OnClick = bt_CloseClick + end + object bt_Disconnect: TButton + Left = 5 + Top = 85 + Width = 62 + Height = 19 + Caption = 'Disconnect' + TabOrder = 4 + OnClick = bt_DisconnectClick + end + object bt_Send: TButton + Left = 5 + Top = 105 + Width = 62 + Height = 19 + Caption = 'Send' + TabOrder = 5 + OnClick = bt_SendClick + end + object Memo1: TMemo + Left = 8 + Top = 130 + Width = 793 + Height = 415 + TabOrder = 6 + end + object pcsc: TPCSCConnector + OnCardInserted = pcscCardInserted + OnCardActive = pcscCardActive + OnCardRemoved = pcscCardRemoved + OnCardInvalid = pcscCardInvalid + OnReaderWaiting = pcscReaderWaiting + OnReaderListChange = pcscReaderListChange + OnError = pcscError + Left = 211 + Top = 13 + end +end diff --git a/__history/FirstTest.dfm.~3~ b/__history/FirstTest.dfm.~3~ new file mode 100644 index 0000000..02a6c26 --- /dev/null +++ b/__history/FirstTest.dfm.~3~ @@ -0,0 +1,185 @@ +object Form1: TForm1 + Left = 380 + Top = 178 + Caption = 'Form1' + ClientHeight = 553 + ClientWidth = 811 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'MS Sans Serif' + Font.Style = [] + PixelsPerInch = 96 + TextHeight = 13 + object Label1: TLabel + Left = 155 + Top = 5 + Width = 9 + Height = 13 + Caption = '...' + end + object Label2: TLabel + Left = 155 + Top = 20 + Width = 9 + Height = 13 + Caption = '...' + end + object Label3: TLabel + Left = 155 + Top = 35 + Width = 9 + Height = 13 + Caption = '...' + end + object Label4: TLabel + Left = 155 + Top = 50 + Width = 9 + Height = 13 + Caption = '...' + end + object Label5: TLabel + Left = 155 + Top = 65 + Width = 9 + Height = 13 + Caption = '...' + end + object Label6: TLabel + Left = 155 + Top = 80 + Width = 9 + Height = 13 + Caption = '...' + end + object Label7: TLabel + Left = 85 + Top = 5 + Width = 43 + Height = 13 + Caption = 'last error:' + end + object Label8: TLabel + Left = 85 + Top = 20 + Width = 65 + Height = 13 + Caption = 'last response:' + end + object Label9: TLabel + Left = 85 + Top = 35 + Width = 56 + Height = 13 + Caption = 'readerstate:' + end + object Label10: TLabel + Left = 85 + Top = 50 + Width = 43 + Height = 13 + Caption = 'ICC type:' + end + object Label11: TLabel + Left = 85 + Top = 65 + Width = 65 + Height = 13 + Caption = 'vendor name:' + end + object Label12: TLabel + Left = 85 + Top = 80 + Width = 42 + Height = 13 + Caption = 'serial nr.:' + end + object Label13: TLabel + Left = 85 + Top = 95 + Width = 41 + Height = 13 + Caption = 'protocol:' + end + object Label14: TLabel + Left = 155 + Top = 95 + Width = 9 + Height = 13 + Caption = '...' + end + object bt_Init: TButton + Left = 5 + Top = 5 + Width = 62 + Height = 19 + Caption = 'Init' + TabOrder = 0 + OnClick = bt_InitClick + end + object bt_Open: TButton + Left = 5 + Top = 25 + Width = 62 + Height = 19 + Caption = 'Open' + TabOrder = 1 + OnClick = bt_OpenClick + end + object bt_Connect: TButton + Left = 5 + Top = 45 + Width = 62 + Height = 19 + Caption = 'Connect' + TabOrder = 2 + OnClick = bt_ConnectClick + end + object bt_Close: TButton + Left = 5 + Top = 65 + Width = 62 + Height = 19 + Caption = 'Close' + TabOrder = 3 + OnClick = bt_CloseClick + end + object bt_Disconnect: TButton + Left = 5 + Top = 85 + Width = 62 + Height = 19 + Caption = 'Disconnect' + TabOrder = 4 + OnClick = bt_DisconnectClick + end + object bt_Send: TButton + Left = 5 + Top = 105 + Width = 62 + Height = 19 + Caption = 'Send' + TabOrder = 5 + OnClick = bt_SendClick + end + object Memo1: TMemo + Left = 8 + Top = 130 + Width = 793 + Height = 415 + TabOrder = 6 + end + object pcsc: TPCSCConnector + OnCardInserted = pcscCardInserted + OnCardActive = pcscCardActive + OnCardRemoved = pcscCardRemoved + OnCardInvalid = pcscCardInvalid + OnReaderWaiting = pcscReaderWaiting + OnReaderListChange = pcscReaderListChange + OnError = pcscError + Left = 211 + Top = 13 + end +end diff --git a/__history/FirstTest.dfm.~4~ b/__history/FirstTest.dfm.~4~ new file mode 100644 index 0000000..0bbbdbb --- /dev/null +++ b/__history/FirstTest.dfm.~4~ @@ -0,0 +1,191 @@ +object Form1: TForm1 + Left = 380 + Top = 178 + Caption = 'Form1' + ClientHeight = 553 + ClientWidth = 811 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'MS Sans Serif' + Font.Style = [] + PixelsPerInch = 96 + TextHeight = 13 + object Label1: TLabel + Left = 155 + Top = 5 + Width = 9 + Height = 13 + Caption = '...' + end + object Label2: TLabel + Left = 155 + Top = 20 + Width = 9 + Height = 13 + Caption = '...' + end + object Label3: TLabel + Left = 155 + Top = 35 + Width = 9 + Height = 13 + Caption = '...' + end + object Label4: TLabel + Left = 155 + Top = 50 + Width = 9 + Height = 13 + Caption = '...' + end + object Label5: TLabel + Left = 155 + Top = 65 + Width = 9 + Height = 13 + Caption = '...' + end + object Label6: TLabel + Left = 155 + Top = 80 + Width = 9 + Height = 13 + Caption = '...' + end + object Label7: TLabel + Left = 85 + Top = 5 + Width = 43 + Height = 13 + Caption = 'last error:' + end + object Label8: TLabel + Left = 85 + Top = 20 + Width = 65 + Height = 13 + Caption = 'last response:' + end + object Label9: TLabel + Left = 85 + Top = 35 + Width = 56 + Height = 13 + Caption = 'readerstate:' + end + object Label10: TLabel + Left = 85 + Top = 50 + Width = 43 + Height = 13 + Caption = 'ICC type:' + end + object Label11: TLabel + Left = 85 + Top = 65 + Width = 65 + Height = 13 + Caption = 'vendor name:' + end + object Label12: TLabel + Left = 85 + Top = 80 + Width = 42 + Height = 13 + Caption = 'serial nr.:' + end + object Label13: TLabel + Left = 85 + Top = 95 + Width = 41 + Height = 13 + Caption = 'protocol:' + end + object Label14: TLabel + Left = 155 + Top = 95 + Width = 9 + Height = 13 + Caption = '...' + end + object bt_Init: TButton + Left = 5 + Top = 5 + Width = 62 + Height = 19 + Caption = 'Init' + TabOrder = 0 + OnClick = bt_InitClick + end + object bt_Open: TButton + Left = 5 + Top = 25 + Width = 62 + Height = 19 + Caption = 'Open' + TabOrder = 1 + OnClick = bt_OpenClick + end + object bt_Connect: TButton + Left = 5 + Top = 45 + Width = 62 + Height = 19 + Caption = 'Connect' + TabOrder = 2 + OnClick = bt_ConnectClick + end + object bt_Close: TButton + Left = 5 + Top = 65 + Width = 62 + Height = 19 + Caption = 'Close' + TabOrder = 3 + OnClick = bt_CloseClick + end + object bt_Disconnect: TButton + Left = 5 + Top = 85 + Width = 62 + Height = 19 + Caption = 'Disconnect' + TabOrder = 4 + OnClick = bt_DisconnectClick + end + object bt_Send: TButton + Left = 5 + Top = 105 + Width = 62 + Height = 19 + Caption = 'Send' + TabOrder = 5 + OnClick = bt_SendClick + end + object Memo1: TMemo + Left = 8 + Top = 130 + Width = 793 + Height = 415 + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -13 + Font.Name = 'MS Sans Serif' + Font.Style = [fsBold] + ParentFont = False + TabOrder = 6 + end + object pcsc: TPCSCConnector + OnCardInserted = pcscCardInserted + OnCardActive = pcscCardActive + OnCardRemoved = pcscCardRemoved + OnCardInvalid = pcscCardInvalid + OnReaderWaiting = pcscReaderWaiting + OnReaderListChange = pcscReaderListChange + OnError = pcscError + Left = 211 + Top = 13 + end +end diff --git a/__history/FirstTest.dfm.~5~ b/__history/FirstTest.dfm.~5~ new file mode 100644 index 0000000..d42e9da --- /dev/null +++ b/__history/FirstTest.dfm.~5~ @@ -0,0 +1,200 @@ +object Form1: TForm1 + Left = 380 + Top = 178 + Caption = 'Form1' + ClientHeight = 553 + ClientWidth = 811 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'MS Sans Serif' + Font.Style = [] + PixelsPerInch = 96 + TextHeight = 13 + object Label1: TLabel + Left = 155 + Top = 5 + Width = 9 + Height = 13 + Caption = '...' + end + object Label2: TLabel + Left = 155 + Top = 20 + Width = 9 + Height = 13 + Caption = '...' + end + object Label3: TLabel + Left = 155 + Top = 35 + Width = 9 + Height = 13 + Caption = '...' + end + object Label4: TLabel + Left = 155 + Top = 50 + Width = 9 + Height = 13 + Caption = '...' + end + object Label5: TLabel + Left = 155 + Top = 65 + Width = 9 + Height = 13 + Caption = '...' + end + object Label6: TLabel + Left = 155 + Top = 80 + Width = 9 + Height = 13 + Caption = '...' + end + object Label7: TLabel + Left = 85 + Top = 5 + Width = 43 + Height = 13 + Caption = 'last error:' + end + object Label8: TLabel + Left = 85 + Top = 20 + Width = 65 + Height = 13 + Caption = 'last response:' + end + object Label9: TLabel + Left = 85 + Top = 35 + Width = 56 + Height = 13 + Caption = 'readerstate:' + end + object Label10: TLabel + Left = 85 + Top = 50 + Width = 43 + Height = 13 + Caption = 'ICC type:' + end + object Label11: TLabel + Left = 85 + Top = 65 + Width = 65 + Height = 13 + Caption = 'vendor name:' + end + object Label12: TLabel + Left = 85 + Top = 80 + Width = 42 + Height = 13 + Caption = 'serial nr.:' + end + object Label13: TLabel + Left = 85 + Top = 95 + Width = 41 + Height = 13 + Caption = 'protocol:' + end + object Label14: TLabel + Left = 155 + Top = 95 + Width = 9 + Height = 13 + Caption = '...' + end + object bt_Init: TButton + Left = 5 + Top = 5 + Width = 62 + Height = 19 + Caption = 'Init' + TabOrder = 0 + OnClick = bt_InitClick + end + object bt_Open: TButton + Left = 5 + Top = 25 + Width = 62 + Height = 19 + Caption = 'Open' + TabOrder = 1 + OnClick = bt_OpenClick + end + object bt_Connect: TButton + Left = 5 + Top = 45 + Width = 62 + Height = 19 + Caption = 'Connect' + TabOrder = 2 + OnClick = bt_ConnectClick + end + object bt_Close: TButton + Left = 5 + Top = 65 + Width = 62 + Height = 19 + Caption = 'Close' + TabOrder = 3 + OnClick = bt_CloseClick + end + object bt_Disconnect: TButton + Left = 5 + Top = 85 + Width = 62 + Height = 19 + Caption = 'Disconnect' + TabOrder = 4 + OnClick = bt_DisconnectClick + end + object bt_Send: TButton + Left = 5 + Top = 105 + Width = 62 + Height = 19 + Caption = 'Send' + TabOrder = 5 + OnClick = bt_SendClick + end + object Memo1: TMemo + Left = 8 + Top = 130 + Width = 793 + Height = 415 + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -13 + Font.Name = 'MS Sans Serif' + Font.Style = [fsBold] + ParentFont = False + TabOrder = 6 + end + object Button1: TButton + Left = 232 + Top = 88 + Width = 75 + Height = 25 + Caption = 'Button1' + TabOrder = 7 + OnClick = Button1Click + end + object pcsc: TPCSCConnector + OnCardInserted = pcscCardInserted + OnCardActive = pcscCardActive + OnCardRemoved = pcscCardRemoved + OnCardInvalid = pcscCardInvalid + OnReaderWaiting = pcscReaderWaiting + OnReaderListChange = pcscReaderListChange + OnError = pcscError + Left = 211 + Top = 13 + end +end diff --git a/__history/FirstTest.dfm.~6~ b/__history/FirstTest.dfm.~6~ new file mode 100644 index 0000000..3bd87ee --- /dev/null +++ b/__history/FirstTest.dfm.~6~ @@ -0,0 +1,200 @@ +object Form1: TForm1 + Left = 380 + Top = 178 + Caption = 'Form1' + ClientHeight = 553 + ClientWidth = 811 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'MS Sans Serif' + Font.Style = [] + PixelsPerInch = 96 + TextHeight = 13 + object Label1: TLabel + Left = 155 + Top = 5 + Width = 9 + Height = 13 + Caption = '...' + end + object Label2: TLabel + Left = 155 + Top = 20 + Width = 9 + Height = 13 + Caption = '...' + end + object Label3: TLabel + Left = 155 + Top = 35 + Width = 9 + Height = 13 + Caption = '...' + end + object Label4: TLabel + Left = 155 + Top = 50 + Width = 9 + Height = 13 + Caption = '...' + end + object Label5: TLabel + Left = 155 + Top = 65 + Width = 9 + Height = 13 + Caption = '...' + end + object Label6: TLabel + Left = 155 + Top = 80 + Width = 9 + Height = 13 + Caption = '...' + end + object Label7: TLabel + Left = 85 + Top = 5 + Width = 43 + Height = 13 + Caption = 'last error:' + end + object Label8: TLabel + Left = 85 + Top = 20 + Width = 65 + Height = 13 + Caption = 'last response:' + end + object Label9: TLabel + Left = 85 + Top = 35 + Width = 56 + Height = 13 + Caption = 'readerstate:' + end + object Label10: TLabel + Left = 85 + Top = 50 + Width = 43 + Height = 13 + Caption = 'ICC type:' + end + object Label11: TLabel + Left = 85 + Top = 65 + Width = 65 + Height = 13 + Caption = 'vendor name:' + end + object Label12: TLabel + Left = 85 + Top = 80 + Width = 42 + Height = 13 + Caption = 'serial nr.:' + end + object Label13: TLabel + Left = 85 + Top = 95 + Width = 41 + Height = 13 + Caption = 'protocol:' + end + object Label14: TLabel + Left = 155 + Top = 95 + Width = 9 + Height = 13 + Caption = '...' + end + object bt_Init: TButton + Left = 5 + Top = 5 + Width = 62 + Height = 19 + Caption = 'Init' + TabOrder = 0 + OnClick = bt_InitClick + end + object bt_Open: TButton + Left = 5 + Top = 25 + Width = 62 + Height = 19 + Caption = 'Open' + TabOrder = 1 + OnClick = bt_OpenClick + end + object bt_Connect: TButton + Left = 5 + Top = 45 + Width = 62 + Height = 19 + Caption = 'Connect' + TabOrder = 2 + OnClick = bt_ConnectClick + end + object bt_Close: TButton + Left = 5 + Top = 65 + Width = 62 + Height = 19 + Caption = 'Close' + TabOrder = 3 + OnClick = bt_CloseClick + end + object bt_Disconnect: TButton + Left = 5 + Top = 85 + Width = 62 + Height = 19 + Caption = 'Disconnect' + TabOrder = 4 + OnClick = bt_DisconnectClick + end + object bt_Send: TButton + Left = 5 + Top = 105 + Width = 62 + Height = 19 + Caption = 'Send' + TabOrder = 5 + OnClick = bt_SendClick + end + object Memo1: TMemo + Left = 8 + Top = 130 + Width = 793 + Height = 415 + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -13 + Font.Name = 'MS Sans Serif' + Font.Style = [fsBold] + ParentFont = False + TabOrder = 6 + end + object Button1: TButton + Left = 192 + Top = 99 + Width = 75 + Height = 25 + Caption = 'Button1' + TabOrder = 7 + OnClick = Button1Click + end + object pcsc: TPCSCConnector + OnCardInserted = pcscCardInserted + OnCardActive = pcscCardActive + OnCardRemoved = pcscCardRemoved + OnCardInvalid = pcscCardInvalid + OnReaderWaiting = pcscReaderWaiting + OnReaderListChange = pcscReaderListChange + OnError = pcscError + Left = 227 + Top = 13 + end +end diff --git a/__history/FirstTest.pas.~57~ b/__history/FirstTest.pas.~57~ new file mode 100644 index 0000000..31f138b --- /dev/null +++ b/__history/FirstTest.pas.~57~ @@ -0,0 +1,283 @@ +unit FirstTest; + +interface + +uses + Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, WinSCard, WinSmCrd, SCardErr, + StdCtrls, PCSCConnector; + +type + TForm1 = class(TForm) + pcsc: TPCSCConnector; + Label1: TLabel; + Label2: TLabel; + Label3: TLabel; + Label4: TLabel; + Label5: TLabel; + Label6: TLabel; + bt_Init: TButton; + bt_Open: TButton; + bt_Connect: TButton; + bt_Close: TButton; + bt_Disconnect: TButton; + Label7: TLabel; + Label8: TLabel; + Label9: TLabel; + Label10: TLabel; + Label11: TLabel; + Label12: TLabel; + bt_Send: TButton; + Memo1: TMemo; + Label13: TLabel; + Label14: TLabel; + Button1: TButton; + procedure pcscCardRemoved(Sender: TObject); + procedure pcscError(Sender: TObject; ErrSource: TErrSource; ErrCode: Cardinal); + procedure ShowData; + procedure bt_InitClick(Sender: TObject); + procedure bt_OpenClick(Sender: TObject); + procedure bt_ConnectClick(Sender: TObject); + procedure bt_CloseClick(Sender: TObject); + procedure bt_DisconnectClick(Sender: TObject); + procedure bt_SendClick(Sender: TObject); + procedure pcscCardActive(Sender: TObject); + procedure pcscCardInserted(Sender: TObject); + procedure pcscCardInvalid(Sender: TObject); + procedure pcscReaderConnect(Sender: TObject); + procedure pcscReaderDisconnect(Sender: TObject); + procedure pcscReaderListChange(Sender: TObject); + procedure pcscReaderWaiting(Sender: TObject); + procedure Button1Click(Sender: TObject); + private + { Private-Deklarationen } + public + { Public-Deklarationen } + end; + +var + Form1: TForm1; + +implementation + +{$R *.DFM} + +const + +HexChars = '0123456789abcdefABCDEF'; + +procedure ListSmartCardReaders(Memo: TMemo); +var + hContext: cardinal; + Readers: PChar; + ReaderList: TStringList; + ReaderListSize: integer; + Res: LongInt; + PtrReader: PChar; + qt:LongInt; +begin + Memo.Clear; // Limpa o memo antes de adicionar os leitores + Readers := nil; + ReaderListSize := 0; + ReaderList := TStringList.Create; + + try + // Estabelece o contexto para comunicação com o gerenciador de smartcard + Res := SCardEstablishContext(SCARD_SCOPE_USER, nil, nil, @hContext); + if Res <> SCARD_S_SUCCESS then + begin + Memo.Lines.Add('Erro ao estabelecer contexto: ' + IntToStr(Res)); + Exit; + end; + + // Obtém o tamanho necessário para armazenar os leitores + Res := SCardListReadersW(hContext, nil,nil, ReaderListSize); +// RetVar := SCardListReadersA(FContext, nil, nil, ReaderListSize); + if (Res <> SCARD_S_SUCCESS) or (ReaderListSize = 0) then + begin + Memo.Lines.Add('Nenhum leitor encontrado ou erro: ' + IntToStr(Res)); + Exit; + end; + + // Aloca espaço para armazenar a lista de leitores + GetMem(Readers, ReaderListSize); + + try + // Obtém a lista de leitores + Res := SCardListReadersW(hContext, nil, Pointer(Readers), ReaderListSize); +// SCardListReadersA(FContext, nil, Pointer(ReaderList), ReaderListSize); + if Res <> SCARD_S_SUCCESS then + begin + Memo.Lines.Add('Erro ao listar leitores: ' + IntToStr(Res)); + Exit; + end; + + // Adiciona os leitores à lista + PtrReader := Readers; + while PtrReader^ <> #0 do + begin + ReaderList.Add(PtrReader); + Inc(PtrReader, StrLen(PtrReader) + 1); + end; + + // Exibe os leitores no TMemo + Memo.Lines.AddStrings(ReaderList); + finally + FreeMem(Readers); + end; + + finally + // Libera o contexto + SCardReleaseContext(hContext); + ReaderList.Free; + end; +end; + +function Hex2Bin(input: string): string; +var +hex, output: string; +loop : integer; +begin + for loop := 1 to Length(input) do if Pos(input[loop], hexchars) > 0 then hex := hex + AnsiUpperCase(input[loop]); + loop := 1; + if Length(hex) > 0 then + repeat + output := output + Chr(StrToInt('$'+Copy(hex,loop,2))); + loop := loop + 2; + until loop > Length(hex); + Result := output; +end; + +function Bin2HexExt(const input:string; const spaces, upcase: boolean): string; +var + loop : integer; + hexresult : string; +begin + hexresult := ''; + for loop := 1 to Length(input) do + begin + hexresult := hexresult + IntToHex(Ord(input[loop]),2); + if spaces then hexresult := hexresult + ' '; + end; + if upcase then result := AnsiUpperCase(hexresult) + else result := AnsiLowerCase(hexresult); +end; + +procedure TForm1.ShowData; +begin +label3.caption := IntToHex(pcsc.ReaderState,8); +label4.caption := pcsc.AttrICCType; +label5.caption := pcsc.AttrVendorName; +label6.caption := pcsc.AttrVendorSerial; +label14.caption := IntToHex(pcsc.AttrProtocol,8); +//memo1.Lines.Add('ATR:'+Bin2HexExt(pcsc.AttrCardATR,false,true)); +end; + +procedure TForm1.pcscCardRemoved(Sender: TObject); +begin +memo1.Lines.Add('OnCardRemoved'); +ShowData; +end; + +procedure TForm1.pcscError(Sender: TObject; ErrSource: TErrSource; ErrCode: Cardinal); +begin +if memo1.Lines[memo1.Lines.Count-1]='OnError ' + IntToHex(ErrCode,8) then exit; +memo1.Lines.Add('OnError ' + IntToHex(ErrCode,8)); +label1.caption := IntToHex(ErrCode,8); +ShowData; +end; + +function AnsiToWide(const AnsiStr: AnsiString; CodePage: Cardinal = CP_ACP ): WideString; +var + Len: Integer; +begin + Len := MultiByteToWideChar(CodePage, 0, PAnsiChar(AnsiStr), -1, nil, 0); + SetLength(Result, Len - 1); + MultiByteToWideChar(CodePage, 0, PAnsiChar(AnsiStr), -1, PWideChar(Result), Len); +end; + +procedure TForm1.bt_InitClick(Sender: TObject); +var i:integer; +begin +pcsc.Init; +pcsc.UseReaderNum := 0; +end; + + +procedure TForm1.bt_OpenClick(Sender: TObject); +begin +if pcsc.Open then memo1.lines.add('OPEN: OK') + else memo1.lines.add('OPEN: NOT OK'); +end; + +procedure TForm1.bt_ConnectClick(Sender: TObject); +begin +if pcsc.Connect then memo1.lines.add('CONNECT to ''' + IntToStr(pcsc.UseReaderNum) + ''' : OK') + else memo1.lines.add('CONNECT to ''' + IntToStr(pcsc.UseReaderNum) + ''' : NOT OK'); +end; + +procedure TForm1.bt_CloseClick(Sender: TObject); +begin +pcsc.Close; +end; + +procedure TForm1.bt_DisconnectClick(Sender: TObject); +begin +pcsc.Disconnect; +end; + +procedure TForm1.bt_SendClick(Sender: TObject); +begin + label2.caption := Bin2HexExt(pcsc.GetResponseFromCard(Hex2Bin('a0f2000016')), true, true); +end; + +procedure TForm1.Button1Click(Sender: TObject); +var i:integer; +begin + memo1.Lines.Add(inttostr(pcsc.ReaderList.Count)); + for i:=0 to pcsc.ReaderList.Count-1 do begin + memo1.Lines.Add(inttostr(i)+':'+pcsc.ReaderList[i]); + end; +end; + +procedure TForm1.pcscCardActive(Sender: TObject); +begin +memo1.Lines.Add('OnCardActive'); +ShowData; +end; + +procedure TForm1.pcscCardInserted(Sender: TObject); +begin +memo1.Lines.Add('OnCardInserted'); +ShowData; +end; + +procedure TForm1.pcscCardInvalid(Sender: TObject); +begin +memo1.Lines.Add('OnCardInvalid'); +ShowData; +end; + +procedure TForm1.pcscReaderConnect(Sender: TObject); +begin +memo1.Lines.Add('OnReaderConnect'); +ShowData; +end; + +procedure TForm1.pcscReaderDisconnect(Sender: TObject); +begin +memo1.Lines.Add('OnReaderDisconnect'); +ShowData; +end; + +procedure TForm1.pcscReaderListChange(Sender: TObject); +begin +memo1.Lines.Add('OnReaderListChange'); +end; + +procedure TForm1.pcscReaderWaiting(Sender: TObject); +begin +memo1.Lines.Add('OnReaderWaiting'); +end; + +end. + diff --git a/__history/FirstTest.pas.~58~ b/__history/FirstTest.pas.~58~ new file mode 100644 index 0000000..5dd44cd --- /dev/null +++ b/__history/FirstTest.pas.~58~ @@ -0,0 +1,283 @@ +unit FirstTest; + +interface + +uses + Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, WinSCard, WinSmCrd, SCardErr, + StdCtrls, PCSCConnector; + +type + TForm1 = class(TForm) + pcsc: TPCSCConnector; + Label1: TLabel; + Label2: TLabel; + Label3: TLabel; + Label4: TLabel; + Label5: TLabel; + Label6: TLabel; + bt_Init: TButton; + bt_Open: TButton; + bt_Connect: TButton; + bt_Close: TButton; + bt_Disconnect: TButton; + Label7: TLabel; + Label8: TLabel; + Label9: TLabel; + Label10: TLabel; + Label11: TLabel; + Label12: TLabel; + bt_Send: TButton; + Memo1: TMemo; + Label13: TLabel; + Label14: TLabel; + Button1: TButton; + procedure pcscCardRemoved(Sender: TObject); + procedure pcscError(Sender: TObject; ErrSource: TErrSource; ErrCode: Cardinal); + procedure ShowData; + procedure bt_InitClick(Sender: TObject); + procedure bt_OpenClick(Sender: TObject); + procedure bt_ConnectClick(Sender: TObject); + procedure bt_CloseClick(Sender: TObject); + procedure bt_DisconnectClick(Sender: TObject); + procedure bt_SendClick(Sender: TObject); + procedure pcscCardActive(Sender: TObject); + procedure pcscCardInserted(Sender: TObject); + procedure pcscCardInvalid(Sender: TObject); + procedure pcscReaderConnect(Sender: TObject); + procedure pcscReaderDisconnect(Sender: TObject); + procedure pcscReaderListChange(Sender: TObject); + procedure pcscReaderWaiting(Sender: TObject); + procedure Button1Click(Sender: TObject); + private + { Private-Deklarationen } + public + { Public-Deklarationen } + end; + +var + Form1: TForm1; + +implementation + +{$R *.DFM} + +const + +HexChars = '0123456789abcdefABCDEF'; + +procedure ListSmartCardReaders(Memo: TMemo); +var + hContext: cardinal; + Readers: PChar; + ReaderList: TStringList; + ReaderListSize: integer; + Res: LongInt; + PtrReader: PChar; + qt:LongInt; +begin + Memo.Clear; // Limpa o memo antes de adicionar os leitores + Readers := nil; + ReaderListSize := 0; + ReaderList := TStringList.Create; + + try + // Estabelece o contexto para comunicação com o gerenciador de smartcard + Res := SCardEstablishContext(SCARD_SCOPE_USER, nil, nil, @hContext); + if Res <> SCARD_S_SUCCESS then + begin + Memo.Lines.Add('Erro ao estabelecer contexto: ' + IntToStr(Res)); + Exit; + end; + + // Obtém o tamanho necessário para armazenar os leitores + Res := SCardListReadersW(hContext, nil,nil, ReaderListSize); +// RetVar := SCardListReadersA(FContext, nil, nil, ReaderListSize); + if (Res <> SCARD_S_SUCCESS) or (ReaderListSize = 0) then + begin + Memo.Lines.Add('Nenhum leitor encontrado ou erro: ' + IntToStr(Res)); + Exit; + end; + + // Aloca espaço para armazenar a lista de leitores + GetMem(Readers, ReaderListSize); + + try + // Obtém a lista de leitores + Res := SCardListReadersW(hContext, nil, Pointer(Readers), ReaderListSize); +// SCardListReadersA(FContext, nil, Pointer(ReaderList), ReaderListSize); + if Res <> SCARD_S_SUCCESS then + begin + Memo.Lines.Add('Erro ao listar leitores: ' + IntToStr(Res)); + Exit; + end; + + // Adiciona os leitores à lista + PtrReader := Readers; + while PtrReader^ <> #0 do + begin + ReaderList.Add(PtrReader); + Inc(PtrReader, StrLen(PtrReader) + 1); + end; + + // Exibe os leitores no TMemo + Memo.Lines.AddStrings(ReaderList); + finally + FreeMem(Readers); + end; + + finally + // Libera o contexto + SCardReleaseContext(hContext); + ReaderList.Free; + end; +end; + +function Hex2Bin(input: string): string; +var +hex, output: string; +loop : integer; +begin + for loop := 1 to Length(input) do if Pos(input[loop], hexchars) > 0 then hex := hex + AnsiUpperCase(input[loop]); + loop := 1; + if Length(hex) > 0 then + repeat + output := output + Chr(StrToInt('$'+Copy(hex,loop,2))); + loop := loop + 2; + until loop > Length(hex); + Result := output; +end; + +function Bin2HexExt(const input:string; const spaces, upcase: boolean): string; +var + loop : integer; + hexresult : string; +begin + hexresult := ''; + for loop := 1 to Length(input) do + begin + hexresult := hexresult + IntToHex(Ord(input[loop]),2); + if spaces then hexresult := hexresult + ' '; + end; + if upcase then result := AnsiUpperCase(hexresult) + else result := AnsiLowerCase(hexresult); +end; + +procedure TForm1.ShowData; +begin +label3.caption := IntToHex(pcsc.ReaderState,8); +label4.caption := pcsc.AttrICCType; +label5.caption := pcsc.AttrVendorName; +label6.caption := pcsc.AttrVendorSerial; +label14.caption := IntToHex(pcsc.AttrProtocol,8); +//memo1.Lines.Add('ATR:'+Bin2HexExt(pcsc.AttrCardATR,false,true)); +end; + +procedure TForm1.pcscCardRemoved(Sender: TObject); +begin +memo1.Lines.Add('OnCardRemoved'); +ShowData; +end; + +procedure TForm1.pcscError(Sender: TObject; ErrSource: TErrSource; ErrCode: Cardinal); +begin +if memo1.Lines[memo1.Lines.Count-1]='OnError ' + IntToHex(ErrCode,8) then exit; +memo1.Lines.Add('OnError ' + IntToHex(ErrCode,8)); +label1.caption := IntToHex(ErrCode,8); +ShowData; +end; + +function AnsiToWide(const AnsiStr: AnsiString; CodePage: Cardinal = CP_ACP ): WideString; +var + Len: Integer; +begin + Len := MultiByteToWideChar(CodePage, 0, PAnsiChar(AnsiStr), -1, nil, 0); + SetLength(Result, Len - 1); + MultiByteToWideChar(CodePage, 0, PAnsiChar(AnsiStr), -1, PWideChar(Result), Len); +end; + +procedure TForm1.bt_InitClick(Sender: TObject); +var i:integer; +begin +pcsc.Init; +pcsc.UseReaderNum := 0; +end; + + +procedure TForm1.bt_OpenClick(Sender: TObject); +begin +if pcsc.Open then memo1.lines.add('OPEN: OK') + else memo1.lines.add('OPEN: NOT OK'); +end; + +procedure TForm1.bt_ConnectClick(Sender: TObject); +begin +if pcsc.Connect then memo1.lines.add('CONNECT to ''' + IntToStr(pcsc.UseReaderNum) + ''' : OK') + else memo1.lines.add('CONNECT to ''' + IntToStr(pcsc.UseReaderNum) + ''' : NOT OK'); +end; + +procedure TForm1.bt_CloseClick(Sender: TObject); +begin +pcsc.Close; +end; + +procedure TForm1.bt_DisconnectClick(Sender: TObject); +begin +pcsc.Disconnect; +end; + +procedure TForm1.bt_SendClick(Sender: TObject); +begin + label2.caption := Bin2HexExt(pcsc.GetResponseFromCard(Hex2Bin('a0f2000016')), true, true); +end; + +procedure TForm1.Button1Click(Sender: TObject); +var i:integer; +begin + memo1.Lines.Add(inttostr(pcsc.ReaderList.Count)); + for i:=0 to pcsc.ReaderList.Count-1 do begin + memo1.Lines.Add(inttostr(i)+':'+pcsc.ReaderList[i]); + end; +end; + +procedure TForm1.pcscCardActive(Sender: TObject); +begin + memo1.Lines.Add('OnCardActive'); + ShowData; +end; + +procedure TForm1.pcscCardInserted(Sender: TObject); +begin +memo1.Lines.Add('OnCardInserted'); +ShowData; +end; + +procedure TForm1.pcscCardInvalid(Sender: TObject); +begin +memo1.Lines.Add('OnCardInvalid'); +ShowData; +end; + +procedure TForm1.pcscReaderConnect(Sender: TObject); +begin +memo1.Lines.Add('OnReaderConnect'); +ShowData; +end; + +procedure TForm1.pcscReaderDisconnect(Sender: TObject); +begin +memo1.Lines.Add('OnReaderDisconnect'); +ShowData; +end; + +procedure TForm1.pcscReaderListChange(Sender: TObject); +begin +memo1.Lines.Add('OnReaderListChange'); +end; + +procedure TForm1.pcscReaderWaiting(Sender: TObject); +begin +memo1.Lines.Add('OnReaderWaiting'); +end; + +end. + diff --git a/__history/FirstTest.pas.~59~ b/__history/FirstTest.pas.~59~ new file mode 100644 index 0000000..13d5df5 --- /dev/null +++ b/__history/FirstTest.pas.~59~ @@ -0,0 +1,283 @@ +unit FirstTest; + +interface + +uses + Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, WinSCard, WinSmCrd, SCardErr, + StdCtrls, PCSCConnector; + +type + TForm1 = class(TForm) + pcsc: TPCSCConnector; + Label1: TLabel; + Label2: TLabel; + Label3: TLabel; + Label4: TLabel; + Label5: TLabel; + Label6: TLabel; + bt_Init: TButton; + bt_Open: TButton; + bt_Connect: TButton; + bt_Close: TButton; + bt_Disconnect: TButton; + Label7: TLabel; + Label8: TLabel; + Label9: TLabel; + Label10: TLabel; + Label11: TLabel; + Label12: TLabel; + bt_Send: TButton; + Memo1: TMemo; + Label13: TLabel; + Label14: TLabel; + Button1: TButton; + procedure pcscCardRemoved(Sender: TObject); + procedure pcscError(Sender: TObject; ErrSource: TErrSource; ErrCode: Cardinal); + procedure ShowData; + procedure bt_InitClick(Sender: TObject); + procedure bt_OpenClick(Sender: TObject); + procedure bt_ConnectClick(Sender: TObject); + procedure bt_CloseClick(Sender: TObject); + procedure bt_DisconnectClick(Sender: TObject); + procedure bt_SendClick(Sender: TObject); + procedure pcscCardActive(Sender: TObject); + procedure pcscCardInserted(Sender: TObject); + procedure pcscCardInvalid(Sender: TObject); + procedure pcscReaderConnect(Sender: TObject); + procedure pcscReaderDisconnect(Sender: TObject); + procedure pcscReaderListChange(Sender: TObject); + procedure pcscReaderWaiting(Sender: TObject); + procedure Button1Click(Sender: TObject); + private + { Private-Deklarationen } + public + { Public-Deklarationen } + end; + +var + Form1: TForm1; + +implementation + +{$R *.DFM} + +const + +HexChars = '0123456789abcdefABCDEF'; + +procedure ListSmartCardReaders(Memo: TMemo); +var + hContext: cardinal; + Readers: PChar; + ReaderList: TStringList; + ReaderListSize: integer; + Res: LongInt; + PtrReader: PChar; + qt:LongInt; +begin + Memo.Clear; // Limpa o memo antes de adicionar os leitores + Readers := nil; + ReaderListSize := 0; + ReaderList := TStringList.Create; + + try + // Estabelece o contexto para comunicação com o gerenciador de smartcard + Res := SCardEstablishContext(SCARD_SCOPE_USER, nil, nil, @hContext); + if Res <> SCARD_S_SUCCESS then + begin + Memo.Lines.Add('Erro ao estabelecer contexto: ' + IntToStr(Res)); + Exit; + end; + + // Obtém o tamanho necessário para armazenar os leitores + Res := SCardListReadersW(hContext, nil,nil, ReaderListSize); +// RetVar := SCardListReadersA(FContext, nil, nil, ReaderListSize); + if (Res <> SCARD_S_SUCCESS) or (ReaderListSize = 0) then + begin + Memo.Lines.Add('Nenhum leitor encontrado ou erro: ' + IntToStr(Res)); + Exit; + end; + + // Aloca espaço para armazenar a lista de leitores + GetMem(Readers, ReaderListSize); + + try + // Obtém a lista de leitores + Res := SCardListReadersW(hContext, nil, Pointer(Readers), ReaderListSize); +// SCardListReadersA(FContext, nil, Pointer(ReaderList), ReaderListSize); + if Res <> SCARD_S_SUCCESS then + begin + Memo.Lines.Add('Erro ao listar leitores: ' + IntToStr(Res)); + Exit; + end; + + // Adiciona os leitores à lista + PtrReader := Readers; + while PtrReader^ <> #0 do + begin + ReaderList.Add(PtrReader); + Inc(PtrReader, StrLen(PtrReader) + 1); + end; + + // Exibe os leitores no TMemo + Memo.Lines.AddStrings(ReaderList); + finally + FreeMem(Readers); + end; + + finally + // Libera o contexto + SCardReleaseContext(hContext); + ReaderList.Free; + end; +end; + +function Hex2Bin(input: string): string; +var +hex, output: string; +loop : integer; +begin + for loop := 1 to Length(input) do if Pos(input[loop], hexchars) > 0 then hex := hex + AnsiUpperCase(input[loop]); + loop := 1; + if Length(hex) > 0 then + repeat + output := output + Chr(StrToInt('$'+Copy(hex,loop,2))); + loop := loop + 2; + until loop > Length(hex); + Result := output; +end; + +function Bin2HexExt(const input:string; const spaces, upcase: boolean): string; +var + loop : integer; + hexresult : string; +begin + hexresult := ''; + for loop := 1 to Length(input) do + begin + hexresult := hexresult + IntToHex(Ord(input[loop]),2); + if spaces then hexresult := hexresult + ' '; + end; + if upcase then result := AnsiUpperCase(hexresult) + else result := AnsiLowerCase(hexresult); +end; + +function AnsiToWide(const AnsiStr: AnsiString; CodePage: Cardinal = CP_ACP ): WideString; +var + Len: Integer; +begin + Len := MultiByteToWideChar(CodePage, 0, PAnsiChar(AnsiStr), -1, nil, 0); + SetLength(Result, Len - 1); + MultiByteToWideChar(CodePage, 0, PAnsiChar(AnsiStr), -1, PWideChar(Result), Len); +end; +procedure TForm1.ShowData; +begin +label3.caption := IntToHex(pcsc.ReaderState,8); +label4.caption := pcsc.AttrICCType; +label5.caption := pcsc.AttrVendorName; +label6.caption := pcsc.AttrVendorSerial; +label14.caption := IntToHex(pcsc.AttrProtocol,8); +//memo1.Lines.Add('ATR:'+Bin2HexExt(pcsc.AttrCardATR,false,true)); +end; + +procedure TForm1.pcscCardRemoved(Sender: TObject); +begin +memo1.Lines.Add('OnCardRemoved'); +ShowData; +end; + +procedure TForm1.pcscError(Sender: TObject; ErrSource: TErrSource; ErrCode: Cardinal); +begin +if memo1.Lines[memo1.Lines.Count-1]='OnError ' + IntToHex(ErrCode,8) then exit; +memo1.Lines.Add('OnError ' + IntToHex(ErrCode,8)); +label1.caption := IntToHex(ErrCode,8); +ShowData; +end; + + +procedure TForm1.bt_InitClick(Sender: TObject); +var i:integer; +begin +pcsc.Init; +pcsc.UseReaderNum := 0; +end; + + +procedure TForm1.bt_OpenClick(Sender: TObject); +begin +if pcsc.Open then memo1.lines.add('OPEN: OK') + else memo1.lines.add('OPEN: NOT OK'); +end; + +procedure TForm1.bt_ConnectClick(Sender: TObject); +begin +if pcsc.Connect then memo1.lines.add('CONNECT to ''' + IntToStr(pcsc.UseReaderNum) + ''' : OK') + else memo1.lines.add('CONNECT to ''' + IntToStr(pcsc.UseReaderNum) + ''' : NOT OK'); +end; + +procedure TForm1.bt_CloseClick(Sender: TObject); +begin +pcsc.Close; +end; + +procedure TForm1.bt_DisconnectClick(Sender: TObject); +begin +pcsc.Disconnect; +end; + +procedure TForm1.bt_SendClick(Sender: TObject); +begin + label2.caption := Bin2HexExt(pcsc.GetResponseFromCard(Hex2Bin('a0f2000016')), true, true); +end; + +procedure TForm1.Button1Click(Sender: TObject); +var i:integer; +begin + memo1.Lines.Add(inttostr(pcsc.ReaderList.Count)); + for i:=0 to pcsc.ReaderList.Count-1 do begin + memo1.Lines.Add(inttostr(i)+':'+pcsc.ReaderList[i]); + end; +end; + +procedure TForm1.pcscCardActive(Sender: TObject); +begin + memo1.Lines.Add('OnCardActive'); + ShowData; +end; + +procedure TForm1.pcscCardInserted(Sender: TObject); +begin +memo1.Lines.Add('OnCardInserted'); +ShowData; +end; + +procedure TForm1.pcscCardInvalid(Sender: TObject); +begin +memo1.Lines.Add('OnCardInvalid'); +ShowData; +end; + +procedure TForm1.pcscReaderConnect(Sender: TObject); +begin +memo1.Lines.Add('OnReaderConnect'); +ShowData; +end; + +procedure TForm1.pcscReaderDisconnect(Sender: TObject); +begin +memo1.Lines.Add('OnReaderDisconnect'); +ShowData; +end; + +procedure TForm1.pcscReaderListChange(Sender: TObject); +begin +memo1.Lines.Add('OnReaderListChange'); +end; + +procedure TForm1.pcscReaderWaiting(Sender: TObject); +begin +memo1.Lines.Add('OnReaderWaiting'); +end; + +end. + diff --git a/__history/FirstTest.pas.~60~ b/__history/FirstTest.pas.~60~ new file mode 100644 index 0000000..7d91346 --- /dev/null +++ b/__history/FirstTest.pas.~60~ @@ -0,0 +1,284 @@ +unit FirstTest; + +interface + +uses + Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, WinSCard, WinSmCrd, SCardErr, + StdCtrls, PCSCConnector; + +type + TForm1 = class(TForm) + pcsc: TPCSCConnector; + Label1: TLabel; + Label2: TLabel; + Label3: TLabel; + Label4: TLabel; + Label5: TLabel; + Label6: TLabel; + bt_Init: TButton; + bt_Open: TButton; + bt_Connect: TButton; + bt_Close: TButton; + bt_Disconnect: TButton; + Label7: TLabel; + Label8: TLabel; + Label9: TLabel; + Label10: TLabel; + Label11: TLabel; + Label12: TLabel; + bt_Send: TButton; + Memo1: TMemo; + Label13: TLabel; + Label14: TLabel; + Button1: TButton; + procedure pcscCardRemoved(Sender: TObject); + procedure pcscError(Sender: TObject; ErrSource: TErrSource; ErrCode: Cardinal); + procedure ShowData; + procedure bt_InitClick(Sender: TObject); + procedure bt_OpenClick(Sender: TObject); + procedure bt_ConnectClick(Sender: TObject); + procedure bt_CloseClick(Sender: TObject); + procedure bt_DisconnectClick(Sender: TObject); + procedure bt_SendClick(Sender: TObject); + procedure pcscCardActive(Sender: TObject); + procedure pcscCardInserted(Sender: TObject); + procedure pcscCardInvalid(Sender: TObject); + procedure pcscReaderConnect(Sender: TObject); + procedure pcscReaderDisconnect(Sender: TObject); + procedure pcscReaderListChange(Sender: TObject); + procedure pcscReaderWaiting(Sender: TObject); + procedure Button1Click(Sender: TObject); + private + { Private-Deklarationen } + public + { Public-Deklarationen } + end; + +var + Form1: TForm1; + +implementation + +{$R *.DFM} + +const + +HexChars = '0123456789abcdefABCDEF'; + +procedure ListSmartCardReaders(Memo: TMemo); +var + hContext: cardinal; + Readers: PChar; + ReaderList: TStringList; + ReaderListSize: integer; + Res: LongInt; + PtrReader: PChar; + qt:LongInt; +begin + Memo.Clear; // Limpa o memo antes de adicionar os leitores + Readers := nil; + ReaderListSize := 0; + ReaderList := TStringList.Create; + + try + // Estabelece o contexto para comunicação com o gerenciador de smartcard + Res := SCardEstablishContext(SCARD_SCOPE_USER, nil, nil, @hContext); + if Res <> SCARD_S_SUCCESS then + begin + Memo.Lines.Add('Erro ao estabelecer contexto: ' + IntToStr(Res)); + Exit; + end; + + // Obtém o tamanho necessário para armazenar os leitores + Res := SCardListReadersW(hContext, nil,nil, ReaderListSize); +// RetVar := SCardListReadersA(FContext, nil, nil, ReaderListSize); + if (Res <> SCARD_S_SUCCESS) or (ReaderListSize = 0) then + begin + Memo.Lines.Add('Nenhum leitor encontrado ou erro: ' + IntToStr(Res)); + Exit; + end; + + // Aloca espaço para armazenar a lista de leitores + GetMem(Readers, ReaderListSize); + + try + // Obtém a lista de leitores + Res := SCardListReadersW(hContext, nil, Pointer(Readers), ReaderListSize); +// SCardListReadersA(FContext, nil, Pointer(ReaderList), ReaderListSize); + if Res <> SCARD_S_SUCCESS then + begin + Memo.Lines.Add('Erro ao listar leitores: ' + IntToStr(Res)); + Exit; + end; + + // Adiciona os leitores à lista + PtrReader := Readers; + while PtrReader^ <> #0 do + begin + ReaderList.Add(PtrReader); + Inc(PtrReader, StrLen(PtrReader) + 1); + end; + + // Exibe os leitores no TMemo + Memo.Lines.AddStrings(ReaderList); + finally + FreeMem(Readers); + end; + + finally + // Libera o contexto + SCardReleaseContext(hContext); + ReaderList.Free; + end; +end; + +function Hex2Bin(input: string): string; +var +hex, output: string; +loop : integer; +begin + for loop := 1 to Length(input) do if Pos(input[loop], hexchars) > 0 then hex := hex + AnsiUpperCase(input[loop]); + loop := 1; + if Length(hex) > 0 then + repeat + output := output + Chr(StrToInt('$'+Copy(hex,loop,2))); + loop := loop + 2; + until loop > Length(hex); + Result := output; +end; + +function Bin2HexExt(const input:string; const spaces, upcase: boolean): string; +var + loop : integer; + hexresult : string; +begin + hexresult := ''; + for loop := 1 to Length(input) do + begin + hexresult := hexresult + IntToHex(Ord(input[loop]),2); + if spaces then hexresult := hexresult + ' '; + end; + if upcase then result := AnsiUpperCase(hexresult) + else result := AnsiLowerCase(hexresult); +end; + +function AnsiToWide(const AnsiStr: AnsiString; CodePage: Cardinal = CP_ACP ): WideString; +var + Len: Integer; +begin + Len := MultiByteToWideChar(CodePage, 0, PAnsiChar(AnsiStr), -1, nil, 0); + SetLength(Result, Len - 1); + MultiByteToWideChar(CodePage, 0, PAnsiChar(AnsiStr), -1, PWideChar(Result), Len); +end; + +procedure TForm1.ShowData; +begin +label3.caption := IntToHex(pcsc.ReaderState,8); +label4.caption := pcsc.AttrICCType; +label5.caption := pcsc.AttrVendorName; +label6.caption := pcsc.AttrVendorSerial; +label14.caption := IntToHex(pcsc.AttrProtocol,8); +//memo1.Lines.Add('ATR:'+Bin2HexExt(pcsc.AttrCardATR,false,true)); +end; + +procedure TForm1.pcscCardRemoved(Sender: TObject); +begin +memo1.Lines.Add('OnCardRemoved'); +ShowData; +end; + +procedure TForm1.pcscError(Sender: TObject; ErrSource: TErrSource; ErrCode: Cardinal); +begin +if memo1.Lines[memo1.Lines.Count-1]='OnError ' + IntToHex(ErrCode,8) then exit; +memo1.Lines.Add('OnError ' + IntToHex(ErrCode,8)); +label1.caption := IntToHex(ErrCode,8); +ShowData; +end; + + +procedure TForm1.bt_InitClick(Sender: TObject); +var i:integer; +begin +pcsc.Init; +pcsc.UseReaderNum := 0; +end; + + +procedure TForm1.bt_OpenClick(Sender: TObject); +begin +if pcsc.Open then memo1.lines.add('OPEN: OK') + else memo1.lines.add('OPEN: NOT OK'); +end; + +procedure TForm1.bt_ConnectClick(Sender: TObject); +begin +if pcsc.Connect then memo1.lines.add('CONNECT to ''' + IntToStr(pcsc.UseReaderNum) + ''' : OK') + else memo1.lines.add('CONNECT to ''' + IntToStr(pcsc.UseReaderNum) + ''' : NOT OK'); +end; + +procedure TForm1.bt_CloseClick(Sender: TObject); +begin +pcsc.Close; +end; + +procedure TForm1.bt_DisconnectClick(Sender: TObject); +begin +pcsc.Disconnect; +end; + +procedure TForm1.bt_SendClick(Sender: TObject); +begin + label2.caption := Bin2HexExt(pcsc.GetResponseFromCard(Hex2Bin('a0f2000016')), true, true); +end; + +procedure TForm1.Button1Click(Sender: TObject); +var i:integer; +begin + memo1.Lines.Add(inttostr(pcsc.ReaderList.Count)); + for i:=0 to pcsc.ReaderList.Count-1 do begin + memo1.Lines.Add(inttostr(i)+':'+pcsc.ReaderList[i]); + end; +end; + +procedure TForm1.pcscCardActive(Sender: TObject); +begin + memo1.Lines.Add('OnCardActive'); + ShowData; +end; + +procedure TForm1.pcscCardInserted(Sender: TObject); +begin +memo1.Lines.Add('OnCardInserted'); +ShowData; +end; + +procedure TForm1.pcscCardInvalid(Sender: TObject); +begin +memo1.Lines.Add('OnCardInvalid'); +ShowData; +end; + +procedure TForm1.pcscReaderConnect(Sender: TObject); +begin +memo1.Lines.Add('OnReaderConnect'); +ShowData; +end; + +procedure TForm1.pcscReaderDisconnect(Sender: TObject); +begin +memo1.Lines.Add('OnReaderDisconnect'); +ShowData; +end; + +procedure TForm1.pcscReaderListChange(Sender: TObject); +begin +memo1.Lines.Add('OnReaderListChange'); +end; + +procedure TForm1.pcscReaderWaiting(Sender: TObject); +begin +memo1.Lines.Add('OnReaderWaiting'); +end; + +end. + diff --git a/__history/FirstTest.pas.~61~ b/__history/FirstTest.pas.~61~ new file mode 100644 index 0000000..a96ec2d --- /dev/null +++ b/__history/FirstTest.pas.~61~ @@ -0,0 +1,284 @@ +unit FirstTest; + +interface + +uses + Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, WinSCard, WinSmCrd, SCardErr, + StdCtrls, PCSCConnector; + +type + TForm1 = class(TForm) + pcsc: TPCSCConnector; + Label1: TLabel; + Label2: TLabel; + Label3: TLabel; + Label4: TLabel; + Label5: TLabel; + Label6: TLabel; + bt_Init: TButton; + bt_Open: TButton; + bt_Connect: TButton; + bt_Close: TButton; + bt_Disconnect: TButton; + Label7: TLabel; + Label8: TLabel; + Label9: TLabel; + Label10: TLabel; + Label11: TLabel; + Label12: TLabel; + bt_Send: TButton; + Memo1: TMemo; + Label13: TLabel; + Label14: TLabel; + Button1: TButton; + procedure pcscCardRemoved(Sender: TObject); + procedure pcscError(Sender: TObject; ErrSource: TErrSource; ErrCode: Cardinal); + procedure ShowData; + procedure bt_InitClick(Sender: TObject); + procedure bt_OpenClick(Sender: TObject); + procedure bt_ConnectClick(Sender: TObject); + procedure bt_CloseClick(Sender: TObject); + procedure bt_DisconnectClick(Sender: TObject); + procedure bt_SendClick(Sender: TObject); + procedure pcscCardActive(Sender: TObject); + procedure pcscCardInserted(Sender: TObject); + procedure pcscCardInvalid(Sender: TObject); + procedure pcscReaderConnect(Sender: TObject); + procedure pcscReaderDisconnect(Sender: TObject); + procedure pcscReaderListChange(Sender: TObject); + procedure pcscReaderWaiting(Sender: TObject); + procedure Button1Click(Sender: TObject); + private + { Private-Deklarationen } + public + { Public-Deklarationen } + end; + +var + Form1: TForm1; + +implementation + +{$R *.DFM} + +const + +HexChars = '0123456789abcdefABCDEF'; + +procedure ListSmartCardReaders(Memo: TMemo); +var + hContext: cardinal; + Readers: PChar; + ReaderList: TStringList; + ReaderListSize: integer; + Res: LongInt; + PtrReader: PChar; + qt:LongInt; +begin + Memo.Clear; // Limpa o memo antes de adicionar os leitores + Readers := nil; + ReaderListSize := 0; + ReaderList := TStringList.Create; + + try + // Estabelece o contexto para comunicação com o gerenciador de smartcard + Res := SCardEstablishContext(SCARD_SCOPE_USER, nil, nil, @hContext); + if Res <> SCARD_S_SUCCESS then + begin + Memo.Lines.Add('Erro ao estabelecer contexto: ' + IntToStr(Res)); + Exit; + end; + + // Obtém o tamanho necessário para armazenar os leitores + Res := SCardListReadersW(hContext, nil,nil, ReaderListSize); +// RetVar := SCardListReadersA(FContext, nil, nil, ReaderListSize); + if (Res <> SCARD_S_SUCCESS) or (ReaderListSize = 0) then + begin + Memo.Lines.Add('Nenhum leitor encontrado ou erro: ' + IntToStr(Res)); + Exit; + end; + + // Aloca espaço para armazenar a lista de leitores + GetMem(Readers, ReaderListSize); + + try + // Obtém a lista de leitores + Res := SCardListReadersW(hContext, nil, Pointer(Readers), ReaderListSize); +// SCardListReadersA(FContext, nil, Pointer(ReaderList), ReaderListSize); + if Res <> SCARD_S_SUCCESS then + begin + Memo.Lines.Add('Erro ao listar leitores: ' + IntToStr(Res)); + Exit; + end; + + // Adiciona os leitores à lista + PtrReader := Readers; + while PtrReader^ <> #0 do + begin + ReaderList.Add(PtrReader); + Inc(PtrReader, StrLen(PtrReader) + 1); + end; + + // Exibe os leitores no TMemo + Memo.Lines.AddStrings(ReaderList); + finally + FreeMem(Readers); + end; + + finally + // Libera o contexto + SCardReleaseContext(hContext); + ReaderList.Free; + end; +end; + +function Hex2Bin(input: string): string; +var +hex, output: string; +loop : integer; +begin + for loop := 1 to Length(input) do if Pos(input[loop], hexchars) > 0 then hex := hex + AnsiUpperCase(input[loop]); + loop := 1; + if Length(hex) > 0 then + repeat + output := output + Chr(StrToInt('$'+Copy(hex,loop,2))); + loop := loop + 2; + until loop > Length(hex); + Result := output; +end; + +function Bin2HexExt(const input:string; const spaces, upcase: boolean): string; +var + loop : integer; + hexresult : string; +begin + hexresult := ''; + for loop := 1 to Length(input) do + begin + hexresult := hexresult + IntToHex(Ord(input[loop]),2); + if spaces then hexresult := hexresult + ' '; + end; + if upcase then result := AnsiUpperCase(hexresult) + else result := AnsiLowerCase(hexresult); +end; + +function AnsiToWide(const AnsiStr: AnsiString; CodePage: Cardinal = CP_ACP ): WideString; +var + Len: Integer; +begin + Len := MultiByteToWideChar(CodePage, 0, PAnsiChar(AnsiStr), -1, nil, 0); + SetLength(Result, Len - 1); + MultiByteToWideChar(CodePage, 0, PAnsiChar(AnsiStr), -1, PWideChar(Result), Len); +end; + +procedure TForm1.ShowData; +begin +label3.caption := IntToHex(pcsc.ReaderState,8); +label4.caption := pcsc.AttrICCType; +label5.caption := pcsc.AttrVendorName; +label6.caption := pcsc.AttrVendorSerial; +label14.caption := IntToHex(pcsc.AttrProtocol,8); +memo1.Lines.Add('ATR:'+Bin2HexExt(pcsc.AttrCardATR,false,true)); +end; + +procedure TForm1.pcscCardRemoved(Sender: TObject); +begin +memo1.Lines.Add('OnCardRemoved'); +ShowData; +end; + +procedure TForm1.pcscError(Sender: TObject; ErrSource: TErrSource; ErrCode: Cardinal); +begin +if memo1.Lines[memo1.Lines.Count-1]='OnError ' + IntToHex(ErrCode,8) then exit; +memo1.Lines.Add('OnError ' + IntToHex(ErrCode,8)); +label1.caption := IntToHex(ErrCode,8); +ShowData; +end; + + +procedure TForm1.bt_InitClick(Sender: TObject); +var i:integer; +begin +pcsc.Init; +pcsc.UseReaderNum := 0; +end; + + +procedure TForm1.bt_OpenClick(Sender: TObject); +begin +if pcsc.Open then memo1.lines.add('OPEN: OK') + else memo1.lines.add('OPEN: NOT OK'); +end; + +procedure TForm1.bt_ConnectClick(Sender: TObject); +begin +if pcsc.Connect then memo1.lines.add('CONNECT to ''' + IntToStr(pcsc.UseReaderNum) + ''' : OK') + else memo1.lines.add('CONNECT to ''' + IntToStr(pcsc.UseReaderNum) + ''' : NOT OK'); +end; + +procedure TForm1.bt_CloseClick(Sender: TObject); +begin +pcsc.Close; +end; + +procedure TForm1.bt_DisconnectClick(Sender: TObject); +begin +pcsc.Disconnect; +end; + +procedure TForm1.bt_SendClick(Sender: TObject); +begin + label2.caption := Bin2HexExt(pcsc.GetResponseFromCard(Hex2Bin('a0f2000016')), true, true); +end; + +procedure TForm1.Button1Click(Sender: TObject); +var i:integer; +begin + memo1.Lines.Add(inttostr(pcsc.ReaderList.Count)); + for i:=0 to pcsc.ReaderList.Count-1 do begin + memo1.Lines.Add(inttostr(i)+':'+pcsc.ReaderList[i]); + end; +end; + +procedure TForm1.pcscCardActive(Sender: TObject); +begin + memo1.Lines.Add('OnCardActive'); + ShowData; +end; + +procedure TForm1.pcscCardInserted(Sender: TObject); +begin +memo1.Lines.Add('OnCardInserted'); +ShowData; +end; + +procedure TForm1.pcscCardInvalid(Sender: TObject); +begin +memo1.Lines.Add('OnCardInvalid'); +ShowData; +end; + +procedure TForm1.pcscReaderConnect(Sender: TObject); +begin +memo1.Lines.Add('OnReaderConnect'); +ShowData; +end; + +procedure TForm1.pcscReaderDisconnect(Sender: TObject); +begin +memo1.Lines.Add('OnReaderDisconnect'); +ShowData; +end; + +procedure TForm1.pcscReaderListChange(Sender: TObject); +begin +memo1.Lines.Add('OnReaderListChange'); +end; + +procedure TForm1.pcscReaderWaiting(Sender: TObject); +begin +memo1.Lines.Add('OnReaderWaiting'); +end; + +end. + diff --git a/__history/FirstTest.pas.~62~ b/__history/FirstTest.pas.~62~ new file mode 100644 index 0000000..17e7408 --- /dev/null +++ b/__history/FirstTest.pas.~62~ @@ -0,0 +1,284 @@ +unit FirstTest; + +interface + +uses + Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, WinSCard, WinSmCrd, SCardErr, + StdCtrls, PCSCConnector; + +type + TForm1 = class(TForm) + pcsc: TPCSCConnector; + Label1: TLabel; + Label2: TLabel; + Label3: TLabel; + Label4: TLabel; + Label5: TLabel; + Label6: TLabel; + bt_Init: TButton; + bt_Open: TButton; + bt_Connect: TButton; + bt_Close: TButton; + bt_Disconnect: TButton; + Label7: TLabel; + Label8: TLabel; + Label9: TLabel; + Label10: TLabel; + Label11: TLabel; + Label12: TLabel; + bt_Send: TButton; + Memo1: TMemo; + Label13: TLabel; + Label14: TLabel; + Button1: TButton; + procedure pcscCardRemoved(Sender: TObject); + procedure pcscError(Sender: TObject; ErrSource: TErrSource; ErrCode: Cardinal); + procedure ShowData; + procedure bt_InitClick(Sender: TObject); + procedure bt_OpenClick(Sender: TObject); + procedure bt_ConnectClick(Sender: TObject); + procedure bt_CloseClick(Sender: TObject); + procedure bt_DisconnectClick(Sender: TObject); + procedure bt_SendClick(Sender: TObject); + procedure pcscCardActive(Sender: TObject); + procedure pcscCardInserted(Sender: TObject); + procedure pcscCardInvalid(Sender: TObject); + procedure pcscReaderConnect(Sender: TObject); + procedure pcscReaderDisconnect(Sender: TObject); + procedure pcscReaderListChange(Sender: TObject); + procedure pcscReaderWaiting(Sender: TObject); + procedure Button1Click(Sender: TObject); + private + { Private-Deklarationen } + public + { Public-Deklarationen } + end; + +var + Form1: TForm1; + +implementation + +{$R *.DFM} + +const + +HexChars = '0123456789abcdefABCDEF'; + +procedure ListSmartCardReaders(Memo: TMemo); +var + hContext: cardinal; + Readers: PChar; + ReaderList: TStringList; + ReaderListSize: integer; + Res: LongInt; + PtrReader: PChar; + qt:LongInt; +begin + Memo.Clear; // Limpa o memo antes de adicionar os leitores + Readers := nil; + ReaderListSize := 0; + ReaderList := TStringList.Create; + + try + // Estabelece o contexto para comunicação com o gerenciador de smartcard + Res := SCardEstablishContext(SCARD_SCOPE_USER, nil, nil, @hContext); + if Res <> SCARD_S_SUCCESS then + begin + Memo.Lines.Add('Erro ao estabelecer contexto: ' + IntToStr(Res)); + Exit; + end; + + // Obtém o tamanho necessário para armazenar os leitores + Res := SCardListReadersW(hContext, nil,nil, ReaderListSize); +// RetVar := SCardListReadersA(FContext, nil, nil, ReaderListSize); + if (Res <> SCARD_S_SUCCESS) or (ReaderListSize = 0) then + begin + Memo.Lines.Add('Nenhum leitor encontrado ou erro: ' + IntToStr(Res)); + Exit; + end; + + // Aloca espaço para armazenar a lista de leitores + GetMem(Readers, ReaderListSize); + + try + // Obtém a lista de leitores + Res := SCardListReadersW(hContext, nil, Pointer(Readers), ReaderListSize); +// SCardListReadersA(FContext, nil, Pointer(ReaderList), ReaderListSize); + if Res <> SCARD_S_SUCCESS then + begin + Memo.Lines.Add('Erro ao listar leitores: ' + IntToStr(Res)); + Exit; + end; + + // Adiciona os leitores à lista + PtrReader := Readers; + while PtrReader^ <> #0 do + begin + ReaderList.Add(PtrReader); + Inc(PtrReader, StrLen(PtrReader) + 1); + end; + + // Exibe os leitores no TMemo + Memo.Lines.AddStrings(ReaderList); + finally + FreeMem(Readers); + end; + + finally + // Libera o contexto + SCardReleaseContext(hContext); + ReaderList.Free; + end; +end; + +function Hex2Bin(input: string): string; +var +hex, output: string; +loop : integer; +begin + for loop := 1 to Length(input) do if Pos(input[loop], hexchars) > 0 then hex := hex + AnsiUpperCase(input[loop]); + loop := 1; + if Length(hex) > 0 then + repeat + output := output + Chr(StrToInt('$'+Copy(hex,loop,2))); + loop := loop + 2; + until loop > Length(hex); + Result := output; +end; + +function Bin2HexExt(const input:string; const spaces, upcase: boolean): string; +var + loop : integer; + hexresult : string; +begin + hexresult := ''; + for loop := 1 to Length(input) do + begin + hexresult := hexresult + IntToHex(Ord(input[loop]),2); + if spaces then hexresult := hexresult + ' '; + end; + if upcase then result := AnsiUpperCase(hexresult) + else result := AnsiLowerCase(hexresult); +end; + +function AnsiToWide(const AnsiStr: AnsiString; CodePage: Cardinal = CP_ACP ): WideString; +var + Len: Integer; +begin + Len := MultiByteToWideChar(CodePage, 0, PAnsiChar(AnsiStr), -1, nil, 0); + SetLength(Result, Len - 1); + MultiByteToWideChar(CodePage, 0, PAnsiChar(AnsiStr), -1, PWideChar(Result), Len); +end; + +procedure TForm1.ShowData; +begin +label3.caption := IntToHex(pcsc.ReaderState,8); +label4.caption := pcsc.AttrICCType; +label5.caption := AnsiToWide(pcsc.AttrVendorName); +label6.caption := pcsc.AttrVendorSerial; +label14.caption := IntToHex(pcsc.AttrProtocol,8); +memo1.Lines.Add('ATR:'+Bin2HexExt(pcsc.AttrCardATR,false,true)); +end; + +procedure TForm1.pcscCardRemoved(Sender: TObject); +begin +memo1.Lines.Add('OnCardRemoved'); +ShowData; +end; + +procedure TForm1.pcscError(Sender: TObject; ErrSource: TErrSource; ErrCode: Cardinal); +begin +if memo1.Lines[memo1.Lines.Count-1]='OnError ' + IntToHex(ErrCode,8) then exit; +memo1.Lines.Add('OnError ' + IntToHex(ErrCode,8)); +label1.caption := IntToHex(ErrCode,8); +ShowData; +end; + + +procedure TForm1.bt_InitClick(Sender: TObject); +var i:integer; +begin +pcsc.Init; +pcsc.UseReaderNum := 0; +end; + + +procedure TForm1.bt_OpenClick(Sender: TObject); +begin +if pcsc.Open then memo1.lines.add('OPEN: OK') + else memo1.lines.add('OPEN: NOT OK'); +end; + +procedure TForm1.bt_ConnectClick(Sender: TObject); +begin +if pcsc.Connect then memo1.lines.add('CONNECT to ''' + IntToStr(pcsc.UseReaderNum) + ''' : OK') + else memo1.lines.add('CONNECT to ''' + IntToStr(pcsc.UseReaderNum) + ''' : NOT OK'); +end; + +procedure TForm1.bt_CloseClick(Sender: TObject); +begin +pcsc.Close; +end; + +procedure TForm1.bt_DisconnectClick(Sender: TObject); +begin +pcsc.Disconnect; +end; + +procedure TForm1.bt_SendClick(Sender: TObject); +begin + label2.caption := Bin2HexExt(pcsc.GetResponseFromCard(Hex2Bin('a0f2000016')), true, true); +end; + +procedure TForm1.Button1Click(Sender: TObject); +var i:integer; +begin + memo1.Lines.Add(inttostr(pcsc.ReaderList.Count)); + for i:=0 to pcsc.ReaderList.Count-1 do begin + memo1.Lines.Add(inttostr(i)+':'+pcsc.ReaderList[i]); + end; +end; + +procedure TForm1.pcscCardActive(Sender: TObject); +begin + memo1.Lines.Add('OnCardActive'); + ShowData; +end; + +procedure TForm1.pcscCardInserted(Sender: TObject); +begin +memo1.Lines.Add('OnCardInserted'); +ShowData; +end; + +procedure TForm1.pcscCardInvalid(Sender: TObject); +begin +memo1.Lines.Add('OnCardInvalid'); +ShowData; +end; + +procedure TForm1.pcscReaderConnect(Sender: TObject); +begin +memo1.Lines.Add('OnReaderConnect'); +ShowData; +end; + +procedure TForm1.pcscReaderDisconnect(Sender: TObject); +begin +memo1.Lines.Add('OnReaderDisconnect'); +ShowData; +end; + +procedure TForm1.pcscReaderListChange(Sender: TObject); +begin +memo1.Lines.Add('OnReaderListChange'); +end; + +procedure TForm1.pcscReaderWaiting(Sender: TObject); +begin +memo1.Lines.Add('OnReaderWaiting'); +end; + +end. + diff --git a/__history/FirstTest.pas.~63~ b/__history/FirstTest.pas.~63~ new file mode 100644 index 0000000..e9d51d5 --- /dev/null +++ b/__history/FirstTest.pas.~63~ @@ -0,0 +1,284 @@ +unit FirstTest; + +interface + +uses + Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, WinSCard, WinSmCrd, SCardErr, + StdCtrls, PCSCConnector; + +type + TForm1 = class(TForm) + pcsc: TPCSCConnector; + Label1: TLabel; + Label2: TLabel; + Label3: TLabel; + Label4: TLabel; + Label5: TLabel; + Label6: TLabel; + bt_Init: TButton; + bt_Open: TButton; + bt_Connect: TButton; + bt_Close: TButton; + bt_Disconnect: TButton; + Label7: TLabel; + Label8: TLabel; + Label9: TLabel; + Label10: TLabel; + Label11: TLabel; + Label12: TLabel; + bt_Send: TButton; + Memo1: TMemo; + Label13: TLabel; + Label14: TLabel; + Button1: TButton; + procedure pcscCardRemoved(Sender: TObject); + procedure pcscError(Sender: TObject; ErrSource: TErrSource; ErrCode: Cardinal); + procedure ShowData; + procedure bt_InitClick(Sender: TObject); + procedure bt_OpenClick(Sender: TObject); + procedure bt_ConnectClick(Sender: TObject); + procedure bt_CloseClick(Sender: TObject); + procedure bt_DisconnectClick(Sender: TObject); + procedure bt_SendClick(Sender: TObject); + procedure pcscCardActive(Sender: TObject); + procedure pcscCardInserted(Sender: TObject); + procedure pcscCardInvalid(Sender: TObject); + procedure pcscReaderConnect(Sender: TObject); + procedure pcscReaderDisconnect(Sender: TObject); + procedure pcscReaderListChange(Sender: TObject); + procedure pcscReaderWaiting(Sender: TObject); + procedure Button1Click(Sender: TObject); + private + { Private-Deklarationen } + public + { Public-Deklarationen } + end; + +var + Form1: TForm1; + +implementation + +{$R *.DFM} + +const + +HexChars = '0123456789abcdefABCDEF'; + +procedure ListSmartCardReaders(Memo: TMemo); +var + hContext: cardinal; + Readers: PChar; + ReaderList: TStringList; + ReaderListSize: integer; + Res: LongInt; + PtrReader: PChar; + qt:LongInt; +begin + Memo.Clear; // Limpa o memo antes de adicionar os leitores + Readers := nil; + ReaderListSize := 0; + ReaderList := TStringList.Create; + + try + // Estabelece o contexto para comunicação com o gerenciador de smartcard + Res := SCardEstablishContext(SCARD_SCOPE_USER, nil, nil, @hContext); + if Res <> SCARD_S_SUCCESS then + begin + Memo.Lines.Add('Erro ao estabelecer contexto: ' + IntToStr(Res)); + Exit; + end; + + // Obtém o tamanho necessário para armazenar os leitores + Res := SCardListReadersW(hContext, nil,nil, ReaderListSize); +// RetVar := SCardListReadersA(FContext, nil, nil, ReaderListSize); + if (Res <> SCARD_S_SUCCESS) or (ReaderListSize = 0) then + begin + Memo.Lines.Add('Nenhum leitor encontrado ou erro: ' + IntToStr(Res)); + Exit; + end; + + // Aloca espaço para armazenar a lista de leitores + GetMem(Readers, ReaderListSize); + + try + // Obtém a lista de leitores + Res := SCardListReadersW(hContext, nil, Pointer(Readers), ReaderListSize); +// SCardListReadersA(FContext, nil, Pointer(ReaderList), ReaderListSize); + if Res <> SCARD_S_SUCCESS then + begin + Memo.Lines.Add('Erro ao listar leitores: ' + IntToStr(Res)); + Exit; + end; + + // Adiciona os leitores à lista + PtrReader := Readers; + while PtrReader^ <> #0 do + begin + ReaderList.Add(PtrReader); + Inc(PtrReader, StrLen(PtrReader) + 1); + end; + + // Exibe os leitores no TMemo + Memo.Lines.AddStrings(ReaderList); + finally + FreeMem(Readers); + end; + + finally + // Libera o contexto + SCardReleaseContext(hContext); + ReaderList.Free; + end; +end; + +function Hex2Bin(input: string): string; +var +hex, output: string; +loop : integer; +begin + for loop := 1 to Length(input) do if Pos(input[loop], hexchars) > 0 then hex := hex + AnsiUpperCase(input[loop]); + loop := 1; + if Length(hex) > 0 then + repeat + output := output + Chr(StrToInt('$'+Copy(hex,loop,2))); + loop := loop + 2; + until loop > Length(hex); + Result := output; +end; + +function Bin2HexExt(const input:string; const spaces, upcase: boolean): string; +var + loop : integer; + hexresult : string; +begin + hexresult := ''; + for loop := 1 to Length(input) do + begin + hexresult := hexresult + IntToHex(Ord(input[loop]),2); + if spaces then hexresult := hexresult + ' '; + end; + if upcase then result := AnsiUpperCase(hexresult) + else result := AnsiLowerCase(hexresult); +end; + +function AnsiToWide(const AnsiStr: AnsiString; CodePage: Cardinal = CP_ACP ): WideString; +var + Len: Integer; +begin + Len := MultiByteToWideChar(CodePage, 0, PAnsiChar(AnsiStr), -1, nil, 0); + SetLength(Result, Len - 1); + MultiByteToWideChar(CodePage, 0, PAnsiChar(AnsiStr), -1, PWideChar(Result), Len); +end; + +procedure TForm1.ShowData; +begin +label3.caption := IntToHex(pcsc.ReaderState,8); +label4.caption := pcsc.AttrICCType; +label5.caption := AnsiToWide(pcsc.AttrVendorName); +label6.caption := pcsc.AttrVendorSerial; +label14.caption := IntToHex(pcsc.AttrProtocol,8); +//memo1.Lines.Add('ATR:'+Bin2HexExt(pcsc.AttrCardATR,false,true)); +end; + +procedure TForm1.pcscCardRemoved(Sender: TObject); +begin +memo1.Lines.Add('OnCardRemoved'); +ShowData; +end; + +procedure TForm1.pcscError(Sender: TObject; ErrSource: TErrSource; ErrCode: Cardinal); +begin +if memo1.Lines[memo1.Lines.Count-1]='OnError ' + IntToHex(ErrCode,8) then exit; +memo1.Lines.Add('OnError ' + IntToHex(ErrCode,8)); +label1.caption := IntToHex(ErrCode,8); +ShowData; +end; + + +procedure TForm1.bt_InitClick(Sender: TObject); +var i:integer; +begin +pcsc.Init; +pcsc.UseReaderNum := 0; +end; + + +procedure TForm1.bt_OpenClick(Sender: TObject); +begin +if pcsc.Open then memo1.lines.add('OPEN: OK') + else memo1.lines.add('OPEN: NOT OK'); +end; + +procedure TForm1.bt_ConnectClick(Sender: TObject); +begin +if pcsc.Connect then memo1.lines.add('CONNECT to ''' + IntToStr(pcsc.UseReaderNum) + ''' : OK') + else memo1.lines.add('CONNECT to ''' + IntToStr(pcsc.UseReaderNum) + ''' : NOT OK'); +end; + +procedure TForm1.bt_CloseClick(Sender: TObject); +begin +pcsc.Close; +end; + +procedure TForm1.bt_DisconnectClick(Sender: TObject); +begin +pcsc.Disconnect; +end; + +procedure TForm1.bt_SendClick(Sender: TObject); +begin + label2.caption := Bin2HexExt(pcsc.GetResponseFromCard(Hex2Bin('a0f2000016')), true, true); +end; + +procedure TForm1.Button1Click(Sender: TObject); +var i:integer; +begin + memo1.Lines.Add(inttostr(pcsc.ReaderList.Count)); + for i:=0 to pcsc.ReaderList.Count-1 do begin + memo1.Lines.Add(inttostr(i)+':'+pcsc.ReaderList[i]); + end; +end; + +procedure TForm1.pcscCardActive(Sender: TObject); +begin + memo1.Lines.Add('OnCardActive'); + ShowData; +end; + +procedure TForm1.pcscCardInserted(Sender: TObject); +begin +memo1.Lines.Add('OnCardInserted'); +ShowData; +end; + +procedure TForm1.pcscCardInvalid(Sender: TObject); +begin +memo1.Lines.Add('OnCardInvalid'); +ShowData; +end; + +procedure TForm1.pcscReaderConnect(Sender: TObject); +begin +memo1.Lines.Add('OnReaderConnect'); +ShowData; +end; + +procedure TForm1.pcscReaderDisconnect(Sender: TObject); +begin +memo1.Lines.Add('OnReaderDisconnect'); +ShowData; +end; + +procedure TForm1.pcscReaderListChange(Sender: TObject); +begin +memo1.Lines.Add('OnReaderListChange'); +end; + +procedure TForm1.pcscReaderWaiting(Sender: TObject); +begin +memo1.Lines.Add('OnReaderWaiting'); +end; + +end. + diff --git a/__history/FirstTest.pas.~64~ b/__history/FirstTest.pas.~64~ new file mode 100644 index 0000000..7d91346 --- /dev/null +++ b/__history/FirstTest.pas.~64~ @@ -0,0 +1,284 @@ +unit FirstTest; + +interface + +uses + Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, WinSCard, WinSmCrd, SCardErr, + StdCtrls, PCSCConnector; + +type + TForm1 = class(TForm) + pcsc: TPCSCConnector; + Label1: TLabel; + Label2: TLabel; + Label3: TLabel; + Label4: TLabel; + Label5: TLabel; + Label6: TLabel; + bt_Init: TButton; + bt_Open: TButton; + bt_Connect: TButton; + bt_Close: TButton; + bt_Disconnect: TButton; + Label7: TLabel; + Label8: TLabel; + Label9: TLabel; + Label10: TLabel; + Label11: TLabel; + Label12: TLabel; + bt_Send: TButton; + Memo1: TMemo; + Label13: TLabel; + Label14: TLabel; + Button1: TButton; + procedure pcscCardRemoved(Sender: TObject); + procedure pcscError(Sender: TObject; ErrSource: TErrSource; ErrCode: Cardinal); + procedure ShowData; + procedure bt_InitClick(Sender: TObject); + procedure bt_OpenClick(Sender: TObject); + procedure bt_ConnectClick(Sender: TObject); + procedure bt_CloseClick(Sender: TObject); + procedure bt_DisconnectClick(Sender: TObject); + procedure bt_SendClick(Sender: TObject); + procedure pcscCardActive(Sender: TObject); + procedure pcscCardInserted(Sender: TObject); + procedure pcscCardInvalid(Sender: TObject); + procedure pcscReaderConnect(Sender: TObject); + procedure pcscReaderDisconnect(Sender: TObject); + procedure pcscReaderListChange(Sender: TObject); + procedure pcscReaderWaiting(Sender: TObject); + procedure Button1Click(Sender: TObject); + private + { Private-Deklarationen } + public + { Public-Deklarationen } + end; + +var + Form1: TForm1; + +implementation + +{$R *.DFM} + +const + +HexChars = '0123456789abcdefABCDEF'; + +procedure ListSmartCardReaders(Memo: TMemo); +var + hContext: cardinal; + Readers: PChar; + ReaderList: TStringList; + ReaderListSize: integer; + Res: LongInt; + PtrReader: PChar; + qt:LongInt; +begin + Memo.Clear; // Limpa o memo antes de adicionar os leitores + Readers := nil; + ReaderListSize := 0; + ReaderList := TStringList.Create; + + try + // Estabelece o contexto para comunicação com o gerenciador de smartcard + Res := SCardEstablishContext(SCARD_SCOPE_USER, nil, nil, @hContext); + if Res <> SCARD_S_SUCCESS then + begin + Memo.Lines.Add('Erro ao estabelecer contexto: ' + IntToStr(Res)); + Exit; + end; + + // Obtém o tamanho necessário para armazenar os leitores + Res := SCardListReadersW(hContext, nil,nil, ReaderListSize); +// RetVar := SCardListReadersA(FContext, nil, nil, ReaderListSize); + if (Res <> SCARD_S_SUCCESS) or (ReaderListSize = 0) then + begin + Memo.Lines.Add('Nenhum leitor encontrado ou erro: ' + IntToStr(Res)); + Exit; + end; + + // Aloca espaço para armazenar a lista de leitores + GetMem(Readers, ReaderListSize); + + try + // Obtém a lista de leitores + Res := SCardListReadersW(hContext, nil, Pointer(Readers), ReaderListSize); +// SCardListReadersA(FContext, nil, Pointer(ReaderList), ReaderListSize); + if Res <> SCARD_S_SUCCESS then + begin + Memo.Lines.Add('Erro ao listar leitores: ' + IntToStr(Res)); + Exit; + end; + + // Adiciona os leitores à lista + PtrReader := Readers; + while PtrReader^ <> #0 do + begin + ReaderList.Add(PtrReader); + Inc(PtrReader, StrLen(PtrReader) + 1); + end; + + // Exibe os leitores no TMemo + Memo.Lines.AddStrings(ReaderList); + finally + FreeMem(Readers); + end; + + finally + // Libera o contexto + SCardReleaseContext(hContext); + ReaderList.Free; + end; +end; + +function Hex2Bin(input: string): string; +var +hex, output: string; +loop : integer; +begin + for loop := 1 to Length(input) do if Pos(input[loop], hexchars) > 0 then hex := hex + AnsiUpperCase(input[loop]); + loop := 1; + if Length(hex) > 0 then + repeat + output := output + Chr(StrToInt('$'+Copy(hex,loop,2))); + loop := loop + 2; + until loop > Length(hex); + Result := output; +end; + +function Bin2HexExt(const input:string; const spaces, upcase: boolean): string; +var + loop : integer; + hexresult : string; +begin + hexresult := ''; + for loop := 1 to Length(input) do + begin + hexresult := hexresult + IntToHex(Ord(input[loop]),2); + if spaces then hexresult := hexresult + ' '; + end; + if upcase then result := AnsiUpperCase(hexresult) + else result := AnsiLowerCase(hexresult); +end; + +function AnsiToWide(const AnsiStr: AnsiString; CodePage: Cardinal = CP_ACP ): WideString; +var + Len: Integer; +begin + Len := MultiByteToWideChar(CodePage, 0, PAnsiChar(AnsiStr), -1, nil, 0); + SetLength(Result, Len - 1); + MultiByteToWideChar(CodePage, 0, PAnsiChar(AnsiStr), -1, PWideChar(Result), Len); +end; + +procedure TForm1.ShowData; +begin +label3.caption := IntToHex(pcsc.ReaderState,8); +label4.caption := pcsc.AttrICCType; +label5.caption := pcsc.AttrVendorName; +label6.caption := pcsc.AttrVendorSerial; +label14.caption := IntToHex(pcsc.AttrProtocol,8); +//memo1.Lines.Add('ATR:'+Bin2HexExt(pcsc.AttrCardATR,false,true)); +end; + +procedure TForm1.pcscCardRemoved(Sender: TObject); +begin +memo1.Lines.Add('OnCardRemoved'); +ShowData; +end; + +procedure TForm1.pcscError(Sender: TObject; ErrSource: TErrSource; ErrCode: Cardinal); +begin +if memo1.Lines[memo1.Lines.Count-1]='OnError ' + IntToHex(ErrCode,8) then exit; +memo1.Lines.Add('OnError ' + IntToHex(ErrCode,8)); +label1.caption := IntToHex(ErrCode,8); +ShowData; +end; + + +procedure TForm1.bt_InitClick(Sender: TObject); +var i:integer; +begin +pcsc.Init; +pcsc.UseReaderNum := 0; +end; + + +procedure TForm1.bt_OpenClick(Sender: TObject); +begin +if pcsc.Open then memo1.lines.add('OPEN: OK') + else memo1.lines.add('OPEN: NOT OK'); +end; + +procedure TForm1.bt_ConnectClick(Sender: TObject); +begin +if pcsc.Connect then memo1.lines.add('CONNECT to ''' + IntToStr(pcsc.UseReaderNum) + ''' : OK') + else memo1.lines.add('CONNECT to ''' + IntToStr(pcsc.UseReaderNum) + ''' : NOT OK'); +end; + +procedure TForm1.bt_CloseClick(Sender: TObject); +begin +pcsc.Close; +end; + +procedure TForm1.bt_DisconnectClick(Sender: TObject); +begin +pcsc.Disconnect; +end; + +procedure TForm1.bt_SendClick(Sender: TObject); +begin + label2.caption := Bin2HexExt(pcsc.GetResponseFromCard(Hex2Bin('a0f2000016')), true, true); +end; + +procedure TForm1.Button1Click(Sender: TObject); +var i:integer; +begin + memo1.Lines.Add(inttostr(pcsc.ReaderList.Count)); + for i:=0 to pcsc.ReaderList.Count-1 do begin + memo1.Lines.Add(inttostr(i)+':'+pcsc.ReaderList[i]); + end; +end; + +procedure TForm1.pcscCardActive(Sender: TObject); +begin + memo1.Lines.Add('OnCardActive'); + ShowData; +end; + +procedure TForm1.pcscCardInserted(Sender: TObject); +begin +memo1.Lines.Add('OnCardInserted'); +ShowData; +end; + +procedure TForm1.pcscCardInvalid(Sender: TObject); +begin +memo1.Lines.Add('OnCardInvalid'); +ShowData; +end; + +procedure TForm1.pcscReaderConnect(Sender: TObject); +begin +memo1.Lines.Add('OnReaderConnect'); +ShowData; +end; + +procedure TForm1.pcscReaderDisconnect(Sender: TObject); +begin +memo1.Lines.Add('OnReaderDisconnect'); +ShowData; +end; + +procedure TForm1.pcscReaderListChange(Sender: TObject); +begin +memo1.Lines.Add('OnReaderListChange'); +end; + +procedure TForm1.pcscReaderWaiting(Sender: TObject); +begin +memo1.Lines.Add('OnReaderWaiting'); +end; + +end. + diff --git a/__history/FirstTest.pas.~65~ b/__history/FirstTest.pas.~65~ new file mode 100644 index 0000000..923d4f4 --- /dev/null +++ b/__history/FirstTest.pas.~65~ @@ -0,0 +1,284 @@ +unit FirstTest; + +interface + +uses + Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, WinSCard, WinSmCrd, SCardErr, + StdCtrls, PCSCConnector; + +type + TForm1 = class(TForm) + pcsc: TPCSCConnector; + Label1: TLabel; + Label2: TLabel; + Label3: TLabel; + Label4: TLabel; + Label5: TLabel; + Label6: TLabel; + bt_Init: TButton; + bt_Open: TButton; + bt_Connect: TButton; + bt_Close: TButton; + bt_Disconnect: TButton; + Label7: TLabel; + Label8: TLabel; + Label9: TLabel; + Label10: TLabel; + Label11: TLabel; + Label12: TLabel; + bt_Send: TButton; + Memo1: TMemo; + Label13: TLabel; + Label14: TLabel; + Button1: TButton; + procedure pcscCardRemoved(Sender: TObject); + procedure pcscError(Sender: TObject; ErrSource: TErrSource; ErrCode: Cardinal); + procedure ShowData; + procedure bt_InitClick(Sender: TObject); + procedure bt_OpenClick(Sender: TObject); + procedure bt_ConnectClick(Sender: TObject); + procedure bt_CloseClick(Sender: TObject); + procedure bt_DisconnectClick(Sender: TObject); + procedure bt_SendClick(Sender: TObject); + procedure pcscCardActive(Sender: TObject); + procedure pcscCardInserted(Sender: TObject); + procedure pcscCardInvalid(Sender: TObject); + procedure pcscReaderConnect(Sender: TObject); + procedure pcscReaderDisconnect(Sender: TObject); + procedure pcscReaderListChange(Sender: TObject); + procedure pcscReaderWaiting(Sender: TObject); + procedure Button1Click(Sender: TObject); + private + { Private-Deklarationen } + public + { Public-Deklarationen } + end; + +var + Form1: TForm1; + +implementation + +{$R *.DFM} + +const + +HexChars = '0123456789abcdefABCDEF'; + +procedure ListSmartCardReaders(Memo: TMemo); +var + hContext: cardinal; + Readers: PChar; + ReaderList: TStringList; + ReaderListSize: integer; + Res: LongInt; + PtrReader: PChar; + qt:LongInt; +begin + Memo.Clear; // Limpa o memo antes de adicionar os leitores + Readers := nil; + ReaderListSize := 0; + ReaderList := TStringList.Create; + + try + // Estabelece o contexto para comunicação com o gerenciador de smartcard + Res := SCardEstablishContext(SCARD_SCOPE_USER, nil, nil, @hContext); + if Res <> SCARD_S_SUCCESS then + begin + Memo.Lines.Add('Erro ao estabelecer contexto: ' + IntToStr(Res)); + Exit; + end; + + // Obtém o tamanho necessário para armazenar os leitores + Res := SCardListReadersW(hContext, nil,nil, ReaderListSize); +// RetVar := SCardListReadersA(FContext, nil, nil, ReaderListSize); + if (Res <> SCARD_S_SUCCESS) or (ReaderListSize = 0) then + begin + Memo.Lines.Add('Nenhum leitor encontrado ou erro: ' + IntToStr(Res)); + Exit; + end; + + // Aloca espaço para armazenar a lista de leitores + GetMem(Readers, ReaderListSize); + + try + // Obtém a lista de leitores + Res := SCardListReadersW(hContext, nil, Pointer(Readers), ReaderListSize); +// SCardListReadersA(FContext, nil, Pointer(ReaderList), ReaderListSize); + if Res <> SCARD_S_SUCCESS then + begin + Memo.Lines.Add('Erro ao listar leitores: ' + IntToStr(Res)); + Exit; + end; + + // Adiciona os leitores à lista + PtrReader := Readers; + while PtrReader^ <> #0 do + begin + ReaderList.Add(PtrReader); + Inc(PtrReader, StrLen(PtrReader) + 1); + end; + + // Exibe os leitores no TMemo + Memo.Lines.AddStrings(ReaderList); + finally + FreeMem(Readers); + end; + + finally + // Libera o contexto + SCardReleaseContext(hContext); + ReaderList.Free; + end; +end; + +function Hex2Bin(input: string): string; +var +hex, output: string; +loop : integer; +begin + for loop := 1 to Length(input) do if Pos(input[loop], hexchars) > 0 then hex := hex + AnsiUpperCase(input[loop]); + loop := 1; + if Length(hex) > 0 then + repeat + output := output + Chr(StrToInt('$'+Copy(hex,loop,2))); + loop := loop + 2; + until loop > Length(hex); + Result := output; +end; + +function Bin2HexExt(const input:string; const spaces, upcase: boolean): string; +var + loop : integer; + hexresult : string; +begin + hexresult := ''; + for loop := 1 to Length(input) do + begin + hexresult := hexresult + IntToHex(Ord(input[loop]),2); + if spaces then hexresult := hexresult + ' '; + end; + if upcase then result := AnsiUpperCase(hexresult) + else result := AnsiLowerCase(hexresult); +end; + +function AnsiToWide(const AnsiStr: AnsiString; CodePage: Cardinal = CP_ACP ): WideString; +var + Len: Integer; +begin + Len := MultiByteToWideChar(CodePage, 0, PAnsiChar(AnsiStr), -1, nil, 0); + SetLength(Result, Len - 1); + MultiByteToWideChar(CodePage, 0, PAnsiChar(AnsiStr), -1, PWideChar(Result), Len); +end; + +procedure TForm1.ShowData; +begin +label3.caption := IntToHex(pcsc.ReaderState,8); +label4.caption := pcsc.AttrICCType; +label5.caption := pcsc.AttrVendorName; +label6.caption := pcsc.AttrVendorSerial; +label14.caption := IntToHex(pcsc.AttrProtocol,8)+' ATR:'+Bin2HexExt(pcsc.AttrCardATR,false,true); + +end; + +procedure TForm1.pcscCardRemoved(Sender: TObject); +begin +memo1.Lines.Add('OnCardRemoved'); +ShowData; +end; + +procedure TForm1.pcscError(Sender: TObject; ErrSource: TErrSource; ErrCode: Cardinal); +begin +if memo1.Lines[memo1.Lines.Count-1]='OnError ' + IntToHex(ErrCode,8) then exit; +memo1.Lines.Add('OnError ' + IntToHex(ErrCode,8)); +label1.caption := IntToHex(ErrCode,8); +ShowData; +end; + + +procedure TForm1.bt_InitClick(Sender: TObject); +var i:integer; +begin +pcsc.Init; +pcsc.UseReaderNum := 0; +end; + + +procedure TForm1.bt_OpenClick(Sender: TObject); +begin +if pcsc.Open then memo1.lines.add('OPEN: OK') + else memo1.lines.add('OPEN: NOT OK'); +end; + +procedure TForm1.bt_ConnectClick(Sender: TObject); +begin +if pcsc.Connect then memo1.lines.add('CONNECT to ''' + IntToStr(pcsc.UseReaderNum) + ''' : OK') + else memo1.lines.add('CONNECT to ''' + IntToStr(pcsc.UseReaderNum) + ''' : NOT OK'); +end; + +procedure TForm1.bt_CloseClick(Sender: TObject); +begin +pcsc.Close; +end; + +procedure TForm1.bt_DisconnectClick(Sender: TObject); +begin +pcsc.Disconnect; +end; + +procedure TForm1.bt_SendClick(Sender: TObject); +begin + label2.caption := Bin2HexExt(pcsc.GetResponseFromCard(Hex2Bin('a0f2000016')), true, true); +end; + +procedure TForm1.Button1Click(Sender: TObject); +var i:integer; +begin + memo1.Lines.Add(inttostr(pcsc.ReaderList.Count)); + for i:=0 to pcsc.ReaderList.Count-1 do begin + memo1.Lines.Add(inttostr(i)+':'+pcsc.ReaderList[i]); + end; +end; + +procedure TForm1.pcscCardActive(Sender: TObject); +begin + memo1.Lines.Add('OnCardActive'); + ShowData; +end; + +procedure TForm1.pcscCardInserted(Sender: TObject); +begin +memo1.Lines.Add('OnCardInserted'); +ShowData; +end; + +procedure TForm1.pcscCardInvalid(Sender: TObject); +begin +memo1.Lines.Add('OnCardInvalid'); +ShowData; +end; + +procedure TForm1.pcscReaderConnect(Sender: TObject); +begin +memo1.Lines.Add('OnReaderConnect'); +ShowData; +end; + +procedure TForm1.pcscReaderDisconnect(Sender: TObject); +begin +memo1.Lines.Add('OnReaderDisconnect'); +ShowData; +end; + +procedure TForm1.pcscReaderListChange(Sender: TObject); +begin +memo1.Lines.Add('OnReaderListChange'); +end; + +procedure TForm1.pcscReaderWaiting(Sender: TObject); +begin +memo1.Lines.Add('OnReaderWaiting'); +end; + +end. + diff --git a/__history/FirstTest.pas.~66~ b/__history/FirstTest.pas.~66~ new file mode 100644 index 0000000..86219f3 --- /dev/null +++ b/__history/FirstTest.pas.~66~ @@ -0,0 +1,284 @@ +unit FirstTest; + +interface + +uses + Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, WinSCard, WinSmCrd, SCardErr, + StdCtrls, PCSCConnector; + +type + TForm1 = class(TForm) + pcsc: TPCSCConnector; + Label1: TLabel; + Label2: TLabel; + Label3: TLabel; + Label4: TLabel; + Label5: TLabel; + Label6: TLabel; + bt_Init: TButton; + bt_Open: TButton; + bt_Connect: TButton; + bt_Close: TButton; + bt_Disconnect: TButton; + Label7: TLabel; + Label8: TLabel; + Label9: TLabel; + Label10: TLabel; + Label11: TLabel; + Label12: TLabel; + bt_Send: TButton; + Memo1: TMemo; + Label13: TLabel; + Label14: TLabel; + Button1: TButton; + procedure pcscCardRemoved(Sender: TObject); + procedure pcscError(Sender: TObject; ErrSource: TErrSource; ErrCode: Cardinal); + procedure ShowData; + procedure bt_InitClick(Sender: TObject); + procedure bt_OpenClick(Sender: TObject); + procedure bt_ConnectClick(Sender: TObject); + procedure bt_CloseClick(Sender: TObject); + procedure bt_DisconnectClick(Sender: TObject); + procedure bt_SendClick(Sender: TObject); + procedure pcscCardActive(Sender: TObject); + procedure pcscCardInserted(Sender: TObject); + procedure pcscCardInvalid(Sender: TObject); + procedure pcscReaderConnect(Sender: TObject); + procedure pcscReaderDisconnect(Sender: TObject); + procedure pcscReaderListChange(Sender: TObject); + procedure pcscReaderWaiting(Sender: TObject); + procedure Button1Click(Sender: TObject); + private + { Private-Deklarationen } + public + { Public-Deklarationen } + end; + +var + Form1: TForm1; + +implementation + +{$R *.DFM} + +const + +HexChars = '0123456789abcdefABCDEF'; + +procedure ListSmartCardReaders(Memo: TMemo); +var + hContext: cardinal; + Readers: PChar; + ReaderList: TStringList; + ReaderListSize: integer; + Res: LongInt; + PtrReader: PChar; + qt:LongInt; +begin + Memo.Clear; // Limpa o memo antes de adicionar os leitores + Readers := nil; + ReaderListSize := 0; + ReaderList := TStringList.Create; + + try + // Estabelece o contexto para comunicação com o gerenciador de smartcard + Res := SCardEstablishContext(SCARD_SCOPE_USER, nil, nil, @hContext); + if Res <> SCARD_S_SUCCESS then + begin + Memo.Lines.Add('Erro ao estabelecer contexto: ' + IntToStr(Res)); + Exit; + end; + + // Obtém o tamanho necessário para armazenar os leitores + Res := SCardListReadersW(hContext, nil,nil, ReaderListSize); +// RetVar := SCardListReadersA(FContext, nil, nil, ReaderListSize); + if (Res <> SCARD_S_SUCCESS) or (ReaderListSize = 0) then + begin + Memo.Lines.Add('Nenhum leitor encontrado ou erro: ' + IntToStr(Res)); + Exit; + end; + + // Aloca espaço para armazenar a lista de leitores + GetMem(Readers, ReaderListSize); + + try + // Obtém a lista de leitores + Res := SCardListReadersW(hContext, nil, Pointer(Readers), ReaderListSize); +// SCardListReadersA(FContext, nil, Pointer(ReaderList), ReaderListSize); + if Res <> SCARD_S_SUCCESS then + begin + Memo.Lines.Add('Erro ao listar leitores: ' + IntToStr(Res)); + Exit; + end; + + // Adiciona os leitores à lista + PtrReader := Readers; + while PtrReader^ <> #0 do + begin + ReaderList.Add(PtrReader); + Inc(PtrReader, StrLen(PtrReader) + 1); + end; + + // Exibe os leitores no TMemo + Memo.Lines.AddStrings(ReaderList); + finally + FreeMem(Readers); + end; + + finally + // Libera o contexto + SCardReleaseContext(hContext); + ReaderList.Free; + end; +end; + +function Hex2Bin(input: string): string; +var +hex, output: string; +loop : integer; +begin + for loop := 1 to Length(input) do if Pos(input[loop], hexchars) > 0 then hex := hex + AnsiUpperCase(input[loop]); + loop := 1; + if Length(hex) > 0 then + repeat + output := output + Chr(StrToInt('$'+Copy(hex,loop,2))); + loop := loop + 2; + until loop > Length(hex); + Result := output; +end; + +function Bin2HexExt(const input:string; const spaces, upcase: boolean): string; +var + loop : integer; + hexresult : string; +begin + hexresult := ''; + for loop := 1 to Length(input) do + begin + hexresult := hexresult + IntToHex(Ord(input[loop]),2); + if spaces then hexresult := hexresult + ' '; + end; + if upcase then result := AnsiUpperCase(hexresult) + else result := AnsiLowerCase(hexresult); +end; + +function AnsiToWide(const AnsiStr: AnsiString; CodePage: Cardinal = CP_ACP ): WideString; +var + Len: Integer; +begin + Len := MultiByteToWideChar(CodePage, 0, PAnsiChar(AnsiStr), -1, nil, 0); + SetLength(Result, Len - 1); + MultiByteToWideChar(CodePage, 0, PAnsiChar(AnsiStr), -1, PWideChar(Result), Len); +end; + +procedure TForm1.ShowData; +begin +label3.caption := IntToHex(pcsc.ReaderState,8); +label4.caption := pcsc.AttrICCType; +label5.caption := pcsc.AttrVendorName; +label6.caption := pcsc.AttrVendorSerial; +label14.caption := IntToHex(pcsc.AttrProtocol,8)+' ATR:'+Bin2HexExt(pcsc.AttrCardATR,true,true); + +end; + +procedure TForm1.pcscCardRemoved(Sender: TObject); +begin +memo1.Lines.Add('OnCardRemoved'); +ShowData; +end; + +procedure TForm1.pcscError(Sender: TObject; ErrSource: TErrSource; ErrCode: Cardinal); +begin +if memo1.Lines[memo1.Lines.Count-1]='OnError ' + IntToHex(ErrCode,8) then exit; +memo1.Lines.Add('OnError ' + IntToHex(ErrCode,8)); +label1.caption := IntToHex(ErrCode,8); +ShowData; +end; + + +procedure TForm1.bt_InitClick(Sender: TObject); +var i:integer; +begin +pcsc.Init; +pcsc.UseReaderNum := 0; +end; + + +procedure TForm1.bt_OpenClick(Sender: TObject); +begin +if pcsc.Open then memo1.lines.add('OPEN: OK') + else memo1.lines.add('OPEN: NOT OK'); +end; + +procedure TForm1.bt_ConnectClick(Sender: TObject); +begin +if pcsc.Connect then memo1.lines.add('CONNECT to ''' + IntToStr(pcsc.UseReaderNum) + ''' : OK') + else memo1.lines.add('CONNECT to ''' + IntToStr(pcsc.UseReaderNum) + ''' : NOT OK'); +end; + +procedure TForm1.bt_CloseClick(Sender: TObject); +begin +pcsc.Close; +end; + +procedure TForm1.bt_DisconnectClick(Sender: TObject); +begin +pcsc.Disconnect; +end; + +procedure TForm1.bt_SendClick(Sender: TObject); +begin + label2.caption := Bin2HexExt(pcsc.GetResponseFromCard(Hex2Bin('a0f2000016')), true, true); +end; + +procedure TForm1.Button1Click(Sender: TObject); +var i:integer; +begin + memo1.Lines.Add(inttostr(pcsc.ReaderList.Count)); + for i:=0 to pcsc.ReaderList.Count-1 do begin + memo1.Lines.Add(inttostr(i)+':'+pcsc.ReaderList[i]); + end; +end; + +procedure TForm1.pcscCardActive(Sender: TObject); +begin + memo1.Lines.Add('OnCardActive'); + ShowData; +end; + +procedure TForm1.pcscCardInserted(Sender: TObject); +begin +memo1.Lines.Add('OnCardInserted'); +ShowData; +end; + +procedure TForm1.pcscCardInvalid(Sender: TObject); +begin +memo1.Lines.Add('OnCardInvalid'); +ShowData; +end; + +procedure TForm1.pcscReaderConnect(Sender: TObject); +begin +memo1.Lines.Add('OnReaderConnect'); +ShowData; +end; + +procedure TForm1.pcscReaderDisconnect(Sender: TObject); +begin +memo1.Lines.Add('OnReaderDisconnect'); +ShowData; +end; + +procedure TForm1.pcscReaderListChange(Sender: TObject); +begin +memo1.Lines.Add('OnReaderListChange'); +end; + +procedure TForm1.pcscReaderWaiting(Sender: TObject); +begin +memo1.Lines.Add('OnReaderWaiting'); +end; + +end. + diff --git a/__history/PCSCConnector.pas.~113~ b/__history/PCSCConnector.pas.~113~ new file mode 100644 index 0000000..12139b6 --- /dev/null +++ b/__history/PCSCConnector.pas.~113~ @@ -0,0 +1,699 @@ +{******************************************************************} +{ } +{ PC/SC Interface component } +{ Helps you access a cardreader through Microsofts SmartCard API } +{ } +{ The Original Code is PCSCConnector.pas } +{ } +{ The Initial Developer of the Original Code is } +{ Norbert Huettisch (nobbi(at)nobbi.com) } +{ } +{ Any suggestions and improvements to the code are appreciated } +{ } +{ This Code uses a modified SCardErr.pas (included) } +{ This Code uses a modified WinSCard.pas (included) } +{ This code uses the original WinSmCrd.pas (included) } +{ } +{ All originally made by Chris Dickerson (chrisd(at)tsc.com), } +{ available as 'Interface units for the Microsoft Smart Card API' } +{ at the Project JEDI Homepage http://www.delphi-jedi.org } +{ } +{ Version info: } +{ 021230 - initial version } +{ 030101 - routed errors from 'init' to the OnError event } +{ } +{ } +{******************************************************************} +{ } +{ The contents of this file are subject to the } +{ } +{ Mozilla Public License Version 1.1 (the "License") } +{ } +{ You may not use this file except in compliance with the License. } +{ You may obtain a copy of the License at } +{ http://www.mozilla.org/MPL/ } +{ } +{ Software distributed under the License is distributed on an } +{ "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or } +{ implied. See the License for the specific language governing } +{ rights and limitations under the License. } +{ } +{******************************************************************} + +unit PCSCConnector; + +interface + +uses + Windows, Messages, Forms, Classes, SysUtils, + SCardErr, WinSCard, WinSmCrd; + +type + TErrSource = (esInit, esConnect, esGetStatus, esTransmit); + TNeededPIN = (npPIN1, npPIN2, npPUK1, npPUK2); + TDelimiters = set of Char; + + TPCSCErrorEvent = procedure(Sender: TObject; ErrSource: TErrSource; ErrCode: cardinal) of object; + TPCSCPinEvent = procedure(Sender: TObject; NeedPIN: TNeededPIN) of object; + +const + MAXAPDULENGTH = 260; // CLA + INS + P1..3 + 255Bytes + NOREADERSELECTED = -1; + SCARD_PCI_T0 : SCARD_IO_REQUEST = (dwProtocol:1; dbPciLength:8); + SCARD_PCI_T1 : SCARD_IO_REQUEST = (dwProtocol:2; dbPciLength:8); + SCARD_PROTOCOL_T0 = $00000001; + SCARD_PROTOCOL_T1 = $00000002; + SCARD_PROTOCOL_RAW = $00010000; + SCARD_PROTOCOL_UNK = $00000000; + + WM_CARDSTATE = WM_USER + 42; + + GSMStatusOK = $9000; + GSMStatusMemoryError = $9240; + GSMStatusNoEFSelected = $9400; + GSMStatusOutOfRange = $9402; + GSMStatusNotFound = $9404; + GSMStatusFCDoNotMatch = $9408; + GSMStatusCHVNeeded = $9802; + GSMStatusAuthFailed = $9804; + GSMStatusAuthFailedBl = $9840; + GSMStatusTechProblem = $6F00; + GSMStatusResponseData = $9F; + + GSMFileTypeRFU = 0; + GSMFileTypeMF = 1; + GSMFileTypeDF = 2; + GSMFileTypeEF = 4; + + GSMEfTransp = 0; + GSMEfLinFixed = 1; + GSMEfCyclic = 3; + +type + TPCSCConnector = class(TComponent) + + protected + FContext : cardinal; + FCardHandle : integer; + FConnected : boolean; + FNumReaders : integer; + FUseReaderNum : integer; + FReaderList : TStringlist; + FAttrProtocol : integer; + FAttrICCType : string; + FAttrCardATR : string; + FAttrVendorName : string; + FAttrVendorSerial : string; + FGSMCurrentFile : string; + FGSMFileInfo : string; + FGSMDirInfo : string; + FGSMVoltage30 : boolean; + FGSMVoltage18 : boolean; + + FOnReaderWaiting : TNotifyEvent; + FOnReaderListChange : TNotifyEvent; + FOnCardInserted : TNotifyEvent; + FOnCardActive : TNotifyEvent; + FOnCardRemoved : TNotifyEvent; + FOnCardInvalid : TNotifyEvent; + FOnError : TPCSCErrorEvent; + FOnCHVNeeded : TPCSCPinEvent; + + procedure SetReaderNum(Value: integer); + procedure MessageWndProc(var Msg: TMessage); + function ConnectSelectedReader: boolean; + procedure ProcessReaderState(const OldState,NewState: cardinal); + procedure GetReaderAttributes; + procedure GetCardAttributes; + procedure ClearReaderAttributes; + procedure ClearCardAttributes; + function IsReaderOpen: boolean; + function GetReaderState: cardinal; + procedure CloseAndDisconnect; + procedure CardInsertedAction; + procedure CardActiveAction; + procedure CardRemovedAction; + + public + constructor Create(AOwner: TComponent); override; + destructor Destroy; override; + function Init: boolean; + function Open: boolean; + procedure Close; + function Connect: boolean; + procedure Disconnect; + function GetResponseFromCard(const apdu: string): string; overload; + function GetResponseFromCard(const command: string; var data: string; var sw1, sw2: byte): boolean; overload; + + function GSMStatus: integer; + function GSMSelect(const FileID: string): integer; + function GSMReadBinary(const Offset, Length: integer; var Data: string): integer; + + published + property UseReaderNum: integer read FUseReaderNum write SetReaderNum default -1; + + property OnCardInserted: TNotifyEvent read FOnCardInserted write FOnCardInserted; + property OnCardActive: TNotifyEvent read FOnCardActive write FOnCardActive; + property OnCardRemoved: TNotifyEvent read FOnCardRemoved write FOnCardRemoved; + property OnCardInvalid: TNotifyEvent read FOnCardInvalid write FOnCardInvalid; + property OnReaderWaiting: TNotifyEvent read FOnReaderWaiting write FOnReaderWaiting; + property OnReaderListChange: TNotifyEvent read FOnReaderListChange write FOnReaderListChange; + property OnError: TPCSCErrorEvent read FOnError write FOnError; + property OnCHVNeeded: TPCSCPinEvent read FOnCHVNeeded write FOnCHVNeeded; + + property ReaderList: TStringList read FReaderList; + property NumReaders: integer read FNumReaders; + property Connected: boolean read FConnected; + property Opened: boolean read IsReaderOpen; + property ReaderState: cardinal read GetReaderState; + property AttrProtocol: integer read FAttrProtocol; + property AttrICCType: string read FAttrICCType; + property AttrCardATR: string read FAttrCardATR; + property AttrVendorName: string read FAttrVendorName; + property AttrVendorSerial: string read FAttrVendorSerial; + property GSMCurrentFile: string read FGSMCurrentFile; + property GSMFileInfo: string read FGSMFileInfo; + property GSMDirInfo: string read FGSMDirInfo; + property GSMVoltage30: boolean read FGSMVoltage30; + property GSMVoltage18: boolean read FGSMVoltage18; + end; + +procedure Register; + +implementation + +var + ActReaderState : cardinal; + LastReaderState : cardinal; + SelectedReader : PAnsiChar; + ReaderOpen : boolean; + NotifyHandle : HWND; + +const + + // GSM Commands + GCGetStatus = #$A0#$F2#$00#$00#$16; + GCGetResponse = #$A0#$C0#$00#$00; + GCSelectFile = #$A0#$A4#$00#$00#$02; + GCReadBinary = #$A0#$B0; + + GSMMasterFile = #$3f#$00; + DFgsm900 = #$7f#$20; + DFgsm1800 = #$7f#$21; + +procedure Register; +begin + RegisterComponents('More...', [TPCSCConnector]); +end; + +function SortOutSubstrings(const From:string; var t:array of string; const Delim:TDelimiters = [' ',';']; const ConcatDelim:boolean = true):integer; +var a,b,s,i : integer; + sep : boolean; +begin +a := 1; +b := Low(t); +s := 1; +i := 0; +sep := ConcatDelim; +t[b] := ''; + +while a <= Length(From) do + begin + if not (From[a] in Delim) then + begin + Inc(i); + sep := false; + end else + begin + if not sep then + begin + t[b] := Copy(From, s, i); + Inc(b); + if b > High(t) then Break; + t[b] := ''; + end; + if ConcatDelim then sep := true; + s := a + 1; + i := 0; + end; + Inc(a); + end; +if (b <= High(t)) and (i > 0) then + begin + t[b] := Copy(From, s, i); + Inc(b); + end; +for a := b + 1 to High(t) do t[a] := ''; +Result := b; +end; + +function OrdD(const From: string; const Index: integer): integer; +begin +if Index <= Length(From) then Result := Ord(From[Index]) + else Result := 0; +end; + +function CardWatcherThread(PContext: pointer): integer; +var + RetVar : cardinal; + RContext : cardinal; + RStates : array[0..1] of SCARD_READERSTATEA; +begin + try + RContext := cardinal(PContext^); + FillChar(RStates,SizeOf(RStates),#0); + RStates[0].szReader := SelectedReader; + RStates[0].pvUserData := nil; + RStates[0].dwEventState := ActReaderState; + while ReaderOpen do + begin + RStates[0].dwCurrentState := RStates[0].dwEventState; + RetVar := SCardGetStatusChangeA(RContext, -1, RStates, 1); + ActReaderState := RStates[0].dwEventState; + PostMessage(NotifyHandle, WM_CARDSTATE, RetVar, 0); + end; + finally + Result := 0; + end; +end; + +procedure TPCSCConnector.MessageWndProc(var Msg: TMessage); +begin + if (Msg.Msg = WM_CARDSTATE) then + begin + if Msg.WParam <> SCARD_S_SUCCESS then + if Assigned(FOnError) then FOnError(Self, esGetStatus, Msg.WParam); + if ActReaderState <> LastReaderState then + begin + ProcessReaderState(LastReaderState, ActReaderState); + end; + end + else Msg.Result := DefWindowProc(NotifyHandle, Msg.Msg, Msg.WParam, Msg.LParam); +end; + +constructor TPCSCConnector.Create(AOwner: TComponent); +begin + inherited Create(AOwner); + FReaderList := TStringlist.Create; + FContext := 0; + FCardHandle := 0; + FNumReaders := 0; + FUseReaderNum := -1; + FConnected := false; + ActReaderState := SCARD_STATE_UNAWARE; + LastReaderState := SCARD_STATE_UNAWARE; + ReaderOpen := false; + ClearReaderAttributes; + ClearCardAttributes; + if not (csDesigning in ComponentState) then NotifyHandle := AllocateHWnd(MessageWndProc); +end; + +destructor TPCSCConnector.Destroy; +begin + CloseAndDisconnect; + SCardReleaseContext(FContext); + FReaderList.Free; + if not (csDesigning in ComponentState) then DeallocateHWnd(NotifyHandle); + inherited Destroy; +end; + +function TPCSCConnector.Init: boolean; +var + RetVar : cardinal; + ReaderList : string; + ReaderListSize : integer; + v : array[0..MAXIMUM_SMARTCARD_READERS] of string; + i : integer; + +begin + Result := false; + FNumReaders := 0; + CloseAndDisconnect; + if SCardIsValidContext(FContext) = SCARD_S_SUCCESS then SCardReleaseContext(FContext); + RetVar := SCardEstablishContext(SCARD_SCOPE_USER, nil, nil, @FContext); + if RetVar = SCARD_S_SUCCESS then + begin + ReaderListSize := 0; + RetVar := SCardListReadersW(FContext, nil, nil, ReaderListSize); + if RetVar = SCARD_S_SUCCESS then + begin + SetLength(ReaderList, ReaderListSize); + SCardListReadersW(FContext, nil, Pointer(ReaderList), ReaderListSize); + FReaderList.Clear; + SortOutSubstrings(ReaderList,v,[#0]); + for i := 0 to MAXIMUM_SMARTCARD_READERS do + if v[i] <> '' then FReaderList.Add(v[i]); + FNumReaders := FReaderList.Count; + if FNumReaders > 0 then + begin + if Assigned(FOnReaderListChange) then FOnReaderListChange(Self); + Result := true; + end; + end else if Assigned(FOnError) then FOnError(Self, esInit, RetVar); + end else if Assigned(FOnError) then FOnError(Self, esInit, RetVar); +end; + +function TPCSCConnector.Open: boolean; +var + ThreadID : LongWord; +begin + CloseAndDisconnect; + if (FUseReaderNum > NOREADERSELECTED) and + (SCardIsValidContext(FContext) = SCARD_S_SUCCESS) then + begin + ReaderOpen := true; + ActReaderState := SCARD_STATE_UNAWARE; + LastReaderState := SCARD_STATE_UNAWARE; + BeginThread(nil, 0, CardWatcherThread, @FContext, 0, ThreadID); + Result := true; + end else Result := false; +end; + +procedure TPCSCConnector.Close; +begin + ReaderOpen := false; + SCardCancel(FContext); + if FConnected then Disconnect; +end; + +function TPCSCConnector.Connect: boolean; +begin + if FConnected then Disconnect; + if FUseReaderNum > NOREADERSELECTED then + if ConnectSelectedReader then FConnected := true + else FConnected := false; + Result := FConnected; +end; + +procedure TPCSCConnector.Disconnect; +begin + if FConnected then + begin + SCardDisconnect(FCardHandle, SCARD_RESET_CARD); + FConnected := false; + FCardHandle := 0; + end; +end; + +procedure TPCSCConnector.CloseAndDisconnect; +begin + if FConnected then Disconnect; + if ReaderOpen then Close; +end; + +function TPCSCConnector.ConnectSelectedReader: boolean; +var + RetVar : cardinal; +begin + RetVar := SCardConnectW(FContext, + PWideChar(SelectedReader), + SCARD_SHARE_EXCLUSIVE, + SCARD_PROTOCOL_Tx, + FCardHandle, + @FAttrProtocol); + case RetVar of + SCARD_S_SUCCESS : begin + CardActiveAction; + Result := true; + end; + SCARD_W_REMOVED_CARD : begin + Result := true; + end; + else begin + Result := false; + if Assigned(FOnError) then FOnError(Self, esConnect, RetVar); + end; + end; +end; + +procedure TPCSCConnector.ProcessReaderState(const OldState,NewState: cardinal); +var + CardInOld, CardInNew : boolean; + ReaderEmOld, ReaderEmNew : boolean; + CardMuteOld, CardMuteNew : boolean; + CardIgnore : boolean; + +begin +CardInOld := (OldState and SCARD_STATE_PRESENT) > 0; +CardInNew := (NewState and SCARD_STATE_PRESENT) > 0; +ReaderEmOld := (OldState and SCARD_STATE_EMPTY) > 0; +ReaderEmNew := (NewState and SCARD_STATE_EMPTY) > 0; +CardMuteOld := (OldState and SCARD_STATE_MUTE) > 0; +CardMuteNew := (NewState and SCARD_STATE_MUTE) > 0; +CardIgnore := (NewState and SCARD_STATE_IGNORE) > 0; + +if CardMuteNew and + not CardMuteold then if Assigned(FOnCardInvalid) then FOnCardInvalid(Self); + +if CardInNew and + not CardInOld and + not CardMuteNew and + not CardIgnore then CardInsertedAction; + +if CardInOld and + not CardInNew then CardRemovedAction; + +if ReaderEmNew and + not ReaderEmOld then begin + if Assigned(FOnReaderWaiting) then FOnReaderWaiting(Self); + end; + +LastReaderState := NewState; +end; + +procedure TPCSCConnector.CardInsertedAction; +begin + if Assigned(FOnCardInserted) then FOnCardInserted(Self); + if FConnected then CardActiveAction; +end; + +procedure TPCSCConnector.CardActiveAction; +begin + GetReaderAttributes; + if FAttrProtocol <> SCARD_PROTOCOL_UNK then + begin + GetCardAttributes; + if Assigned(FOnCardActive) then FOnCardActive(Self); + end; +end; + +procedure TPCSCConnector.CardRemovedAction; +begin + ClearReaderAttributes; + ClearCardAttributes; + if Assigned(FOnCardRemoved) then FOnCardRemoved(Self); + Disconnect; +end; + +procedure TPCSCConnector.SetReaderNum(Value: Integer); +begin + if Value <> FUseReaderNum then + begin + CloseAndDisconnect; + if Value < FReaderList.Count then + begin + SelectedReader := PChar(FReaderList[Value]); + FUseReaderNum := Value; + end else + begin + SelectedReader := ''; + FUseReaderNum := -1; + end; + end; +end; + +function TPCSCConnector.IsReaderOpen: boolean; +begin + Result := ReaderOpen; +end; + +function TPCSCConnector.GetReaderState: cardinal; +begin + Result := ActReaderState; +end; + +procedure TPCSCConnector.GetReaderAttributes; +var + RetVar : cardinal; + ABuf : string; + AIBuf : integer; + ALen : integer; +begin + ABuf := StringOfChar(#0, 127); + ALen := Length(ABuf); + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_ATR_STRING, Pointer(ABuf), @ALen); + if RetVar = SCARD_S_SUCCESS then FAttrCardATR := Copy(ABuf, 1, ALen) + else FAttrCardATR := ''; + + ALen := Length(ABuf); + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_VENDOR_NAME, Pointer(ABuf), @ALen); + if RetVar = SCARD_S_SUCCESS then FAttrVendorName := Copy(ABuf, 1, ALen) + else FAttrVendorName := ''; + + ALen := Length(ABuf); + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_VENDOR_IFD_SERIAL_NO, Pointer(ABuf), @ALen); + if RetVar = SCARD_S_SUCCESS then FAttrVendorSerial := Copy(ABuf, 1, ALen) + else FAttrVendorSerial := ''; + + ALen := SizeOf(AIBuf); + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_CURRENT_PROTOCOL_TYPE, @AIBuf, @ALen); + if RetVar = SCARD_S_SUCCESS then FAttrProtocol := AIBuf + else FAttrProtocol := 0; + + ALen := SizeOf(AIBuf); + AIBuf := 0; + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_ICC_TYPE_PER_ATR, @AIBuf, @ALen); + if RetVar = SCARD_S_SUCCESS then begin + case AIBuf of + 1 : FAttrICCType := 'ISO7816A'; + 2 : FAttrICCType := 'ISO7816S'; + else FAttrICCType := 'UNKNOWN'; + end; + end + else FAttrICCType := ''; +end; + +procedure TPCSCConnector.GetCardAttributes; +begin +if GSMSelect(DFgsm900) = GSMStatusOK then + begin + FGSMVoltage30 := (OrdD(FGSMDirInfo, 14) and $10) > 0; + FGSMVoltage18 := (OrdD(FGSMDirInfo, 14) and $20) > 0; + end; +end; + +procedure TPCSCConnector.ClearReaderAttributes; +begin + FAttrCardATR := ''; + FAttrVendorName := ''; + FAttrVendorSerial := ''; + FAttrProtocol := 0; + FAttrICCType := ''; +end; + +procedure TPCSCConnector.ClearCardAttributes; +begin + FGSMCurrentFile := ''; + FGSMFileInfo := ''; + FGSMDirInfo := ''; + FGSMVoltage30 := false; + FGSMVoltage18 := false; +end; + +function TPCSCConnector.GetResponseFromCard(const APdu: string): string; +var + RetVar : cardinal; + SBuf : string; + SLen : cardinal; + RBuf : string; + RLen : cardinal; + Ppci : Pointer; +begin +SBuf := APdu; +RBuf := StringOfChar(#0,MAXAPDULENGTH); +if Length(SBuf) <= MAXAPDULENGTH then + begin + case FAttrProtocol of + SCARD_PROTOCOL_T0 : Ppci := @SCARD_PCI_T0; + SCARD_PROTOCOL_T1 : Ppci := @SCARD_PCI_T1; + else Ppci := nil; + end; + SLen := Length(APdu); + RLen := Length(RBuf); + RetVar := SCardTransmit(FCardHandle, Ppci, Pointer(SBuf), SLen, nil, Pointer(RBuf), @RLen); + if RetVar = SCARD_S_SUCCESS then + begin + Result := Copy(RBuf,1,RLen); + end else + begin + Result := ''; + if Assigned(FOnError) then FOnError(Self, esTransmit, RetVar); + end; + end; +end; + +function TPCSCConnector.GetResponseFromCard(const Command: string; var Data: string; var sw1, sw2: byte): boolean; +var + Answer : string; + AnswerL : integer; +begin +Answer := GetResponseFromCard(Command + Data); +AnswerL := Length(Answer); +if AnswerL >= 2 then + begin + Data := Copy(Answer, 1, AnswerL - 2); + sw1 := Ord(Answer[AnswerL - 1]); + sw2 := Ord(Answer[AnswerL]); + if sw1 = GSMStatusResponseData then + begin + Data := Chr(sw2); + if not GetResponseFromCard(GCGetResponse, Data, sw1, sw2) then + begin + Data := ''; + sw1 := 0; + sw2 := 0; + Result := false; + end else Result := true; + end else Result := true; + end else + begin + Data := ''; + sw1 := 0; + sw2 := 0; + Result := false; + end; +end; + +function TPCSCConnector.GSMStatus: integer; +var + Answer : string; + sw1, sw2 : byte; +begin + GetResponseFromCard(GCGetStatus, Answer, sw1, sw2); + Result := (sw1 shl 8) + sw2; + if Result = GSMStatusOK then + begin + FGSMDirInfo := Answer; + FGSMCurrentFile := Copy(Answer, 5, 2); + end else + begin + FGSMDirInfo := ''; + end; +end; + +function TPCSCConnector.GSMSelect(const FileID: string): integer; +var + Answer : string; + sw1, sw2 : byte; +begin + Answer := FileID; + GetResponseFromCard(GCSelectFile, Answer, sw1, sw2); + Result := (sw1 shl 8) + sw2; + if Result = GSMStatusOK then + begin + FGSMCurrentFile := Copy(Answer, 5, 2); + if OrdD(Answer, 7) = GSMFileTypeEF then + begin + FGSMFileInfo := Answer; + end else + begin + FGSMDirInfo := Answer; + end; + end; +end; + +function TPCSCConnector.GSMReadBinary(const Offset, Length: integer; var Data: string): integer; +var + Command : string; + sw1, sw2 : byte; +begin + Command := GCReadBinary + Chr(Offset div 256) + Chr(Offset mod 256) + Chr(Length mod 256); + GetResponseFromCard(Command, Data, sw1, sw2); + Result := (sw1 shl 8) + sw2; + if Result = GSMStatusOK then + begin + end; +end; + +end. + diff --git a/__history/PCSCConnector.pas.~114~ b/__history/PCSCConnector.pas.~114~ new file mode 100644 index 0000000..034a38a --- /dev/null +++ b/__history/PCSCConnector.pas.~114~ @@ -0,0 +1,699 @@ +{******************************************************************} +{ } +{ PC/SC Interface component } +{ Helps you access a cardreader through Microsofts SmartCard API } +{ } +{ The Original Code is PCSCConnector.pas } +{ } +{ The Initial Developer of the Original Code is } +{ Norbert Huettisch (nobbi(at)nobbi.com) } +{ } +{ Any suggestions and improvements to the code are appreciated } +{ } +{ This Code uses a modified SCardErr.pas (included) } +{ This Code uses a modified WinSCard.pas (included) } +{ This code uses the original WinSmCrd.pas (included) } +{ } +{ All originally made by Chris Dickerson (chrisd(at)tsc.com), } +{ available as 'Interface units for the Microsoft Smart Card API' } +{ at the Project JEDI Homepage http://www.delphi-jedi.org } +{ } +{ Version info: } +{ 021230 - initial version } +{ 030101 - routed errors from 'init' to the OnError event } +{ } +{ } +{******************************************************************} +{ } +{ The contents of this file are subject to the } +{ } +{ Mozilla Public License Version 1.1 (the "License") } +{ } +{ You may not use this file except in compliance with the License. } +{ You may obtain a copy of the License at } +{ http://www.mozilla.org/MPL/ } +{ } +{ Software distributed under the License is distributed on an } +{ "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or } +{ implied. See the License for the specific language governing } +{ rights and limitations under the License. } +{ } +{******************************************************************} + +unit PCSCConnector; + +interface + +uses + Windows, Messages, Forms, Classes, SysUtils, + SCardErr, WinSCard, WinSmCrd; + +type + TErrSource = (esInit, esConnect, esGetStatus, esTransmit); + TNeededPIN = (npPIN1, npPIN2, npPUK1, npPUK2); + TDelimiters = set of Char; + + TPCSCErrorEvent = procedure(Sender: TObject; ErrSource: TErrSource; ErrCode: cardinal) of object; + TPCSCPinEvent = procedure(Sender: TObject; NeedPIN: TNeededPIN) of object; + +const + MAXAPDULENGTH = 260; // CLA + INS + P1..3 + 255Bytes + NOREADERSELECTED = -1; + SCARD_PCI_T0 : SCARD_IO_REQUEST = (dwProtocol:1; dbPciLength:8); + SCARD_PCI_T1 : SCARD_IO_REQUEST = (dwProtocol:2; dbPciLength:8); + SCARD_PROTOCOL_T0 = $00000001; + SCARD_PROTOCOL_T1 = $00000002; + SCARD_PROTOCOL_RAW = $00010000; + SCARD_PROTOCOL_UNK = $00000000; + + WM_CARDSTATE = WM_USER + 42; + + GSMStatusOK = $9000; + GSMStatusMemoryError = $9240; + GSMStatusNoEFSelected = $9400; + GSMStatusOutOfRange = $9402; + GSMStatusNotFound = $9404; + GSMStatusFCDoNotMatch = $9408; + GSMStatusCHVNeeded = $9802; + GSMStatusAuthFailed = $9804; + GSMStatusAuthFailedBl = $9840; + GSMStatusTechProblem = $6F00; + GSMStatusResponseData = $9F; + + GSMFileTypeRFU = 0; + GSMFileTypeMF = 1; + GSMFileTypeDF = 2; + GSMFileTypeEF = 4; + + GSMEfTransp = 0; + GSMEfLinFixed = 1; + GSMEfCyclic = 3; + +type + TPCSCConnector = class(TComponent) + + protected + FContext : cardinal; + FCardHandle : integer; + FConnected : boolean; + FNumReaders : integer; + FUseReaderNum : integer; + FReaderList : TStringlist; + FAttrProtocol : integer; + FAttrICCType : string; + FAttrCardATR : string; + FAttrVendorName : string; + FAttrVendorSerial : string; + FGSMCurrentFile : string; + FGSMFileInfo : string; + FGSMDirInfo : string; + FGSMVoltage30 : boolean; + FGSMVoltage18 : boolean; + + FOnReaderWaiting : TNotifyEvent; + FOnReaderListChange : TNotifyEvent; + FOnCardInserted : TNotifyEvent; + FOnCardActive : TNotifyEvent; + FOnCardRemoved : TNotifyEvent; + FOnCardInvalid : TNotifyEvent; + FOnError : TPCSCErrorEvent; + FOnCHVNeeded : TPCSCPinEvent; + + procedure SetReaderNum(Value: integer); + procedure MessageWndProc(var Msg: TMessage); + function ConnectSelectedReader: boolean; + procedure ProcessReaderState(const OldState,NewState: cardinal); + procedure GetReaderAttributes; + procedure GetCardAttributes; + procedure ClearReaderAttributes; + procedure ClearCardAttributes; + function IsReaderOpen: boolean; + function GetReaderState: cardinal; + procedure CloseAndDisconnect; + procedure CardInsertedAction; + procedure CardActiveAction; + procedure CardRemovedAction; + + public + constructor Create(AOwner: TComponent); override; + destructor Destroy; override; + function Init: boolean; + function Open: boolean; + procedure Close; + function Connect: boolean; + procedure Disconnect; + function GetResponseFromCard(const apdu: string): string; overload; + function GetResponseFromCard(const command: string; var data: string; var sw1, sw2: byte): boolean; overload; + + function GSMStatus: integer; + function GSMSelect(const FileID: string): integer; + function GSMReadBinary(const Offset, Length: integer; var Data: string): integer; + + published + property UseReaderNum: integer read FUseReaderNum write SetReaderNum default -1; + + property OnCardInserted: TNotifyEvent read FOnCardInserted write FOnCardInserted; + property OnCardActive: TNotifyEvent read FOnCardActive write FOnCardActive; + property OnCardRemoved: TNotifyEvent read FOnCardRemoved write FOnCardRemoved; + property OnCardInvalid: TNotifyEvent read FOnCardInvalid write FOnCardInvalid; + property OnReaderWaiting: TNotifyEvent read FOnReaderWaiting write FOnReaderWaiting; + property OnReaderListChange: TNotifyEvent read FOnReaderListChange write FOnReaderListChange; + property OnError: TPCSCErrorEvent read FOnError write FOnError; + property OnCHVNeeded: TPCSCPinEvent read FOnCHVNeeded write FOnCHVNeeded; + + property ReaderList: TStringList read FReaderList; + property NumReaders: integer read FNumReaders; + property Connected: boolean read FConnected; + property Opened: boolean read IsReaderOpen; + property ReaderState: cardinal read GetReaderState; + property AttrProtocol: integer read FAttrProtocol; + property AttrICCType: string read FAttrICCType; + property AttrCardATR: string read FAttrCardATR; + property AttrVendorName: string read FAttrVendorName; + property AttrVendorSerial: string read FAttrVendorSerial; + property GSMCurrentFile: string read FGSMCurrentFile; + property GSMFileInfo: string read FGSMFileInfo; + property GSMDirInfo: string read FGSMDirInfo; + property GSMVoltage30: boolean read FGSMVoltage30; + property GSMVoltage18: boolean read FGSMVoltage18; + end; + +procedure Register; + +implementation + +var + ActReaderState : cardinal; + LastReaderState : cardinal; + SelectedReader : PChar; + ReaderOpen : boolean; + NotifyHandle : HWND; + +const + + // GSM Commands + GCGetStatus = #$A0#$F2#$00#$00#$16; + GCGetResponse = #$A0#$C0#$00#$00; + GCSelectFile = #$A0#$A4#$00#$00#$02; + GCReadBinary = #$A0#$B0; + + GSMMasterFile = #$3f#$00; + DFgsm900 = #$7f#$20; + DFgsm1800 = #$7f#$21; + +procedure Register; +begin + RegisterComponents('More...', [TPCSCConnector]); +end; + +function SortOutSubstrings(const From:string; var t:array of string; const Delim:TDelimiters = [' ',';']; const ConcatDelim:boolean = true):integer; +var a,b,s,i : integer; + sep : boolean; +begin +a := 1; +b := Low(t); +s := 1; +i := 0; +sep := ConcatDelim; +t[b] := ''; + +while a <= Length(From) do + begin + if not (From[a] in Delim) then + begin + Inc(i); + sep := false; + end else + begin + if not sep then + begin + t[b] := Copy(From, s, i); + Inc(b); + if b > High(t) then Break; + t[b] := ''; + end; + if ConcatDelim then sep := true; + s := a + 1; + i := 0; + end; + Inc(a); + end; +if (b <= High(t)) and (i > 0) then + begin + t[b] := Copy(From, s, i); + Inc(b); + end; +for a := b + 1 to High(t) do t[a] := ''; +Result := b; +end; + +function OrdD(const From: string; const Index: integer): integer; +begin +if Index <= Length(From) then Result := Ord(From[Index]) + else Result := 0; +end; + +function CardWatcherThread(PContext: pointer): integer; +var + RetVar : cardinal; + RContext : cardinal; + RStates : array[0..1] of SCARD_READERSTATEA; +begin + try + RContext := cardinal(PContext^); + FillChar(RStates,SizeOf(RStates),#0); + RStates[0].szReader := SelectedReader; + RStates[0].pvUserData := nil; + RStates[0].dwEventState := ActReaderState; + while ReaderOpen do + begin + RStates[0].dwCurrentState := RStates[0].dwEventState; + RetVar := SCardGetStatusChangeA(RContext, -1, RStates, 1); + ActReaderState := RStates[0].dwEventState; + PostMessage(NotifyHandle, WM_CARDSTATE, RetVar, 0); + end; + finally + Result := 0; + end; +end; + +procedure TPCSCConnector.MessageWndProc(var Msg: TMessage); +begin + if (Msg.Msg = WM_CARDSTATE) then + begin + if Msg.WParam <> SCARD_S_SUCCESS then + if Assigned(FOnError) then FOnError(Self, esGetStatus, Msg.WParam); + if ActReaderState <> LastReaderState then + begin + ProcessReaderState(LastReaderState, ActReaderState); + end; + end + else Msg.Result := DefWindowProc(NotifyHandle, Msg.Msg, Msg.WParam, Msg.LParam); +end; + +constructor TPCSCConnector.Create(AOwner: TComponent); +begin + inherited Create(AOwner); + FReaderList := TStringlist.Create; + FContext := 0; + FCardHandle := 0; + FNumReaders := 0; + FUseReaderNum := -1; + FConnected := false; + ActReaderState := SCARD_STATE_UNAWARE; + LastReaderState := SCARD_STATE_UNAWARE; + ReaderOpen := false; + ClearReaderAttributes; + ClearCardAttributes; + if not (csDesigning in ComponentState) then NotifyHandle := AllocateHWnd(MessageWndProc); +end; + +destructor TPCSCConnector.Destroy; +begin + CloseAndDisconnect; + SCardReleaseContext(FContext); + FReaderList.Free; + if not (csDesigning in ComponentState) then DeallocateHWnd(NotifyHandle); + inherited Destroy; +end; + +function TPCSCConnector.Init: boolean; +var + RetVar : cardinal; + ReaderList : string; + ReaderListSize : integer; + v : array[0..MAXIMUM_SMARTCARD_READERS] of string; + i : integer; + +begin + Result := false; + FNumReaders := 0; + CloseAndDisconnect; + if SCardIsValidContext(FContext) = SCARD_S_SUCCESS then SCardReleaseContext(FContext); + RetVar := SCardEstablishContext(SCARD_SCOPE_USER, nil, nil, @FContext); + if RetVar = SCARD_S_SUCCESS then + begin + ReaderListSize := 0; + RetVar := SCardListReadersW(FContext, nil, nil, ReaderListSize); + if RetVar = SCARD_S_SUCCESS then + begin + SetLength(ReaderList, ReaderListSize); + SCardListReadersW(FContext, nil, Pointer(ReaderList), ReaderListSize); + FReaderList.Clear; + SortOutSubstrings(ReaderList,v,[#0]); + for i := 0 to MAXIMUM_SMARTCARD_READERS do + if v[i] <> '' then FReaderList.Add(v[i]); + FNumReaders := FReaderList.Count; + if FNumReaders > 0 then + begin + if Assigned(FOnReaderListChange) then FOnReaderListChange(Self); + Result := true; + end; + end else if Assigned(FOnError) then FOnError(Self, esInit, RetVar); + end else if Assigned(FOnError) then FOnError(Self, esInit, RetVar); +end; + +function TPCSCConnector.Open: boolean; +var + ThreadID : LongWord; +begin + CloseAndDisconnect; + if (FUseReaderNum > NOREADERSELECTED) and + (SCardIsValidContext(FContext) = SCARD_S_SUCCESS) then + begin + ReaderOpen := true; + ActReaderState := SCARD_STATE_UNAWARE; + LastReaderState := SCARD_STATE_UNAWARE; + BeginThread(nil, 0, CardWatcherThread, @FContext, 0, ThreadID); + Result := true; + end else Result := false; +end; + +procedure TPCSCConnector.Close; +begin + ReaderOpen := false; + SCardCancel(FContext); + if FConnected then Disconnect; +end; + +function TPCSCConnector.Connect: boolean; +begin + if FConnected then Disconnect; + if FUseReaderNum > NOREADERSELECTED then + if ConnectSelectedReader then FConnected := true + else FConnected := false; + Result := FConnected; +end; + +procedure TPCSCConnector.Disconnect; +begin + if FConnected then + begin + SCardDisconnect(FCardHandle, SCARD_RESET_CARD); + FConnected := false; + FCardHandle := 0; + end; +end; + +procedure TPCSCConnector.CloseAndDisconnect; +begin + if FConnected then Disconnect; + if ReaderOpen then Close; +end; + +function TPCSCConnector.ConnectSelectedReader: boolean; +var + RetVar : cardinal; +begin + RetVar := SCardConnectW(FContext, + PWideChar(SelectedReader), + SCARD_SHARE_EXCLUSIVE, + SCARD_PROTOCOL_Tx, + FCardHandle, + @FAttrProtocol); + case RetVar of + SCARD_S_SUCCESS : begin + CardActiveAction; + Result := true; + end; + SCARD_W_REMOVED_CARD : begin + Result := true; + end; + else begin + Result := false; + if Assigned(FOnError) then FOnError(Self, esConnect, RetVar); + end; + end; +end; + +procedure TPCSCConnector.ProcessReaderState(const OldState,NewState: cardinal); +var + CardInOld, CardInNew : boolean; + ReaderEmOld, ReaderEmNew : boolean; + CardMuteOld, CardMuteNew : boolean; + CardIgnore : boolean; + +begin +CardInOld := (OldState and SCARD_STATE_PRESENT) > 0; +CardInNew := (NewState and SCARD_STATE_PRESENT) > 0; +ReaderEmOld := (OldState and SCARD_STATE_EMPTY) > 0; +ReaderEmNew := (NewState and SCARD_STATE_EMPTY) > 0; +CardMuteOld := (OldState and SCARD_STATE_MUTE) > 0; +CardMuteNew := (NewState and SCARD_STATE_MUTE) > 0; +CardIgnore := (NewState and SCARD_STATE_IGNORE) > 0; + +if CardMuteNew and + not CardMuteold then if Assigned(FOnCardInvalid) then FOnCardInvalid(Self); + +if CardInNew and + not CardInOld and + not CardMuteNew and + not CardIgnore then CardInsertedAction; + +if CardInOld and + not CardInNew then CardRemovedAction; + +if ReaderEmNew and + not ReaderEmOld then begin + if Assigned(FOnReaderWaiting) then FOnReaderWaiting(Self); + end; + +LastReaderState := NewState; +end; + +procedure TPCSCConnector.CardInsertedAction; +begin + if Assigned(FOnCardInserted) then FOnCardInserted(Self); + if FConnected then CardActiveAction; +end; + +procedure TPCSCConnector.CardActiveAction; +begin + GetReaderAttributes; + if FAttrProtocol <> SCARD_PROTOCOL_UNK then + begin + GetCardAttributes; + if Assigned(FOnCardActive) then FOnCardActive(Self); + end; +end; + +procedure TPCSCConnector.CardRemovedAction; +begin + ClearReaderAttributes; + ClearCardAttributes; + if Assigned(FOnCardRemoved) then FOnCardRemoved(Self); + Disconnect; +end; + +procedure TPCSCConnector.SetReaderNum(Value: Integer); +begin + if Value <> FUseReaderNum then + begin + CloseAndDisconnect; + if Value < FReaderList.Count then + begin + SelectedReader := PChar(FReaderList[Value]); + FUseReaderNum := Value; + end else + begin + SelectedReader := ''; + FUseReaderNum := -1; + end; + end; +end; + +function TPCSCConnector.IsReaderOpen: boolean; +begin + Result := ReaderOpen; +end; + +function TPCSCConnector.GetReaderState: cardinal; +begin + Result := ActReaderState; +end; + +procedure TPCSCConnector.GetReaderAttributes; +var + RetVar : cardinal; + ABuf : string; + AIBuf : integer; + ALen : integer; +begin + ABuf := StringOfChar(#0, 127); + ALen := Length(ABuf); + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_ATR_STRING, Pointer(ABuf), @ALen); + if RetVar = SCARD_S_SUCCESS then FAttrCardATR := Copy(ABuf, 1, ALen) + else FAttrCardATR := ''; + + ALen := Length(ABuf); + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_VENDOR_NAME, Pointer(ABuf), @ALen); + if RetVar = SCARD_S_SUCCESS then FAttrVendorName := Copy(ABuf, 1, ALen) + else FAttrVendorName := ''; + + ALen := Length(ABuf); + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_VENDOR_IFD_SERIAL_NO, Pointer(ABuf), @ALen); + if RetVar = SCARD_S_SUCCESS then FAttrVendorSerial := Copy(ABuf, 1, ALen) + else FAttrVendorSerial := ''; + + ALen := SizeOf(AIBuf); + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_CURRENT_PROTOCOL_TYPE, @AIBuf, @ALen); + if RetVar = SCARD_S_SUCCESS then FAttrProtocol := AIBuf + else FAttrProtocol := 0; + + ALen := SizeOf(AIBuf); + AIBuf := 0; + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_ICC_TYPE_PER_ATR, @AIBuf, @ALen); + if RetVar = SCARD_S_SUCCESS then begin + case AIBuf of + 1 : FAttrICCType := 'ISO7816A'; + 2 : FAttrICCType := 'ISO7816S'; + else FAttrICCType := 'UNKNOWN'; + end; + end + else FAttrICCType := ''; +end; + +procedure TPCSCConnector.GetCardAttributes; +begin +if GSMSelect(DFgsm900) = GSMStatusOK then + begin + FGSMVoltage30 := (OrdD(FGSMDirInfo, 14) and $10) > 0; + FGSMVoltage18 := (OrdD(FGSMDirInfo, 14) and $20) > 0; + end; +end; + +procedure TPCSCConnector.ClearReaderAttributes; +begin + FAttrCardATR := ''; + FAttrVendorName := ''; + FAttrVendorSerial := ''; + FAttrProtocol := 0; + FAttrICCType := ''; +end; + +procedure TPCSCConnector.ClearCardAttributes; +begin + FGSMCurrentFile := ''; + FGSMFileInfo := ''; + FGSMDirInfo := ''; + FGSMVoltage30 := false; + FGSMVoltage18 := false; +end; + +function TPCSCConnector.GetResponseFromCard(const APdu: string): string; +var + RetVar : cardinal; + SBuf : string; + SLen : cardinal; + RBuf : string; + RLen : cardinal; + Ppci : Pointer; +begin +SBuf := APdu; +RBuf := StringOfChar(#0,MAXAPDULENGTH); +if Length(SBuf) <= MAXAPDULENGTH then + begin + case FAttrProtocol of + SCARD_PROTOCOL_T0 : Ppci := @SCARD_PCI_T0; + SCARD_PROTOCOL_T1 : Ppci := @SCARD_PCI_T1; + else Ppci := nil; + end; + SLen := Length(APdu); + RLen := Length(RBuf); + RetVar := SCardTransmit(FCardHandle, Ppci, Pointer(SBuf), SLen, nil, Pointer(RBuf), @RLen); + if RetVar = SCARD_S_SUCCESS then + begin + Result := Copy(RBuf,1,RLen); + end else + begin + Result := ''; + if Assigned(FOnError) then FOnError(Self, esTransmit, RetVar); + end; + end; +end; + +function TPCSCConnector.GetResponseFromCard(const Command: string; var Data: string; var sw1, sw2: byte): boolean; +var + Answer : string; + AnswerL : integer; +begin +Answer := GetResponseFromCard(Command + Data); +AnswerL := Length(Answer); +if AnswerL >= 2 then + begin + Data := Copy(Answer, 1, AnswerL - 2); + sw1 := Ord(Answer[AnswerL - 1]); + sw2 := Ord(Answer[AnswerL]); + if sw1 = GSMStatusResponseData then + begin + Data := Chr(sw2); + if not GetResponseFromCard(GCGetResponse, Data, sw1, sw2) then + begin + Data := ''; + sw1 := 0; + sw2 := 0; + Result := false; + end else Result := true; + end else Result := true; + end else + begin + Data := ''; + sw1 := 0; + sw2 := 0; + Result := false; + end; +end; + +function TPCSCConnector.GSMStatus: integer; +var + Answer : string; + sw1, sw2 : byte; +begin + GetResponseFromCard(GCGetStatus, Answer, sw1, sw2); + Result := (sw1 shl 8) + sw2; + if Result = GSMStatusOK then + begin + FGSMDirInfo := Answer; + FGSMCurrentFile := Copy(Answer, 5, 2); + end else + begin + FGSMDirInfo := ''; + end; +end; + +function TPCSCConnector.GSMSelect(const FileID: string): integer; +var + Answer : string; + sw1, sw2 : byte; +begin + Answer := FileID; + GetResponseFromCard(GCSelectFile, Answer, sw1, sw2); + Result := (sw1 shl 8) + sw2; + if Result = GSMStatusOK then + begin + FGSMCurrentFile := Copy(Answer, 5, 2); + if OrdD(Answer, 7) = GSMFileTypeEF then + begin + FGSMFileInfo := Answer; + end else + begin + FGSMDirInfo := Answer; + end; + end; +end; + +function TPCSCConnector.GSMReadBinary(const Offset, Length: integer; var Data: string): integer; +var + Command : string; + sw1, sw2 : byte; +begin + Command := GCReadBinary + Chr(Offset div 256) + Chr(Offset mod 256) + Chr(Length mod 256); + GetResponseFromCard(Command, Data, sw1, sw2); + Result := (sw1 shl 8) + sw2; + if Result = GSMStatusOK then + begin + end; +end; + +end. + diff --git a/__history/PCSCConnector.pas.~115~ b/__history/PCSCConnector.pas.~115~ new file mode 100644 index 0000000..8d86978 --- /dev/null +++ b/__history/PCSCConnector.pas.~115~ @@ -0,0 +1,699 @@ +{******************************************************************} +{ } +{ PC/SC Interface component } +{ Helps you access a cardreader through Microsofts SmartCard API } +{ } +{ The Original Code is PCSCConnector.pas } +{ } +{ The Initial Developer of the Original Code is } +{ Norbert Huettisch (nobbi(at)nobbi.com) } +{ } +{ Any suggestions and improvements to the code are appreciated } +{ } +{ This Code uses a modified SCardErr.pas (included) } +{ This Code uses a modified WinSCard.pas (included) } +{ This code uses the original WinSmCrd.pas (included) } +{ } +{ All originally made by Chris Dickerson (chrisd(at)tsc.com), } +{ available as 'Interface units for the Microsoft Smart Card API' } +{ at the Project JEDI Homepage http://www.delphi-jedi.org } +{ } +{ Version info: } +{ 021230 - initial version } +{ 030101 - routed errors from 'init' to the OnError event } +{ } +{ } +{******************************************************************} +{ } +{ The contents of this file are subject to the } +{ } +{ Mozilla Public License Version 1.1 (the "License") } +{ } +{ You may not use this file except in compliance with the License. } +{ You may obtain a copy of the License at } +{ http://www.mozilla.org/MPL/ } +{ } +{ Software distributed under the License is distributed on an } +{ "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or } +{ implied. See the License for the specific language governing } +{ rights and limitations under the License. } +{ } +{******************************************************************} + +unit PCSCConnector; + +interface + +uses + Windows, Messages, Forms, Classes, SysUtils, + SCardErr, WinSCard, WinSmCrd; + +type + TErrSource = (esInit, esConnect, esGetStatus, esTransmit); + TNeededPIN = (npPIN1, npPIN2, npPUK1, npPUK2); + TDelimiters = set of Char; + + TPCSCErrorEvent = procedure(Sender: TObject; ErrSource: TErrSource; ErrCode: cardinal) of object; + TPCSCPinEvent = procedure(Sender: TObject; NeedPIN: TNeededPIN) of object; + +const + MAXAPDULENGTH = 260; // CLA + INS + P1..3 + 255Bytes + NOREADERSELECTED = -1; + SCARD_PCI_T0 : SCARD_IO_REQUEST = (dwProtocol:1; dbPciLength:8); + SCARD_PCI_T1 : SCARD_IO_REQUEST = (dwProtocol:2; dbPciLength:8); + SCARD_PROTOCOL_T0 = $00000001; + SCARD_PROTOCOL_T1 = $00000002; + SCARD_PROTOCOL_RAW = $00010000; + SCARD_PROTOCOL_UNK = $00000000; + + WM_CARDSTATE = WM_USER + 42; + + GSMStatusOK = $9000; + GSMStatusMemoryError = $9240; + GSMStatusNoEFSelected = $9400; + GSMStatusOutOfRange = $9402; + GSMStatusNotFound = $9404; + GSMStatusFCDoNotMatch = $9408; + GSMStatusCHVNeeded = $9802; + GSMStatusAuthFailed = $9804; + GSMStatusAuthFailedBl = $9840; + GSMStatusTechProblem = $6F00; + GSMStatusResponseData = $9F; + + GSMFileTypeRFU = 0; + GSMFileTypeMF = 1; + GSMFileTypeDF = 2; + GSMFileTypeEF = 4; + + GSMEfTransp = 0; + GSMEfLinFixed = 1; + GSMEfCyclic = 3; + +type + TPCSCConnector = class(TComponent) + + protected + FContext : cardinal; + FCardHandle : integer; + FConnected : boolean; + FNumReaders : integer; + FUseReaderNum : integer; + FReaderList : TStringlist; + FAttrProtocol : integer; + FAttrICCType : string; + FAttrCardATR : string; + FAttrVendorName : string; + FAttrVendorSerial : string; + FGSMCurrentFile : string; + FGSMFileInfo : string; + FGSMDirInfo : string; + FGSMVoltage30 : boolean; + FGSMVoltage18 : boolean; + + FOnReaderWaiting : TNotifyEvent; + FOnReaderListChange : TNotifyEvent; + FOnCardInserted : TNotifyEvent; + FOnCardActive : TNotifyEvent; + FOnCardRemoved : TNotifyEvent; + FOnCardInvalid : TNotifyEvent; + FOnError : TPCSCErrorEvent; + FOnCHVNeeded : TPCSCPinEvent; + + procedure SetReaderNum(Value: integer); + procedure MessageWndProc(var Msg: TMessage); + function ConnectSelectedReader: boolean; + procedure ProcessReaderState(const OldState,NewState: cardinal); + procedure GetReaderAttributes; + procedure GetCardAttributes; + procedure ClearReaderAttributes; + procedure ClearCardAttributes; + function IsReaderOpen: boolean; + function GetReaderState: cardinal; + procedure CloseAndDisconnect; + procedure CardInsertedAction; + procedure CardActiveAction; + procedure CardRemovedAction; + + public + constructor Create(AOwner: TComponent); override; + destructor Destroy; override; + function Init: boolean; + function Open: boolean; + procedure Close; + function Connect: boolean; + procedure Disconnect; + function GetResponseFromCard(const apdu: string): string; overload; + function GetResponseFromCard(const command: string; var data: string; var sw1, sw2: byte): boolean; overload; + + function GSMStatus: integer; + function GSMSelect(const FileID: string): integer; + function GSMReadBinary(const Offset, Length: integer; var Data: string): integer; + + published + property UseReaderNum: integer read FUseReaderNum write SetReaderNum default -1; + + property OnCardInserted: TNotifyEvent read FOnCardInserted write FOnCardInserted; + property OnCardActive: TNotifyEvent read FOnCardActive write FOnCardActive; + property OnCardRemoved: TNotifyEvent read FOnCardRemoved write FOnCardRemoved; + property OnCardInvalid: TNotifyEvent read FOnCardInvalid write FOnCardInvalid; + property OnReaderWaiting: TNotifyEvent read FOnReaderWaiting write FOnReaderWaiting; + property OnReaderListChange: TNotifyEvent read FOnReaderListChange write FOnReaderListChange; + property OnError: TPCSCErrorEvent read FOnError write FOnError; + property OnCHVNeeded: TPCSCPinEvent read FOnCHVNeeded write FOnCHVNeeded; + + property ReaderList: TStringList read FReaderList; + property NumReaders: integer read FNumReaders; + property Connected: boolean read FConnected; + property Opened: boolean read IsReaderOpen; + property ReaderState: cardinal read GetReaderState; + property AttrProtocol: integer read FAttrProtocol; + property AttrICCType: string read FAttrICCType; + property AttrCardATR: string read FAttrCardATR; + property AttrVendorName: string read FAttrVendorName; + property AttrVendorSerial: string read FAttrVendorSerial; + property GSMCurrentFile: string read FGSMCurrentFile; + property GSMFileInfo: string read FGSMFileInfo; + property GSMDirInfo: string read FGSMDirInfo; + property GSMVoltage30: boolean read FGSMVoltage30; + property GSMVoltage18: boolean read FGSMVoltage18; + end; + +procedure Register; + +implementation + +var + ActReaderState : cardinal; + LastReaderState : cardinal; + SelectedReader : PChar; + ReaderOpen : boolean; + NotifyHandle : HWND; + +const + + // GSM Commands + GCGetStatus = #$A0#$F2#$00#$00#$16; + GCGetResponse = #$A0#$C0#$00#$00; + GCSelectFile = #$A0#$A4#$00#$00#$02; + GCReadBinary = #$A0#$B0; + + GSMMasterFile = #$3f#$00; + DFgsm900 = #$7f#$20; + DFgsm1800 = #$7f#$21; + +procedure Register; +begin + RegisterComponents('More...', [TPCSCConnector]); +end; + +function SortOutSubstrings(const From:string; var t:array of string; const Delim:TDelimiters = [' ',';']; const ConcatDelim:boolean = true):integer; +var a,b,s,i : integer; + sep : boolean; +begin +a := 1; +b := Low(t); +s := 1; +i := 0; +sep := ConcatDelim; +t[b] := ''; + +while a <= Length(From) do + begin + if not (From[a] in Delim) then + begin + Inc(i); + sep := false; + end else + begin + if not sep then + begin + t[b] := Copy(From, s, i); + Inc(b); + if b > High(t) then Break; + t[b] := ''; + end; + if ConcatDelim then sep := true; + s := a + 1; + i := 0; + end; + Inc(a); + end; +if (b <= High(t)) and (i > 0) then + begin + t[b] := Copy(From, s, i); + Inc(b); + end; +for a := b + 1 to High(t) do t[a] := ''; +Result := b; +end; + +function OrdD(const From: string; const Index: integer): integer; +begin +if Index <= Length(From) then Result := Ord(From[Index]) + else Result := 0; +end; + +function CardWatcherThread(PContext: pointer): integer; +var + RetVar : cardinal; + RContext : cardinal; + RStates : array[0..1] of SCARD_READERSTATEA; +begin + try + RContext := cardinal(PContext^); + FillChar(RStates,SizeOf(RStates),#0); + RStates[0].szReader := PAnsichar(SelectedReader); + RStates[0].pvUserData := nil; + RStates[0].dwEventState := ActReaderState; + while ReaderOpen do + begin + RStates[0].dwCurrentState := RStates[0].dwEventState; + RetVar := SCardGetStatusChangeA(RContext, -1, RStates, 1); + ActReaderState := RStates[0].dwEventState; + PostMessage(NotifyHandle, WM_CARDSTATE, RetVar, 0); + end; + finally + Result := 0; + end; +end; + +procedure TPCSCConnector.MessageWndProc(var Msg: TMessage); +begin + if (Msg.Msg = WM_CARDSTATE) then + begin + if Msg.WParam <> SCARD_S_SUCCESS then + if Assigned(FOnError) then FOnError(Self, esGetStatus, Msg.WParam); + if ActReaderState <> LastReaderState then + begin + ProcessReaderState(LastReaderState, ActReaderState); + end; + end + else Msg.Result := DefWindowProc(NotifyHandle, Msg.Msg, Msg.WParam, Msg.LParam); +end; + +constructor TPCSCConnector.Create(AOwner: TComponent); +begin + inherited Create(AOwner); + FReaderList := TStringlist.Create; + FContext := 0; + FCardHandle := 0; + FNumReaders := 0; + FUseReaderNum := -1; + FConnected := false; + ActReaderState := SCARD_STATE_UNAWARE; + LastReaderState := SCARD_STATE_UNAWARE; + ReaderOpen := false; + ClearReaderAttributes; + ClearCardAttributes; + if not (csDesigning in ComponentState) then NotifyHandle := AllocateHWnd(MessageWndProc); +end; + +destructor TPCSCConnector.Destroy; +begin + CloseAndDisconnect; + SCardReleaseContext(FContext); + FReaderList.Free; + if not (csDesigning in ComponentState) then DeallocateHWnd(NotifyHandle); + inherited Destroy; +end; + +function TPCSCConnector.Init: boolean; +var + RetVar : cardinal; + ReaderList : string; + ReaderListSize : integer; + v : array[0..MAXIMUM_SMARTCARD_READERS] of string; + i : integer; + +begin + Result := false; + FNumReaders := 0; + CloseAndDisconnect; + if SCardIsValidContext(FContext) = SCARD_S_SUCCESS then SCardReleaseContext(FContext); + RetVar := SCardEstablishContext(SCARD_SCOPE_USER, nil, nil, @FContext); + if RetVar = SCARD_S_SUCCESS then + begin + ReaderListSize := 0; + RetVar := SCardListReadersW(FContext, nil, nil, ReaderListSize); + if RetVar = SCARD_S_SUCCESS then + begin + SetLength(ReaderList, ReaderListSize); + SCardListReadersW(FContext, nil, Pointer(ReaderList), ReaderListSize); + FReaderList.Clear; + SortOutSubstrings(ReaderList,v,[#0]); + for i := 0 to MAXIMUM_SMARTCARD_READERS do + if v[i] <> '' then FReaderList.Add(v[i]); + FNumReaders := FReaderList.Count; + if FNumReaders > 0 then + begin + if Assigned(FOnReaderListChange) then FOnReaderListChange(Self); + Result := true; + end; + end else if Assigned(FOnError) then FOnError(Self, esInit, RetVar); + end else if Assigned(FOnError) then FOnError(Self, esInit, RetVar); +end; + +function TPCSCConnector.Open: boolean; +var + ThreadID : LongWord; +begin + CloseAndDisconnect; + if (FUseReaderNum > NOREADERSELECTED) and + (SCardIsValidContext(FContext) = SCARD_S_SUCCESS) then + begin + ReaderOpen := true; + ActReaderState := SCARD_STATE_UNAWARE; + LastReaderState := SCARD_STATE_UNAWARE; + BeginThread(nil, 0, CardWatcherThread, @FContext, 0, ThreadID); + Result := true; + end else Result := false; +end; + +procedure TPCSCConnector.Close; +begin + ReaderOpen := false; + SCardCancel(FContext); + if FConnected then Disconnect; +end; + +function TPCSCConnector.Connect: boolean; +begin + if FConnected then Disconnect; + if FUseReaderNum > NOREADERSELECTED then + if ConnectSelectedReader then FConnected := true + else FConnected := false; + Result := FConnected; +end; + +procedure TPCSCConnector.Disconnect; +begin + if FConnected then + begin + SCardDisconnect(FCardHandle, SCARD_RESET_CARD); + FConnected := false; + FCardHandle := 0; + end; +end; + +procedure TPCSCConnector.CloseAndDisconnect; +begin + if FConnected then Disconnect; + if ReaderOpen then Close; +end; + +function TPCSCConnector.ConnectSelectedReader: boolean; +var + RetVar : cardinal; +begin + RetVar := SCardConnectW(FContext, + PWideChar(SelectedReader), + SCARD_SHARE_EXCLUSIVE, + SCARD_PROTOCOL_Tx, + FCardHandle, + @FAttrProtocol); + case RetVar of + SCARD_S_SUCCESS : begin + CardActiveAction; + Result := true; + end; + SCARD_W_REMOVED_CARD : begin + Result := true; + end; + else begin + Result := false; + if Assigned(FOnError) then FOnError(Self, esConnect, RetVar); + end; + end; +end; + +procedure TPCSCConnector.ProcessReaderState(const OldState,NewState: cardinal); +var + CardInOld, CardInNew : boolean; + ReaderEmOld, ReaderEmNew : boolean; + CardMuteOld, CardMuteNew : boolean; + CardIgnore : boolean; + +begin +CardInOld := (OldState and SCARD_STATE_PRESENT) > 0; +CardInNew := (NewState and SCARD_STATE_PRESENT) > 0; +ReaderEmOld := (OldState and SCARD_STATE_EMPTY) > 0; +ReaderEmNew := (NewState and SCARD_STATE_EMPTY) > 0; +CardMuteOld := (OldState and SCARD_STATE_MUTE) > 0; +CardMuteNew := (NewState and SCARD_STATE_MUTE) > 0; +CardIgnore := (NewState and SCARD_STATE_IGNORE) > 0; + +if CardMuteNew and + not CardMuteold then if Assigned(FOnCardInvalid) then FOnCardInvalid(Self); + +if CardInNew and + not CardInOld and + not CardMuteNew and + not CardIgnore then CardInsertedAction; + +if CardInOld and + not CardInNew then CardRemovedAction; + +if ReaderEmNew and + not ReaderEmOld then begin + if Assigned(FOnReaderWaiting) then FOnReaderWaiting(Self); + end; + +LastReaderState := NewState; +end; + +procedure TPCSCConnector.CardInsertedAction; +begin + if Assigned(FOnCardInserted) then FOnCardInserted(Self); + if FConnected then CardActiveAction; +end; + +procedure TPCSCConnector.CardActiveAction; +begin + GetReaderAttributes; + if FAttrProtocol <> SCARD_PROTOCOL_UNK then + begin + GetCardAttributes; + if Assigned(FOnCardActive) then FOnCardActive(Self); + end; +end; + +procedure TPCSCConnector.CardRemovedAction; +begin + ClearReaderAttributes; + ClearCardAttributes; + if Assigned(FOnCardRemoved) then FOnCardRemoved(Self); + Disconnect; +end; + +procedure TPCSCConnector.SetReaderNum(Value: Integer); +begin + if Value <> FUseReaderNum then + begin + CloseAndDisconnect; + if Value < FReaderList.Count then + begin + SelectedReader := PChar(FReaderList[Value]); + FUseReaderNum := Value; + end else + begin + SelectedReader := ''; + FUseReaderNum := -1; + end; + end; +end; + +function TPCSCConnector.IsReaderOpen: boolean; +begin + Result := ReaderOpen; +end; + +function TPCSCConnector.GetReaderState: cardinal; +begin + Result := ActReaderState; +end; + +procedure TPCSCConnector.GetReaderAttributes; +var + RetVar : cardinal; + ABuf : string; + AIBuf : integer; + ALen : integer; +begin + ABuf := StringOfChar(#0, 127); + ALen := Length(ABuf); + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_ATR_STRING, Pointer(ABuf), @ALen); + if RetVar = SCARD_S_SUCCESS then FAttrCardATR := Copy(ABuf, 1, ALen) + else FAttrCardATR := ''; + + ALen := Length(ABuf); + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_VENDOR_NAME, Pointer(ABuf), @ALen); + if RetVar = SCARD_S_SUCCESS then FAttrVendorName := Copy(ABuf, 1, ALen) + else FAttrVendorName := ''; + + ALen := Length(ABuf); + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_VENDOR_IFD_SERIAL_NO, Pointer(ABuf), @ALen); + if RetVar = SCARD_S_SUCCESS then FAttrVendorSerial := Copy(ABuf, 1, ALen) + else FAttrVendorSerial := ''; + + ALen := SizeOf(AIBuf); + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_CURRENT_PROTOCOL_TYPE, @AIBuf, @ALen); + if RetVar = SCARD_S_SUCCESS then FAttrProtocol := AIBuf + else FAttrProtocol := 0; + + ALen := SizeOf(AIBuf); + AIBuf := 0; + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_ICC_TYPE_PER_ATR, @AIBuf, @ALen); + if RetVar = SCARD_S_SUCCESS then begin + case AIBuf of + 1 : FAttrICCType := 'ISO7816A'; + 2 : FAttrICCType := 'ISO7816S'; + else FAttrICCType := 'UNKNOWN'; + end; + end + else FAttrICCType := ''; +end; + +procedure TPCSCConnector.GetCardAttributes; +begin +if GSMSelect(DFgsm900) = GSMStatusOK then + begin + FGSMVoltage30 := (OrdD(FGSMDirInfo, 14) and $10) > 0; + FGSMVoltage18 := (OrdD(FGSMDirInfo, 14) and $20) > 0; + end; +end; + +procedure TPCSCConnector.ClearReaderAttributes; +begin + FAttrCardATR := ''; + FAttrVendorName := ''; + FAttrVendorSerial := ''; + FAttrProtocol := 0; + FAttrICCType := ''; +end; + +procedure TPCSCConnector.ClearCardAttributes; +begin + FGSMCurrentFile := ''; + FGSMFileInfo := ''; + FGSMDirInfo := ''; + FGSMVoltage30 := false; + FGSMVoltage18 := false; +end; + +function TPCSCConnector.GetResponseFromCard(const APdu: string): string; +var + RetVar : cardinal; + SBuf : string; + SLen : cardinal; + RBuf : string; + RLen : cardinal; + Ppci : Pointer; +begin +SBuf := APdu; +RBuf := StringOfChar(#0,MAXAPDULENGTH); +if Length(SBuf) <= MAXAPDULENGTH then + begin + case FAttrProtocol of + SCARD_PROTOCOL_T0 : Ppci := @SCARD_PCI_T0; + SCARD_PROTOCOL_T1 : Ppci := @SCARD_PCI_T1; + else Ppci := nil; + end; + SLen := Length(APdu); + RLen := Length(RBuf); + RetVar := SCardTransmit(FCardHandle, Ppci, Pointer(SBuf), SLen, nil, Pointer(RBuf), @RLen); + if RetVar = SCARD_S_SUCCESS then + begin + Result := Copy(RBuf,1,RLen); + end else + begin + Result := ''; + if Assigned(FOnError) then FOnError(Self, esTransmit, RetVar); + end; + end; +end; + +function TPCSCConnector.GetResponseFromCard(const Command: string; var Data: string; var sw1, sw2: byte): boolean; +var + Answer : string; + AnswerL : integer; +begin +Answer := GetResponseFromCard(Command + Data); +AnswerL := Length(Answer); +if AnswerL >= 2 then + begin + Data := Copy(Answer, 1, AnswerL - 2); + sw1 := Ord(Answer[AnswerL - 1]); + sw2 := Ord(Answer[AnswerL]); + if sw1 = GSMStatusResponseData then + begin + Data := Chr(sw2); + if not GetResponseFromCard(GCGetResponse, Data, sw1, sw2) then + begin + Data := ''; + sw1 := 0; + sw2 := 0; + Result := false; + end else Result := true; + end else Result := true; + end else + begin + Data := ''; + sw1 := 0; + sw2 := 0; + Result := false; + end; +end; + +function TPCSCConnector.GSMStatus: integer; +var + Answer : string; + sw1, sw2 : byte; +begin + GetResponseFromCard(GCGetStatus, Answer, sw1, sw2); + Result := (sw1 shl 8) + sw2; + if Result = GSMStatusOK then + begin + FGSMDirInfo := Answer; + FGSMCurrentFile := Copy(Answer, 5, 2); + end else + begin + FGSMDirInfo := ''; + end; +end; + +function TPCSCConnector.GSMSelect(const FileID: string): integer; +var + Answer : string; + sw1, sw2 : byte; +begin + Answer := FileID; + GetResponseFromCard(GCSelectFile, Answer, sw1, sw2); + Result := (sw1 shl 8) + sw2; + if Result = GSMStatusOK then + begin + FGSMCurrentFile := Copy(Answer, 5, 2); + if OrdD(Answer, 7) = GSMFileTypeEF then + begin + FGSMFileInfo := Answer; + end else + begin + FGSMDirInfo := Answer; + end; + end; +end; + +function TPCSCConnector.GSMReadBinary(const Offset, Length: integer; var Data: string): integer; +var + Command : string; + sw1, sw2 : byte; +begin + Command := GCReadBinary + Chr(Offset div 256) + Chr(Offset mod 256) + Chr(Length mod 256); + GetResponseFromCard(Command, Data, sw1, sw2); + Result := (sw1 shl 8) + sw2; + if Result = GSMStatusOK then + begin + end; +end; + +end. + diff --git a/__history/PCSCConnector.pas.~116~ b/__history/PCSCConnector.pas.~116~ new file mode 100644 index 0000000..7beaaa7 --- /dev/null +++ b/__history/PCSCConnector.pas.~116~ @@ -0,0 +1,699 @@ +{******************************************************************} +{ } +{ PC/SC Interface component } +{ Helps you access a cardreader through Microsofts SmartCard API } +{ } +{ The Original Code is PCSCConnector.pas } +{ } +{ The Initial Developer of the Original Code is } +{ Norbert Huettisch (nobbi(at)nobbi.com) } +{ } +{ Any suggestions and improvements to the code are appreciated } +{ } +{ This Code uses a modified SCardErr.pas (included) } +{ This Code uses a modified WinSCard.pas (included) } +{ This code uses the original WinSmCrd.pas (included) } +{ } +{ All originally made by Chris Dickerson (chrisd(at)tsc.com), } +{ available as 'Interface units for the Microsoft Smart Card API' } +{ at the Project JEDI Homepage http://www.delphi-jedi.org } +{ } +{ Version info: } +{ 021230 - initial version } +{ 030101 - routed errors from 'init' to the OnError event } +{ } +{ } +{******************************************************************} +{ } +{ The contents of this file are subject to the } +{ } +{ Mozilla Public License Version 1.1 (the "License") } +{ } +{ You may not use this file except in compliance with the License. } +{ You may obtain a copy of the License at } +{ http://www.mozilla.org/MPL/ } +{ } +{ Software distributed under the License is distributed on an } +{ "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or } +{ implied. See the License for the specific language governing } +{ rights and limitations under the License. } +{ } +{******************************************************************} + +unit PCSCConnector; + +interface + +uses + Windows, Messages, Forms, Classes, SysUtils, + SCardErr, WinSCard, WinSmCrd; + +type + TErrSource = (esInit, esConnect, esGetStatus, esTransmit); + TNeededPIN = (npPIN1, npPIN2, npPUK1, npPUK2); + TDelimiters = set of Char; + + TPCSCErrorEvent = procedure(Sender: TObject; ErrSource: TErrSource; ErrCode: cardinal) of object; + TPCSCPinEvent = procedure(Sender: TObject; NeedPIN: TNeededPIN) of object; + +const + MAXAPDULENGTH = 260; // CLA + INS + P1..3 + 255Bytes + NOREADERSELECTED = -1; + SCARD_PCI_T0 : SCARD_IO_REQUEST = (dwProtocol:1; dbPciLength:8); + SCARD_PCI_T1 : SCARD_IO_REQUEST = (dwProtocol:2; dbPciLength:8); + SCARD_PROTOCOL_T0 = $00000001; + SCARD_PROTOCOL_T1 = $00000002; + SCARD_PROTOCOL_RAW = $00010000; + SCARD_PROTOCOL_UNK = $00000000; + + WM_CARDSTATE = WM_USER + 42; + + GSMStatusOK = $9000; + GSMStatusMemoryError = $9240; + GSMStatusNoEFSelected = $9400; + GSMStatusOutOfRange = $9402; + GSMStatusNotFound = $9404; + GSMStatusFCDoNotMatch = $9408; + GSMStatusCHVNeeded = $9802; + GSMStatusAuthFailed = $9804; + GSMStatusAuthFailedBl = $9840; + GSMStatusTechProblem = $6F00; + GSMStatusResponseData = $9F; + + GSMFileTypeRFU = 0; + GSMFileTypeMF = 1; + GSMFileTypeDF = 2; + GSMFileTypeEF = 4; + + GSMEfTransp = 0; + GSMEfLinFixed = 1; + GSMEfCyclic = 3; + +type + TPCSCConnector = class(TComponent) + + protected + FContext : cardinal; + FCardHandle : integer; + FConnected : boolean; + FNumReaders : integer; + FUseReaderNum : integer; + FReaderList : TStringlist; + FAttrProtocol : integer; + FAttrICCType : string; + FAttrCardATR : string; + FAttrVendorName : string; + FAttrVendorSerial : string; + FGSMCurrentFile : string; + FGSMFileInfo : string; + FGSMDirInfo : string; + FGSMVoltage30 : boolean; + FGSMVoltage18 : boolean; + + FOnReaderWaiting : TNotifyEvent; + FOnReaderListChange : TNotifyEvent; + FOnCardInserted : TNotifyEvent; + FOnCardActive : TNotifyEvent; + FOnCardRemoved : TNotifyEvent; + FOnCardInvalid : TNotifyEvent; + FOnError : TPCSCErrorEvent; + FOnCHVNeeded : TPCSCPinEvent; + + procedure SetReaderNum(Value: integer); + procedure MessageWndProc(var Msg: TMessage); + function ConnectSelectedReader: boolean; + procedure ProcessReaderState(const OldState,NewState: cardinal); + procedure GetReaderAttributes; + procedure GetCardAttributes; + procedure ClearReaderAttributes; + procedure ClearCardAttributes; + function IsReaderOpen: boolean; + function GetReaderState: cardinal; + procedure CloseAndDisconnect; + procedure CardInsertedAction; + procedure CardActiveAction; + procedure CardRemovedAction; + + public + constructor Create(AOwner: TComponent); override; + destructor Destroy; override; + function Init: boolean; + function Open: boolean; + procedure Close; + function Connect: boolean; + procedure Disconnect; + function GetResponseFromCard(const apdu: string): string; overload; + function GetResponseFromCard(const command: string; var data: string; var sw1, sw2: byte): boolean; overload; + + function GSMStatus: integer; + function GSMSelect(const FileID: string): integer; + function GSMReadBinary(const Offset, Length: integer; var Data: string): integer; + + published + property UseReaderNum: integer read FUseReaderNum write SetReaderNum default -1; + + property OnCardInserted: TNotifyEvent read FOnCardInserted write FOnCardInserted; + property OnCardActive: TNotifyEvent read FOnCardActive write FOnCardActive; + property OnCardRemoved: TNotifyEvent read FOnCardRemoved write FOnCardRemoved; + property OnCardInvalid: TNotifyEvent read FOnCardInvalid write FOnCardInvalid; + property OnReaderWaiting: TNotifyEvent read FOnReaderWaiting write FOnReaderWaiting; + property OnReaderListChange: TNotifyEvent read FOnReaderListChange write FOnReaderListChange; + property OnError: TPCSCErrorEvent read FOnError write FOnError; + property OnCHVNeeded: TPCSCPinEvent read FOnCHVNeeded write FOnCHVNeeded; + + property ReaderList: TStringList read FReaderList; + property NumReaders: integer read FNumReaders; + property Connected: boolean read FConnected; + property Opened: boolean read IsReaderOpen; + property ReaderState: cardinal read GetReaderState; + property AttrProtocol: integer read FAttrProtocol; + property AttrICCType: string read FAttrICCType; + property AttrCardATR: string read FAttrCardATR; + property AttrVendorName: string read FAttrVendorName; + property AttrVendorSerial: string read FAttrVendorSerial; + property GSMCurrentFile: string read FGSMCurrentFile; + property GSMFileInfo: string read FGSMFileInfo; + property GSMDirInfo: string read FGSMDirInfo; + property GSMVoltage30: boolean read FGSMVoltage30; + property GSMVoltage18: boolean read FGSMVoltage18; + end; + +procedure Register; + +implementation + +var + ActReaderState : cardinal; + LastReaderState : cardinal; + SelectedReader : String; + ReaderOpen : boolean; + NotifyHandle : HWND; + +const + + // GSM Commands + GCGetStatus = #$A0#$F2#$00#$00#$16; + GCGetResponse = #$A0#$C0#$00#$00; + GCSelectFile = #$A0#$A4#$00#$00#$02; + GCReadBinary = #$A0#$B0; + + GSMMasterFile = #$3f#$00; + DFgsm900 = #$7f#$20; + DFgsm1800 = #$7f#$21; + +procedure Register; +begin + RegisterComponents('More...', [TPCSCConnector]); +end; + +function SortOutSubstrings(const From:string; var t:array of string; const Delim:TDelimiters = [' ',';']; const ConcatDelim:boolean = true):integer; +var a,b,s,i : integer; + sep : boolean; +begin +a := 1; +b := Low(t); +s := 1; +i := 0; +sep := ConcatDelim; +t[b] := ''; + +while a <= Length(From) do + begin + if not (From[a] in Delim) then + begin + Inc(i); + sep := false; + end else + begin + if not sep then + begin + t[b] := Copy(From, s, i); + Inc(b); + if b > High(t) then Break; + t[b] := ''; + end; + if ConcatDelim then sep := true; + s := a + 1; + i := 0; + end; + Inc(a); + end; +if (b <= High(t)) and (i > 0) then + begin + t[b] := Copy(From, s, i); + Inc(b); + end; +for a := b + 1 to High(t) do t[a] := ''; +Result := b; +end; + +function OrdD(const From: string; const Index: integer): integer; +begin +if Index <= Length(From) then Result := Ord(From[Index]) + else Result := 0; +end; + +function CardWatcherThread(PContext: pointer): integer; +var + RetVar : cardinal; + RContext : cardinal; + RStates : array[0..1] of SCARD_READERSTATEA; +begin + try + RContext := cardinal(PContext^); + FillChar(RStates,SizeOf(RStates),#0); + RStates[0].szReader := PAnsichar(SelectedReader); + RStates[0].pvUserData := nil; + RStates[0].dwEventState := ActReaderState; + while ReaderOpen do + begin + RStates[0].dwCurrentState := RStates[0].dwEventState; + RetVar := SCardGetStatusChangeA(RContext, -1, RStates, 1); + ActReaderState := RStates[0].dwEventState; + PostMessage(NotifyHandle, WM_CARDSTATE, RetVar, 0); + end; + finally + Result := 0; + end; +end; + +procedure TPCSCConnector.MessageWndProc(var Msg: TMessage); +begin + if (Msg.Msg = WM_CARDSTATE) then + begin + if Msg.WParam <> SCARD_S_SUCCESS then + if Assigned(FOnError) then FOnError(Self, esGetStatus, Msg.WParam); + if ActReaderState <> LastReaderState then + begin + ProcessReaderState(LastReaderState, ActReaderState); + end; + end + else Msg.Result := DefWindowProc(NotifyHandle, Msg.Msg, Msg.WParam, Msg.LParam); +end; + +constructor TPCSCConnector.Create(AOwner: TComponent); +begin + inherited Create(AOwner); + FReaderList := TStringlist.Create; + FContext := 0; + FCardHandle := 0; + FNumReaders := 0; + FUseReaderNum := -1; + FConnected := false; + ActReaderState := SCARD_STATE_UNAWARE; + LastReaderState := SCARD_STATE_UNAWARE; + ReaderOpen := false; + ClearReaderAttributes; + ClearCardAttributes; + if not (csDesigning in ComponentState) then NotifyHandle := AllocateHWnd(MessageWndProc); +end; + +destructor TPCSCConnector.Destroy; +begin + CloseAndDisconnect; + SCardReleaseContext(FContext); + FReaderList.Free; + if not (csDesigning in ComponentState) then DeallocateHWnd(NotifyHandle); + inherited Destroy; +end; + +function TPCSCConnector.Init: boolean; +var + RetVar : cardinal; + ReaderList : string; + ReaderListSize : integer; + v : array[0..MAXIMUM_SMARTCARD_READERS] of string; + i : integer; + +begin + Result := false; + FNumReaders := 0; + CloseAndDisconnect; + if SCardIsValidContext(FContext) = SCARD_S_SUCCESS then SCardReleaseContext(FContext); + RetVar := SCardEstablishContext(SCARD_SCOPE_USER, nil, nil, @FContext); + if RetVar = SCARD_S_SUCCESS then + begin + ReaderListSize := 0; + RetVar := SCardListReadersW(FContext, nil, nil, ReaderListSize); + if RetVar = SCARD_S_SUCCESS then + begin + SetLength(ReaderList, ReaderListSize); + SCardListReadersW(FContext, nil, Pointer(ReaderList), ReaderListSize); + FReaderList.Clear; + SortOutSubstrings(ReaderList,v,[#0]); + for i := 0 to MAXIMUM_SMARTCARD_READERS do + if v[i] <> '' then FReaderList.Add(v[i]); + FNumReaders := FReaderList.Count; + if FNumReaders > 0 then + begin + if Assigned(FOnReaderListChange) then FOnReaderListChange(Self); + Result := true; + end; + end else if Assigned(FOnError) then FOnError(Self, esInit, RetVar); + end else if Assigned(FOnError) then FOnError(Self, esInit, RetVar); +end; + +function TPCSCConnector.Open: boolean; +var + ThreadID : LongWord; +begin + CloseAndDisconnect; + if (FUseReaderNum > NOREADERSELECTED) and + (SCardIsValidContext(FContext) = SCARD_S_SUCCESS) then + begin + ReaderOpen := true; + ActReaderState := SCARD_STATE_UNAWARE; + LastReaderState := SCARD_STATE_UNAWARE; + BeginThread(nil, 0, CardWatcherThread, @FContext, 0, ThreadID); + Result := true; + end else Result := false; +end; + +procedure TPCSCConnector.Close; +begin + ReaderOpen := false; + SCardCancel(FContext); + if FConnected then Disconnect; +end; + +function TPCSCConnector.Connect: boolean; +begin + if FConnected then Disconnect; + if FUseReaderNum > NOREADERSELECTED then + if ConnectSelectedReader then FConnected := true + else FConnected := false; + Result := FConnected; +end; + +procedure TPCSCConnector.Disconnect; +begin + if FConnected then + begin + SCardDisconnect(FCardHandle, SCARD_RESET_CARD); + FConnected := false; + FCardHandle := 0; + end; +end; + +procedure TPCSCConnector.CloseAndDisconnect; +begin + if FConnected then Disconnect; + if ReaderOpen then Close; +end; + +function TPCSCConnector.ConnectSelectedReader: boolean; +var + RetVar : cardinal; +begin + RetVar := SCardConnectW(FContext, + PWideChar(SelectedReader), + SCARD_SHARE_EXCLUSIVE, + SCARD_PROTOCOL_Tx, + FCardHandle, + @FAttrProtocol); + case RetVar of + SCARD_S_SUCCESS : begin + CardActiveAction; + Result := true; + end; + SCARD_W_REMOVED_CARD : begin + Result := true; + end; + else begin + Result := false; + if Assigned(FOnError) then FOnError(Self, esConnect, RetVar); + end; + end; +end; + +procedure TPCSCConnector.ProcessReaderState(const OldState,NewState: cardinal); +var + CardInOld, CardInNew : boolean; + ReaderEmOld, ReaderEmNew : boolean; + CardMuteOld, CardMuteNew : boolean; + CardIgnore : boolean; + +begin +CardInOld := (OldState and SCARD_STATE_PRESENT) > 0; +CardInNew := (NewState and SCARD_STATE_PRESENT) > 0; +ReaderEmOld := (OldState and SCARD_STATE_EMPTY) > 0; +ReaderEmNew := (NewState and SCARD_STATE_EMPTY) > 0; +CardMuteOld := (OldState and SCARD_STATE_MUTE) > 0; +CardMuteNew := (NewState and SCARD_STATE_MUTE) > 0; +CardIgnore := (NewState and SCARD_STATE_IGNORE) > 0; + +if CardMuteNew and + not CardMuteold then if Assigned(FOnCardInvalid) then FOnCardInvalid(Self); + +if CardInNew and + not CardInOld and + not CardMuteNew and + not CardIgnore then CardInsertedAction; + +if CardInOld and + not CardInNew then CardRemovedAction; + +if ReaderEmNew and + not ReaderEmOld then begin + if Assigned(FOnReaderWaiting) then FOnReaderWaiting(Self); + end; + +LastReaderState := NewState; +end; + +procedure TPCSCConnector.CardInsertedAction; +begin + if Assigned(FOnCardInserted) then FOnCardInserted(Self); + if FConnected then CardActiveAction; +end; + +procedure TPCSCConnector.CardActiveAction; +begin + GetReaderAttributes; + if FAttrProtocol <> SCARD_PROTOCOL_UNK then + begin + GetCardAttributes; + if Assigned(FOnCardActive) then FOnCardActive(Self); + end; +end; + +procedure TPCSCConnector.CardRemovedAction; +begin + ClearReaderAttributes; + ClearCardAttributes; + if Assigned(FOnCardRemoved) then FOnCardRemoved(Self); + Disconnect; +end; + +procedure TPCSCConnector.SetReaderNum(Value: Integer); +begin + if Value <> FUseReaderNum then + begin + CloseAndDisconnect; + if Value < FReaderList.Count then + begin + SelectedReader := PChar(FReaderList[Value]); + FUseReaderNum := Value; + end else + begin + SelectedReader := ''; + FUseReaderNum := -1; + end; + end; +end; + +function TPCSCConnector.IsReaderOpen: boolean; +begin + Result := ReaderOpen; +end; + +function TPCSCConnector.GetReaderState: cardinal; +begin + Result := ActReaderState; +end; + +procedure TPCSCConnector.GetReaderAttributes; +var + RetVar : cardinal; + ABuf : string; + AIBuf : integer; + ALen : integer; +begin + ABuf := StringOfChar(#0, 127); + ALen := Length(ABuf); + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_ATR_STRING, Pointer(ABuf), @ALen); + if RetVar = SCARD_S_SUCCESS then FAttrCardATR := Copy(ABuf, 1, ALen) + else FAttrCardATR := ''; + + ALen := Length(ABuf); + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_VENDOR_NAME, Pointer(ABuf), @ALen); + if RetVar = SCARD_S_SUCCESS then FAttrVendorName := Copy(ABuf, 1, ALen) + else FAttrVendorName := ''; + + ALen := Length(ABuf); + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_VENDOR_IFD_SERIAL_NO, Pointer(ABuf), @ALen); + if RetVar = SCARD_S_SUCCESS then FAttrVendorSerial := Copy(ABuf, 1, ALen) + else FAttrVendorSerial := ''; + + ALen := SizeOf(AIBuf); + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_CURRENT_PROTOCOL_TYPE, @AIBuf, @ALen); + if RetVar = SCARD_S_SUCCESS then FAttrProtocol := AIBuf + else FAttrProtocol := 0; + + ALen := SizeOf(AIBuf); + AIBuf := 0; + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_ICC_TYPE_PER_ATR, @AIBuf, @ALen); + if RetVar = SCARD_S_SUCCESS then begin + case AIBuf of + 1 : FAttrICCType := 'ISO7816A'; + 2 : FAttrICCType := 'ISO7816S'; + else FAttrICCType := 'UNKNOWN'; + end; + end + else FAttrICCType := ''; +end; + +procedure TPCSCConnector.GetCardAttributes; +begin +if GSMSelect(DFgsm900) = GSMStatusOK then + begin + FGSMVoltage30 := (OrdD(FGSMDirInfo, 14) and $10) > 0; + FGSMVoltage18 := (OrdD(FGSMDirInfo, 14) and $20) > 0; + end; +end; + +procedure TPCSCConnector.ClearReaderAttributes; +begin + FAttrCardATR := ''; + FAttrVendorName := ''; + FAttrVendorSerial := ''; + FAttrProtocol := 0; + FAttrICCType := ''; +end; + +procedure TPCSCConnector.ClearCardAttributes; +begin + FGSMCurrentFile := ''; + FGSMFileInfo := ''; + FGSMDirInfo := ''; + FGSMVoltage30 := false; + FGSMVoltage18 := false; +end; + +function TPCSCConnector.GetResponseFromCard(const APdu: string): string; +var + RetVar : cardinal; + SBuf : string; + SLen : cardinal; + RBuf : string; + RLen : cardinal; + Ppci : Pointer; +begin +SBuf := APdu; +RBuf := StringOfChar(#0,MAXAPDULENGTH); +if Length(SBuf) <= MAXAPDULENGTH then + begin + case FAttrProtocol of + SCARD_PROTOCOL_T0 : Ppci := @SCARD_PCI_T0; + SCARD_PROTOCOL_T1 : Ppci := @SCARD_PCI_T1; + else Ppci := nil; + end; + SLen := Length(APdu); + RLen := Length(RBuf); + RetVar := SCardTransmit(FCardHandle, Ppci, Pointer(SBuf), SLen, nil, Pointer(RBuf), @RLen); + if RetVar = SCARD_S_SUCCESS then + begin + Result := Copy(RBuf,1,RLen); + end else + begin + Result := ''; + if Assigned(FOnError) then FOnError(Self, esTransmit, RetVar); + end; + end; +end; + +function TPCSCConnector.GetResponseFromCard(const Command: string; var Data: string; var sw1, sw2: byte): boolean; +var + Answer : string; + AnswerL : integer; +begin +Answer := GetResponseFromCard(Command + Data); +AnswerL := Length(Answer); +if AnswerL >= 2 then + begin + Data := Copy(Answer, 1, AnswerL - 2); + sw1 := Ord(Answer[AnswerL - 1]); + sw2 := Ord(Answer[AnswerL]); + if sw1 = GSMStatusResponseData then + begin + Data := Chr(sw2); + if not GetResponseFromCard(GCGetResponse, Data, sw1, sw2) then + begin + Data := ''; + sw1 := 0; + sw2 := 0; + Result := false; + end else Result := true; + end else Result := true; + end else + begin + Data := ''; + sw1 := 0; + sw2 := 0; + Result := false; + end; +end; + +function TPCSCConnector.GSMStatus: integer; +var + Answer : string; + sw1, sw2 : byte; +begin + GetResponseFromCard(GCGetStatus, Answer, sw1, sw2); + Result := (sw1 shl 8) + sw2; + if Result = GSMStatusOK then + begin + FGSMDirInfo := Answer; + FGSMCurrentFile := Copy(Answer, 5, 2); + end else + begin + FGSMDirInfo := ''; + end; +end; + +function TPCSCConnector.GSMSelect(const FileID: string): integer; +var + Answer : string; + sw1, sw2 : byte; +begin + Answer := FileID; + GetResponseFromCard(GCSelectFile, Answer, sw1, sw2); + Result := (sw1 shl 8) + sw2; + if Result = GSMStatusOK then + begin + FGSMCurrentFile := Copy(Answer, 5, 2); + if OrdD(Answer, 7) = GSMFileTypeEF then + begin + FGSMFileInfo := Answer; + end else + begin + FGSMDirInfo := Answer; + end; + end; +end; + +function TPCSCConnector.GSMReadBinary(const Offset, Length: integer; var Data: string): integer; +var + Command : string; + sw1, sw2 : byte; +begin + Command := GCReadBinary + Chr(Offset div 256) + Chr(Offset mod 256) + Chr(Length mod 256); + GetResponseFromCard(Command, Data, sw1, sw2); + Result := (sw1 shl 8) + sw2; + if Result = GSMStatusOK then + begin + end; +end; + +end. + diff --git a/__history/PCSCConnector.pas.~117~ b/__history/PCSCConnector.pas.~117~ new file mode 100644 index 0000000..7beaaa7 --- /dev/null +++ b/__history/PCSCConnector.pas.~117~ @@ -0,0 +1,699 @@ +{******************************************************************} +{ } +{ PC/SC Interface component } +{ Helps you access a cardreader through Microsofts SmartCard API } +{ } +{ The Original Code is PCSCConnector.pas } +{ } +{ The Initial Developer of the Original Code is } +{ Norbert Huettisch (nobbi(at)nobbi.com) } +{ } +{ Any suggestions and improvements to the code are appreciated } +{ } +{ This Code uses a modified SCardErr.pas (included) } +{ This Code uses a modified WinSCard.pas (included) } +{ This code uses the original WinSmCrd.pas (included) } +{ } +{ All originally made by Chris Dickerson (chrisd(at)tsc.com), } +{ available as 'Interface units for the Microsoft Smart Card API' } +{ at the Project JEDI Homepage http://www.delphi-jedi.org } +{ } +{ Version info: } +{ 021230 - initial version } +{ 030101 - routed errors from 'init' to the OnError event } +{ } +{ } +{******************************************************************} +{ } +{ The contents of this file are subject to the } +{ } +{ Mozilla Public License Version 1.1 (the "License") } +{ } +{ You may not use this file except in compliance with the License. } +{ You may obtain a copy of the License at } +{ http://www.mozilla.org/MPL/ } +{ } +{ Software distributed under the License is distributed on an } +{ "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or } +{ implied. See the License for the specific language governing } +{ rights and limitations under the License. } +{ } +{******************************************************************} + +unit PCSCConnector; + +interface + +uses + Windows, Messages, Forms, Classes, SysUtils, + SCardErr, WinSCard, WinSmCrd; + +type + TErrSource = (esInit, esConnect, esGetStatus, esTransmit); + TNeededPIN = (npPIN1, npPIN2, npPUK1, npPUK2); + TDelimiters = set of Char; + + TPCSCErrorEvent = procedure(Sender: TObject; ErrSource: TErrSource; ErrCode: cardinal) of object; + TPCSCPinEvent = procedure(Sender: TObject; NeedPIN: TNeededPIN) of object; + +const + MAXAPDULENGTH = 260; // CLA + INS + P1..3 + 255Bytes + NOREADERSELECTED = -1; + SCARD_PCI_T0 : SCARD_IO_REQUEST = (dwProtocol:1; dbPciLength:8); + SCARD_PCI_T1 : SCARD_IO_REQUEST = (dwProtocol:2; dbPciLength:8); + SCARD_PROTOCOL_T0 = $00000001; + SCARD_PROTOCOL_T1 = $00000002; + SCARD_PROTOCOL_RAW = $00010000; + SCARD_PROTOCOL_UNK = $00000000; + + WM_CARDSTATE = WM_USER + 42; + + GSMStatusOK = $9000; + GSMStatusMemoryError = $9240; + GSMStatusNoEFSelected = $9400; + GSMStatusOutOfRange = $9402; + GSMStatusNotFound = $9404; + GSMStatusFCDoNotMatch = $9408; + GSMStatusCHVNeeded = $9802; + GSMStatusAuthFailed = $9804; + GSMStatusAuthFailedBl = $9840; + GSMStatusTechProblem = $6F00; + GSMStatusResponseData = $9F; + + GSMFileTypeRFU = 0; + GSMFileTypeMF = 1; + GSMFileTypeDF = 2; + GSMFileTypeEF = 4; + + GSMEfTransp = 0; + GSMEfLinFixed = 1; + GSMEfCyclic = 3; + +type + TPCSCConnector = class(TComponent) + + protected + FContext : cardinal; + FCardHandle : integer; + FConnected : boolean; + FNumReaders : integer; + FUseReaderNum : integer; + FReaderList : TStringlist; + FAttrProtocol : integer; + FAttrICCType : string; + FAttrCardATR : string; + FAttrVendorName : string; + FAttrVendorSerial : string; + FGSMCurrentFile : string; + FGSMFileInfo : string; + FGSMDirInfo : string; + FGSMVoltage30 : boolean; + FGSMVoltage18 : boolean; + + FOnReaderWaiting : TNotifyEvent; + FOnReaderListChange : TNotifyEvent; + FOnCardInserted : TNotifyEvent; + FOnCardActive : TNotifyEvent; + FOnCardRemoved : TNotifyEvent; + FOnCardInvalid : TNotifyEvent; + FOnError : TPCSCErrorEvent; + FOnCHVNeeded : TPCSCPinEvent; + + procedure SetReaderNum(Value: integer); + procedure MessageWndProc(var Msg: TMessage); + function ConnectSelectedReader: boolean; + procedure ProcessReaderState(const OldState,NewState: cardinal); + procedure GetReaderAttributes; + procedure GetCardAttributes; + procedure ClearReaderAttributes; + procedure ClearCardAttributes; + function IsReaderOpen: boolean; + function GetReaderState: cardinal; + procedure CloseAndDisconnect; + procedure CardInsertedAction; + procedure CardActiveAction; + procedure CardRemovedAction; + + public + constructor Create(AOwner: TComponent); override; + destructor Destroy; override; + function Init: boolean; + function Open: boolean; + procedure Close; + function Connect: boolean; + procedure Disconnect; + function GetResponseFromCard(const apdu: string): string; overload; + function GetResponseFromCard(const command: string; var data: string; var sw1, sw2: byte): boolean; overload; + + function GSMStatus: integer; + function GSMSelect(const FileID: string): integer; + function GSMReadBinary(const Offset, Length: integer; var Data: string): integer; + + published + property UseReaderNum: integer read FUseReaderNum write SetReaderNum default -1; + + property OnCardInserted: TNotifyEvent read FOnCardInserted write FOnCardInserted; + property OnCardActive: TNotifyEvent read FOnCardActive write FOnCardActive; + property OnCardRemoved: TNotifyEvent read FOnCardRemoved write FOnCardRemoved; + property OnCardInvalid: TNotifyEvent read FOnCardInvalid write FOnCardInvalid; + property OnReaderWaiting: TNotifyEvent read FOnReaderWaiting write FOnReaderWaiting; + property OnReaderListChange: TNotifyEvent read FOnReaderListChange write FOnReaderListChange; + property OnError: TPCSCErrorEvent read FOnError write FOnError; + property OnCHVNeeded: TPCSCPinEvent read FOnCHVNeeded write FOnCHVNeeded; + + property ReaderList: TStringList read FReaderList; + property NumReaders: integer read FNumReaders; + property Connected: boolean read FConnected; + property Opened: boolean read IsReaderOpen; + property ReaderState: cardinal read GetReaderState; + property AttrProtocol: integer read FAttrProtocol; + property AttrICCType: string read FAttrICCType; + property AttrCardATR: string read FAttrCardATR; + property AttrVendorName: string read FAttrVendorName; + property AttrVendorSerial: string read FAttrVendorSerial; + property GSMCurrentFile: string read FGSMCurrentFile; + property GSMFileInfo: string read FGSMFileInfo; + property GSMDirInfo: string read FGSMDirInfo; + property GSMVoltage30: boolean read FGSMVoltage30; + property GSMVoltage18: boolean read FGSMVoltage18; + end; + +procedure Register; + +implementation + +var + ActReaderState : cardinal; + LastReaderState : cardinal; + SelectedReader : String; + ReaderOpen : boolean; + NotifyHandle : HWND; + +const + + // GSM Commands + GCGetStatus = #$A0#$F2#$00#$00#$16; + GCGetResponse = #$A0#$C0#$00#$00; + GCSelectFile = #$A0#$A4#$00#$00#$02; + GCReadBinary = #$A0#$B0; + + GSMMasterFile = #$3f#$00; + DFgsm900 = #$7f#$20; + DFgsm1800 = #$7f#$21; + +procedure Register; +begin + RegisterComponents('More...', [TPCSCConnector]); +end; + +function SortOutSubstrings(const From:string; var t:array of string; const Delim:TDelimiters = [' ',';']; const ConcatDelim:boolean = true):integer; +var a,b,s,i : integer; + sep : boolean; +begin +a := 1; +b := Low(t); +s := 1; +i := 0; +sep := ConcatDelim; +t[b] := ''; + +while a <= Length(From) do + begin + if not (From[a] in Delim) then + begin + Inc(i); + sep := false; + end else + begin + if not sep then + begin + t[b] := Copy(From, s, i); + Inc(b); + if b > High(t) then Break; + t[b] := ''; + end; + if ConcatDelim then sep := true; + s := a + 1; + i := 0; + end; + Inc(a); + end; +if (b <= High(t)) and (i > 0) then + begin + t[b] := Copy(From, s, i); + Inc(b); + end; +for a := b + 1 to High(t) do t[a] := ''; +Result := b; +end; + +function OrdD(const From: string; const Index: integer): integer; +begin +if Index <= Length(From) then Result := Ord(From[Index]) + else Result := 0; +end; + +function CardWatcherThread(PContext: pointer): integer; +var + RetVar : cardinal; + RContext : cardinal; + RStates : array[0..1] of SCARD_READERSTATEA; +begin + try + RContext := cardinal(PContext^); + FillChar(RStates,SizeOf(RStates),#0); + RStates[0].szReader := PAnsichar(SelectedReader); + RStates[0].pvUserData := nil; + RStates[0].dwEventState := ActReaderState; + while ReaderOpen do + begin + RStates[0].dwCurrentState := RStates[0].dwEventState; + RetVar := SCardGetStatusChangeA(RContext, -1, RStates, 1); + ActReaderState := RStates[0].dwEventState; + PostMessage(NotifyHandle, WM_CARDSTATE, RetVar, 0); + end; + finally + Result := 0; + end; +end; + +procedure TPCSCConnector.MessageWndProc(var Msg: TMessage); +begin + if (Msg.Msg = WM_CARDSTATE) then + begin + if Msg.WParam <> SCARD_S_SUCCESS then + if Assigned(FOnError) then FOnError(Self, esGetStatus, Msg.WParam); + if ActReaderState <> LastReaderState then + begin + ProcessReaderState(LastReaderState, ActReaderState); + end; + end + else Msg.Result := DefWindowProc(NotifyHandle, Msg.Msg, Msg.WParam, Msg.LParam); +end; + +constructor TPCSCConnector.Create(AOwner: TComponent); +begin + inherited Create(AOwner); + FReaderList := TStringlist.Create; + FContext := 0; + FCardHandle := 0; + FNumReaders := 0; + FUseReaderNum := -1; + FConnected := false; + ActReaderState := SCARD_STATE_UNAWARE; + LastReaderState := SCARD_STATE_UNAWARE; + ReaderOpen := false; + ClearReaderAttributes; + ClearCardAttributes; + if not (csDesigning in ComponentState) then NotifyHandle := AllocateHWnd(MessageWndProc); +end; + +destructor TPCSCConnector.Destroy; +begin + CloseAndDisconnect; + SCardReleaseContext(FContext); + FReaderList.Free; + if not (csDesigning in ComponentState) then DeallocateHWnd(NotifyHandle); + inherited Destroy; +end; + +function TPCSCConnector.Init: boolean; +var + RetVar : cardinal; + ReaderList : string; + ReaderListSize : integer; + v : array[0..MAXIMUM_SMARTCARD_READERS] of string; + i : integer; + +begin + Result := false; + FNumReaders := 0; + CloseAndDisconnect; + if SCardIsValidContext(FContext) = SCARD_S_SUCCESS then SCardReleaseContext(FContext); + RetVar := SCardEstablishContext(SCARD_SCOPE_USER, nil, nil, @FContext); + if RetVar = SCARD_S_SUCCESS then + begin + ReaderListSize := 0; + RetVar := SCardListReadersW(FContext, nil, nil, ReaderListSize); + if RetVar = SCARD_S_SUCCESS then + begin + SetLength(ReaderList, ReaderListSize); + SCardListReadersW(FContext, nil, Pointer(ReaderList), ReaderListSize); + FReaderList.Clear; + SortOutSubstrings(ReaderList,v,[#0]); + for i := 0 to MAXIMUM_SMARTCARD_READERS do + if v[i] <> '' then FReaderList.Add(v[i]); + FNumReaders := FReaderList.Count; + if FNumReaders > 0 then + begin + if Assigned(FOnReaderListChange) then FOnReaderListChange(Self); + Result := true; + end; + end else if Assigned(FOnError) then FOnError(Self, esInit, RetVar); + end else if Assigned(FOnError) then FOnError(Self, esInit, RetVar); +end; + +function TPCSCConnector.Open: boolean; +var + ThreadID : LongWord; +begin + CloseAndDisconnect; + if (FUseReaderNum > NOREADERSELECTED) and + (SCardIsValidContext(FContext) = SCARD_S_SUCCESS) then + begin + ReaderOpen := true; + ActReaderState := SCARD_STATE_UNAWARE; + LastReaderState := SCARD_STATE_UNAWARE; + BeginThread(nil, 0, CardWatcherThread, @FContext, 0, ThreadID); + Result := true; + end else Result := false; +end; + +procedure TPCSCConnector.Close; +begin + ReaderOpen := false; + SCardCancel(FContext); + if FConnected then Disconnect; +end; + +function TPCSCConnector.Connect: boolean; +begin + if FConnected then Disconnect; + if FUseReaderNum > NOREADERSELECTED then + if ConnectSelectedReader then FConnected := true + else FConnected := false; + Result := FConnected; +end; + +procedure TPCSCConnector.Disconnect; +begin + if FConnected then + begin + SCardDisconnect(FCardHandle, SCARD_RESET_CARD); + FConnected := false; + FCardHandle := 0; + end; +end; + +procedure TPCSCConnector.CloseAndDisconnect; +begin + if FConnected then Disconnect; + if ReaderOpen then Close; +end; + +function TPCSCConnector.ConnectSelectedReader: boolean; +var + RetVar : cardinal; +begin + RetVar := SCardConnectW(FContext, + PWideChar(SelectedReader), + SCARD_SHARE_EXCLUSIVE, + SCARD_PROTOCOL_Tx, + FCardHandle, + @FAttrProtocol); + case RetVar of + SCARD_S_SUCCESS : begin + CardActiveAction; + Result := true; + end; + SCARD_W_REMOVED_CARD : begin + Result := true; + end; + else begin + Result := false; + if Assigned(FOnError) then FOnError(Self, esConnect, RetVar); + end; + end; +end; + +procedure TPCSCConnector.ProcessReaderState(const OldState,NewState: cardinal); +var + CardInOld, CardInNew : boolean; + ReaderEmOld, ReaderEmNew : boolean; + CardMuteOld, CardMuteNew : boolean; + CardIgnore : boolean; + +begin +CardInOld := (OldState and SCARD_STATE_PRESENT) > 0; +CardInNew := (NewState and SCARD_STATE_PRESENT) > 0; +ReaderEmOld := (OldState and SCARD_STATE_EMPTY) > 0; +ReaderEmNew := (NewState and SCARD_STATE_EMPTY) > 0; +CardMuteOld := (OldState and SCARD_STATE_MUTE) > 0; +CardMuteNew := (NewState and SCARD_STATE_MUTE) > 0; +CardIgnore := (NewState and SCARD_STATE_IGNORE) > 0; + +if CardMuteNew and + not CardMuteold then if Assigned(FOnCardInvalid) then FOnCardInvalid(Self); + +if CardInNew and + not CardInOld and + not CardMuteNew and + not CardIgnore then CardInsertedAction; + +if CardInOld and + not CardInNew then CardRemovedAction; + +if ReaderEmNew and + not ReaderEmOld then begin + if Assigned(FOnReaderWaiting) then FOnReaderWaiting(Self); + end; + +LastReaderState := NewState; +end; + +procedure TPCSCConnector.CardInsertedAction; +begin + if Assigned(FOnCardInserted) then FOnCardInserted(Self); + if FConnected then CardActiveAction; +end; + +procedure TPCSCConnector.CardActiveAction; +begin + GetReaderAttributes; + if FAttrProtocol <> SCARD_PROTOCOL_UNK then + begin + GetCardAttributes; + if Assigned(FOnCardActive) then FOnCardActive(Self); + end; +end; + +procedure TPCSCConnector.CardRemovedAction; +begin + ClearReaderAttributes; + ClearCardAttributes; + if Assigned(FOnCardRemoved) then FOnCardRemoved(Self); + Disconnect; +end; + +procedure TPCSCConnector.SetReaderNum(Value: Integer); +begin + if Value <> FUseReaderNum then + begin + CloseAndDisconnect; + if Value < FReaderList.Count then + begin + SelectedReader := PChar(FReaderList[Value]); + FUseReaderNum := Value; + end else + begin + SelectedReader := ''; + FUseReaderNum := -1; + end; + end; +end; + +function TPCSCConnector.IsReaderOpen: boolean; +begin + Result := ReaderOpen; +end; + +function TPCSCConnector.GetReaderState: cardinal; +begin + Result := ActReaderState; +end; + +procedure TPCSCConnector.GetReaderAttributes; +var + RetVar : cardinal; + ABuf : string; + AIBuf : integer; + ALen : integer; +begin + ABuf := StringOfChar(#0, 127); + ALen := Length(ABuf); + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_ATR_STRING, Pointer(ABuf), @ALen); + if RetVar = SCARD_S_SUCCESS then FAttrCardATR := Copy(ABuf, 1, ALen) + else FAttrCardATR := ''; + + ALen := Length(ABuf); + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_VENDOR_NAME, Pointer(ABuf), @ALen); + if RetVar = SCARD_S_SUCCESS then FAttrVendorName := Copy(ABuf, 1, ALen) + else FAttrVendorName := ''; + + ALen := Length(ABuf); + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_VENDOR_IFD_SERIAL_NO, Pointer(ABuf), @ALen); + if RetVar = SCARD_S_SUCCESS then FAttrVendorSerial := Copy(ABuf, 1, ALen) + else FAttrVendorSerial := ''; + + ALen := SizeOf(AIBuf); + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_CURRENT_PROTOCOL_TYPE, @AIBuf, @ALen); + if RetVar = SCARD_S_SUCCESS then FAttrProtocol := AIBuf + else FAttrProtocol := 0; + + ALen := SizeOf(AIBuf); + AIBuf := 0; + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_ICC_TYPE_PER_ATR, @AIBuf, @ALen); + if RetVar = SCARD_S_SUCCESS then begin + case AIBuf of + 1 : FAttrICCType := 'ISO7816A'; + 2 : FAttrICCType := 'ISO7816S'; + else FAttrICCType := 'UNKNOWN'; + end; + end + else FAttrICCType := ''; +end; + +procedure TPCSCConnector.GetCardAttributes; +begin +if GSMSelect(DFgsm900) = GSMStatusOK then + begin + FGSMVoltage30 := (OrdD(FGSMDirInfo, 14) and $10) > 0; + FGSMVoltage18 := (OrdD(FGSMDirInfo, 14) and $20) > 0; + end; +end; + +procedure TPCSCConnector.ClearReaderAttributes; +begin + FAttrCardATR := ''; + FAttrVendorName := ''; + FAttrVendorSerial := ''; + FAttrProtocol := 0; + FAttrICCType := ''; +end; + +procedure TPCSCConnector.ClearCardAttributes; +begin + FGSMCurrentFile := ''; + FGSMFileInfo := ''; + FGSMDirInfo := ''; + FGSMVoltage30 := false; + FGSMVoltage18 := false; +end; + +function TPCSCConnector.GetResponseFromCard(const APdu: string): string; +var + RetVar : cardinal; + SBuf : string; + SLen : cardinal; + RBuf : string; + RLen : cardinal; + Ppci : Pointer; +begin +SBuf := APdu; +RBuf := StringOfChar(#0,MAXAPDULENGTH); +if Length(SBuf) <= MAXAPDULENGTH then + begin + case FAttrProtocol of + SCARD_PROTOCOL_T0 : Ppci := @SCARD_PCI_T0; + SCARD_PROTOCOL_T1 : Ppci := @SCARD_PCI_T1; + else Ppci := nil; + end; + SLen := Length(APdu); + RLen := Length(RBuf); + RetVar := SCardTransmit(FCardHandle, Ppci, Pointer(SBuf), SLen, nil, Pointer(RBuf), @RLen); + if RetVar = SCARD_S_SUCCESS then + begin + Result := Copy(RBuf,1,RLen); + end else + begin + Result := ''; + if Assigned(FOnError) then FOnError(Self, esTransmit, RetVar); + end; + end; +end; + +function TPCSCConnector.GetResponseFromCard(const Command: string; var Data: string; var sw1, sw2: byte): boolean; +var + Answer : string; + AnswerL : integer; +begin +Answer := GetResponseFromCard(Command + Data); +AnswerL := Length(Answer); +if AnswerL >= 2 then + begin + Data := Copy(Answer, 1, AnswerL - 2); + sw1 := Ord(Answer[AnswerL - 1]); + sw2 := Ord(Answer[AnswerL]); + if sw1 = GSMStatusResponseData then + begin + Data := Chr(sw2); + if not GetResponseFromCard(GCGetResponse, Data, sw1, sw2) then + begin + Data := ''; + sw1 := 0; + sw2 := 0; + Result := false; + end else Result := true; + end else Result := true; + end else + begin + Data := ''; + sw1 := 0; + sw2 := 0; + Result := false; + end; +end; + +function TPCSCConnector.GSMStatus: integer; +var + Answer : string; + sw1, sw2 : byte; +begin + GetResponseFromCard(GCGetStatus, Answer, sw1, sw2); + Result := (sw1 shl 8) + sw2; + if Result = GSMStatusOK then + begin + FGSMDirInfo := Answer; + FGSMCurrentFile := Copy(Answer, 5, 2); + end else + begin + FGSMDirInfo := ''; + end; +end; + +function TPCSCConnector.GSMSelect(const FileID: string): integer; +var + Answer : string; + sw1, sw2 : byte; +begin + Answer := FileID; + GetResponseFromCard(GCSelectFile, Answer, sw1, sw2); + Result := (sw1 shl 8) + sw2; + if Result = GSMStatusOK then + begin + FGSMCurrentFile := Copy(Answer, 5, 2); + if OrdD(Answer, 7) = GSMFileTypeEF then + begin + FGSMFileInfo := Answer; + end else + begin + FGSMDirInfo := Answer; + end; + end; +end; + +function TPCSCConnector.GSMReadBinary(const Offset, Length: integer; var Data: string): integer; +var + Command : string; + sw1, sw2 : byte; +begin + Command := GCReadBinary + Chr(Offset div 256) + Chr(Offset mod 256) + Chr(Length mod 256); + GetResponseFromCard(Command, Data, sw1, sw2); + Result := (sw1 shl 8) + sw2; + if Result = GSMStatusOK then + begin + end; +end; + +end. + diff --git a/__history/PCSCConnector.pas.~118~ b/__history/PCSCConnector.pas.~118~ new file mode 100644 index 0000000..e3dc9f2 --- /dev/null +++ b/__history/PCSCConnector.pas.~118~ @@ -0,0 +1,699 @@ +{******************************************************************} +{ } +{ PC/SC Interface component } +{ Helps you access a cardreader through Microsofts SmartCard API } +{ } +{ The Original Code is PCSCConnector.pas } +{ } +{ The Initial Developer of the Original Code is } +{ Norbert Huettisch (nobbi(at)nobbi.com) } +{ } +{ Any suggestions and improvements to the code are appreciated } +{ } +{ This Code uses a modified SCardErr.pas (included) } +{ This Code uses a modified WinSCard.pas (included) } +{ This code uses the original WinSmCrd.pas (included) } +{ } +{ All originally made by Chris Dickerson (chrisd(at)tsc.com), } +{ available as 'Interface units for the Microsoft Smart Card API' } +{ at the Project JEDI Homepage http://www.delphi-jedi.org } +{ } +{ Version info: } +{ 021230 - initial version } +{ 030101 - routed errors from 'init' to the OnError event } +{ } +{ } +{******************************************************************} +{ } +{ The contents of this file are subject to the } +{ } +{ Mozilla Public License Version 1.1 (the "License") } +{ } +{ You may not use this file except in compliance with the License. } +{ You may obtain a copy of the License at } +{ http://www.mozilla.org/MPL/ } +{ } +{ Software distributed under the License is distributed on an } +{ "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or } +{ implied. See the License for the specific language governing } +{ rights and limitations under the License. } +{ } +{******************************************************************} + +unit PCSCConnector; + +interface + +uses + Windows, Messages, Forms, Classes, SysUtils, + SCardErr, WinSCard, WinSmCrd; + +type + TErrSource = (esInit, esConnect, esGetStatus, esTransmit); + TNeededPIN = (npPIN1, npPIN2, npPUK1, npPUK2); + TDelimiters = set of Char; + + TPCSCErrorEvent = procedure(Sender: TObject; ErrSource: TErrSource; ErrCode: cardinal) of object; + TPCSCPinEvent = procedure(Sender: TObject; NeedPIN: TNeededPIN) of object; + +const + MAXAPDULENGTH = 260; // CLA + INS + P1..3 + 255Bytes + NOREADERSELECTED = -1; + SCARD_PCI_T0 : SCARD_IO_REQUEST = (dwProtocol:1; dbPciLength:8); + SCARD_PCI_T1 : SCARD_IO_REQUEST = (dwProtocol:2; dbPciLength:8); + SCARD_PROTOCOL_T0 = $00000001; + SCARD_PROTOCOL_T1 = $00000002; + SCARD_PROTOCOL_RAW = $00010000; + SCARD_PROTOCOL_UNK = $00000000; + + WM_CARDSTATE = WM_USER + 42; + + GSMStatusOK = $9000; + GSMStatusMemoryError = $9240; + GSMStatusNoEFSelected = $9400; + GSMStatusOutOfRange = $9402; + GSMStatusNotFound = $9404; + GSMStatusFCDoNotMatch = $9408; + GSMStatusCHVNeeded = $9802; + GSMStatusAuthFailed = $9804; + GSMStatusAuthFailedBl = $9840; + GSMStatusTechProblem = $6F00; + GSMStatusResponseData = $9F; + + GSMFileTypeRFU = 0; + GSMFileTypeMF = 1; + GSMFileTypeDF = 2; + GSMFileTypeEF = 4; + + GSMEfTransp = 0; + GSMEfLinFixed = 1; + GSMEfCyclic = 3; + +type + TPCSCConnector = class(TComponent) + + protected + FContext : cardinal; + FCardHandle : integer; + FConnected : boolean; + FNumReaders : integer; + FUseReaderNum : integer; + FReaderList : TStringlist; + FAttrProtocol : integer; + FAttrICCType : string; + FAttrCardATR : string; + FAttrVendorName : string; + FAttrVendorSerial : string; + FGSMCurrentFile : string; + FGSMFileInfo : string; + FGSMDirInfo : string; + FGSMVoltage30 : boolean; + FGSMVoltage18 : boolean; + + FOnReaderWaiting : TNotifyEvent; + FOnReaderListChange : TNotifyEvent; + FOnCardInserted : TNotifyEvent; + FOnCardActive : TNotifyEvent; + FOnCardRemoved : TNotifyEvent; + FOnCardInvalid : TNotifyEvent; + FOnError : TPCSCErrorEvent; + FOnCHVNeeded : TPCSCPinEvent; + + procedure SetReaderNum(Value: integer); + procedure MessageWndProc(var Msg: TMessage); + function ConnectSelectedReader: boolean; + procedure ProcessReaderState(const OldState,NewState: cardinal); + procedure GetReaderAttributes; + procedure GetCardAttributes; + procedure ClearReaderAttributes; + procedure ClearCardAttributes; + function IsReaderOpen: boolean; + function GetReaderState: cardinal; + procedure CloseAndDisconnect; + procedure CardInsertedAction; + procedure CardActiveAction; + procedure CardRemovedAction; + + public + constructor Create(AOwner: TComponent); override; + destructor Destroy; override; + function Init: boolean; + function Open: boolean; + procedure Close; + function Connect: boolean; + procedure Disconnect; + function GetResponseFromCard(const apdu: string): string; overload; + function GetResponseFromCard(const command: string; var data: string; var sw1, sw2: byte): boolean; overload; + + function GSMStatus: integer; + function GSMSelect(const FileID: string): integer; + function GSMReadBinary(const Offset, Length: integer; var Data: string): integer; + + published + property UseReaderNum: integer read FUseReaderNum write SetReaderNum default -1; + + property OnCardInserted: TNotifyEvent read FOnCardInserted write FOnCardInserted; + property OnCardActive: TNotifyEvent read FOnCardActive write FOnCardActive; + property OnCardRemoved: TNotifyEvent read FOnCardRemoved write FOnCardRemoved; + property OnCardInvalid: TNotifyEvent read FOnCardInvalid write FOnCardInvalid; + property OnReaderWaiting: TNotifyEvent read FOnReaderWaiting write FOnReaderWaiting; + property OnReaderListChange: TNotifyEvent read FOnReaderListChange write FOnReaderListChange; + property OnError: TPCSCErrorEvent read FOnError write FOnError; + property OnCHVNeeded: TPCSCPinEvent read FOnCHVNeeded write FOnCHVNeeded; + + property ReaderList: TStringList read FReaderList; + property NumReaders: integer read FNumReaders; + property Connected: boolean read FConnected; + property Opened: boolean read IsReaderOpen; + property ReaderState: cardinal read GetReaderState; + property AttrProtocol: integer read FAttrProtocol; + property AttrICCType: string read FAttrICCType; + property AttrCardATR: string read FAttrCardATR; + property AttrVendorName: string read FAttrVendorName; + property AttrVendorSerial: string read FAttrVendorSerial; + property GSMCurrentFile: string read FGSMCurrentFile; + property GSMFileInfo: string read FGSMFileInfo; + property GSMDirInfo: string read FGSMDirInfo; + property GSMVoltage30: boolean read FGSMVoltage30; + property GSMVoltage18: boolean read FGSMVoltage18; + end; + +procedure Register; + +implementation + +var + ActReaderState : cardinal; + LastReaderState : cardinal; + SelectedReader : String; + ReaderOpen : boolean; + NotifyHandle : HWND; + +const + + // GSM Commands + GCGetStatus = #$A0#$F2#$00#$00#$16; + GCGetResponse = #$A0#$C0#$00#$00; + GCSelectFile = #$A0#$A4#$00#$00#$02; + GCReadBinary = #$A0#$B0; + + GSMMasterFile = #$3f#$00; + DFgsm900 = #$7f#$20; + DFgsm1800 = #$7f#$21; + +procedure Register; +begin + RegisterComponents('More...', [TPCSCConnector]); +end; + +function SortOutSubstrings(const From:string; var t:array of string; const Delim:TDelimiters = [' ',';']; const ConcatDelim:boolean = true):integer; +var a,b,s,i : integer; + sep : boolean; +begin +a := 1; +b := Low(t); +s := 1; +i := 0; +sep := ConcatDelim; +t[b] := ''; + +while a <= Length(From) do + begin + if not (From[a] in Delim) then + begin + Inc(i); + sep := false; + end else + begin + if not sep then + begin + t[b] := Copy(From, s, i); + Inc(b); + if b > High(t) then Break; + t[b] := ''; + end; + if ConcatDelim then sep := true; + s := a + 1; + i := 0; + end; + Inc(a); + end; +if (b <= High(t)) and (i > 0) then + begin + t[b] := Copy(From, s, i); + Inc(b); + end; +for a := b + 1 to High(t) do t[a] := ''; +Result := b; +end; + +function OrdD(const From: string; const Index: integer): integer; +begin +if Index <= Length(From) then Result := Ord(From[Index]) + else Result := 0; +end; + +function CardWatcherThread(PContext: pointer): integer; +var + RetVar : cardinal; + RContext : cardinal; + RStates : array[0..1] of SCARD_READERSTATEA; +begin + try + RContext := cardinal(PContext^); + FillChar(RStates,SizeOf(RStates),#0); + RStates[0].szReader := PAnsichar(^SelectedReader); + RStates[0].pvUserData := nil; + RStates[0].dwEventState := ActReaderState; + while ReaderOpen do + begin + RStates[0].dwCurrentState := RStates[0].dwEventState; + RetVar := SCardGetStatusChangeA(RContext, -1, RStates, 1); + ActReaderState := RStates[0].dwEventState; + PostMessage(NotifyHandle, WM_CARDSTATE, RetVar, 0); + end; + finally + Result := 0; + end; +end; + +procedure TPCSCConnector.MessageWndProc(var Msg: TMessage); +begin + if (Msg.Msg = WM_CARDSTATE) then + begin + if Msg.WParam <> SCARD_S_SUCCESS then + if Assigned(FOnError) then FOnError(Self, esGetStatus, Msg.WParam); + if ActReaderState <> LastReaderState then + begin + ProcessReaderState(LastReaderState, ActReaderState); + end; + end + else Msg.Result := DefWindowProc(NotifyHandle, Msg.Msg, Msg.WParam, Msg.LParam); +end; + +constructor TPCSCConnector.Create(AOwner: TComponent); +begin + inherited Create(AOwner); + FReaderList := TStringlist.Create; + FContext := 0; + FCardHandle := 0; + FNumReaders := 0; + FUseReaderNum := -1; + FConnected := false; + ActReaderState := SCARD_STATE_UNAWARE; + LastReaderState := SCARD_STATE_UNAWARE; + ReaderOpen := false; + ClearReaderAttributes; + ClearCardAttributes; + if not (csDesigning in ComponentState) then NotifyHandle := AllocateHWnd(MessageWndProc); +end; + +destructor TPCSCConnector.Destroy; +begin + CloseAndDisconnect; + SCardReleaseContext(FContext); + FReaderList.Free; + if not (csDesigning in ComponentState) then DeallocateHWnd(NotifyHandle); + inherited Destroy; +end; + +function TPCSCConnector.Init: boolean; +var + RetVar : cardinal; + ReaderList : string; + ReaderListSize : integer; + v : array[0..MAXIMUM_SMARTCARD_READERS] of string; + i : integer; + +begin + Result := false; + FNumReaders := 0; + CloseAndDisconnect; + if SCardIsValidContext(FContext) = SCARD_S_SUCCESS then SCardReleaseContext(FContext); + RetVar := SCardEstablishContext(SCARD_SCOPE_USER, nil, nil, @FContext); + if RetVar = SCARD_S_SUCCESS then + begin + ReaderListSize := 0; + RetVar := SCardListReadersW(FContext, nil, nil, ReaderListSize); + if RetVar = SCARD_S_SUCCESS then + begin + SetLength(ReaderList, ReaderListSize); + SCardListReadersW(FContext, nil, Pointer(ReaderList), ReaderListSize); + FReaderList.Clear; + SortOutSubstrings(ReaderList,v,[#0]); + for i := 0 to MAXIMUM_SMARTCARD_READERS do + if v[i] <> '' then FReaderList.Add(v[i]); + FNumReaders := FReaderList.Count; + if FNumReaders > 0 then + begin + if Assigned(FOnReaderListChange) then FOnReaderListChange(Self); + Result := true; + end; + end else if Assigned(FOnError) then FOnError(Self, esInit, RetVar); + end else if Assigned(FOnError) then FOnError(Self, esInit, RetVar); +end; + +function TPCSCConnector.Open: boolean; +var + ThreadID : LongWord; +begin + CloseAndDisconnect; + if (FUseReaderNum > NOREADERSELECTED) and + (SCardIsValidContext(FContext) = SCARD_S_SUCCESS) then + begin + ReaderOpen := true; + ActReaderState := SCARD_STATE_UNAWARE; + LastReaderState := SCARD_STATE_UNAWARE; + BeginThread(nil, 0, CardWatcherThread, @FContext, 0, ThreadID); + Result := true; + end else Result := false; +end; + +procedure TPCSCConnector.Close; +begin + ReaderOpen := false; + SCardCancel(FContext); + if FConnected then Disconnect; +end; + +function TPCSCConnector.Connect: boolean; +begin + if FConnected then Disconnect; + if FUseReaderNum > NOREADERSELECTED then + if ConnectSelectedReader then FConnected := true + else FConnected := false; + Result := FConnected; +end; + +procedure TPCSCConnector.Disconnect; +begin + if FConnected then + begin + SCardDisconnect(FCardHandle, SCARD_RESET_CARD); + FConnected := false; + FCardHandle := 0; + end; +end; + +procedure TPCSCConnector.CloseAndDisconnect; +begin + if FConnected then Disconnect; + if ReaderOpen then Close; +end; + +function TPCSCConnector.ConnectSelectedReader: boolean; +var + RetVar : cardinal; +begin + RetVar := SCardConnectW(FContext, + PWideChar(SelectedReader), + SCARD_SHARE_EXCLUSIVE, + SCARD_PROTOCOL_Tx, + FCardHandle, + @FAttrProtocol); + case RetVar of + SCARD_S_SUCCESS : begin + CardActiveAction; + Result := true; + end; + SCARD_W_REMOVED_CARD : begin + Result := true; + end; + else begin + Result := false; + if Assigned(FOnError) then FOnError(Self, esConnect, RetVar); + end; + end; +end; + +procedure TPCSCConnector.ProcessReaderState(const OldState,NewState: cardinal); +var + CardInOld, CardInNew : boolean; + ReaderEmOld, ReaderEmNew : boolean; + CardMuteOld, CardMuteNew : boolean; + CardIgnore : boolean; + +begin +CardInOld := (OldState and SCARD_STATE_PRESENT) > 0; +CardInNew := (NewState and SCARD_STATE_PRESENT) > 0; +ReaderEmOld := (OldState and SCARD_STATE_EMPTY) > 0; +ReaderEmNew := (NewState and SCARD_STATE_EMPTY) > 0; +CardMuteOld := (OldState and SCARD_STATE_MUTE) > 0; +CardMuteNew := (NewState and SCARD_STATE_MUTE) > 0; +CardIgnore := (NewState and SCARD_STATE_IGNORE) > 0; + +if CardMuteNew and + not CardMuteold then if Assigned(FOnCardInvalid) then FOnCardInvalid(Self); + +if CardInNew and + not CardInOld and + not CardMuteNew and + not CardIgnore then CardInsertedAction; + +if CardInOld and + not CardInNew then CardRemovedAction; + +if ReaderEmNew and + not ReaderEmOld then begin + if Assigned(FOnReaderWaiting) then FOnReaderWaiting(Self); + end; + +LastReaderState := NewState; +end; + +procedure TPCSCConnector.CardInsertedAction; +begin + if Assigned(FOnCardInserted) then FOnCardInserted(Self); + if FConnected then CardActiveAction; +end; + +procedure TPCSCConnector.CardActiveAction; +begin + GetReaderAttributes; + if FAttrProtocol <> SCARD_PROTOCOL_UNK then + begin + GetCardAttributes; + if Assigned(FOnCardActive) then FOnCardActive(Self); + end; +end; + +procedure TPCSCConnector.CardRemovedAction; +begin + ClearReaderAttributes; + ClearCardAttributes; + if Assigned(FOnCardRemoved) then FOnCardRemoved(Self); + Disconnect; +end; + +procedure TPCSCConnector.SetReaderNum(Value: Integer); +begin + if Value <> FUseReaderNum then + begin + CloseAndDisconnect; + if Value < FReaderList.Count then + begin + SelectedReader := PChar(FReaderList[Value]); + FUseReaderNum := Value; + end else + begin + SelectedReader := ''; + FUseReaderNum := -1; + end; + end; +end; + +function TPCSCConnector.IsReaderOpen: boolean; +begin + Result := ReaderOpen; +end; + +function TPCSCConnector.GetReaderState: cardinal; +begin + Result := ActReaderState; +end; + +procedure TPCSCConnector.GetReaderAttributes; +var + RetVar : cardinal; + ABuf : string; + AIBuf : integer; + ALen : integer; +begin + ABuf := StringOfChar(#0, 127); + ALen := Length(ABuf); + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_ATR_STRING, Pointer(ABuf), @ALen); + if RetVar = SCARD_S_SUCCESS then FAttrCardATR := Copy(ABuf, 1, ALen) + else FAttrCardATR := ''; + + ALen := Length(ABuf); + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_VENDOR_NAME, Pointer(ABuf), @ALen); + if RetVar = SCARD_S_SUCCESS then FAttrVendorName := Copy(ABuf, 1, ALen) + else FAttrVendorName := ''; + + ALen := Length(ABuf); + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_VENDOR_IFD_SERIAL_NO, Pointer(ABuf), @ALen); + if RetVar = SCARD_S_SUCCESS then FAttrVendorSerial := Copy(ABuf, 1, ALen) + else FAttrVendorSerial := ''; + + ALen := SizeOf(AIBuf); + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_CURRENT_PROTOCOL_TYPE, @AIBuf, @ALen); + if RetVar = SCARD_S_SUCCESS then FAttrProtocol := AIBuf + else FAttrProtocol := 0; + + ALen := SizeOf(AIBuf); + AIBuf := 0; + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_ICC_TYPE_PER_ATR, @AIBuf, @ALen); + if RetVar = SCARD_S_SUCCESS then begin + case AIBuf of + 1 : FAttrICCType := 'ISO7816A'; + 2 : FAttrICCType := 'ISO7816S'; + else FAttrICCType := 'UNKNOWN'; + end; + end + else FAttrICCType := ''; +end; + +procedure TPCSCConnector.GetCardAttributes; +begin +if GSMSelect(DFgsm900) = GSMStatusOK then + begin + FGSMVoltage30 := (OrdD(FGSMDirInfo, 14) and $10) > 0; + FGSMVoltage18 := (OrdD(FGSMDirInfo, 14) and $20) > 0; + end; +end; + +procedure TPCSCConnector.ClearReaderAttributes; +begin + FAttrCardATR := ''; + FAttrVendorName := ''; + FAttrVendorSerial := ''; + FAttrProtocol := 0; + FAttrICCType := ''; +end; + +procedure TPCSCConnector.ClearCardAttributes; +begin + FGSMCurrentFile := ''; + FGSMFileInfo := ''; + FGSMDirInfo := ''; + FGSMVoltage30 := false; + FGSMVoltage18 := false; +end; + +function TPCSCConnector.GetResponseFromCard(const APdu: string): string; +var + RetVar : cardinal; + SBuf : string; + SLen : cardinal; + RBuf : string; + RLen : cardinal; + Ppci : Pointer; +begin +SBuf := APdu; +RBuf := StringOfChar(#0,MAXAPDULENGTH); +if Length(SBuf) <= MAXAPDULENGTH then + begin + case FAttrProtocol of + SCARD_PROTOCOL_T0 : Ppci := @SCARD_PCI_T0; + SCARD_PROTOCOL_T1 : Ppci := @SCARD_PCI_T1; + else Ppci := nil; + end; + SLen := Length(APdu); + RLen := Length(RBuf); + RetVar := SCardTransmit(FCardHandle, Ppci, Pointer(SBuf), SLen, nil, Pointer(RBuf), @RLen); + if RetVar = SCARD_S_SUCCESS then + begin + Result := Copy(RBuf,1,RLen); + end else + begin + Result := ''; + if Assigned(FOnError) then FOnError(Self, esTransmit, RetVar); + end; + end; +end; + +function TPCSCConnector.GetResponseFromCard(const Command: string; var Data: string; var sw1, sw2: byte): boolean; +var + Answer : string; + AnswerL : integer; +begin +Answer := GetResponseFromCard(Command + Data); +AnswerL := Length(Answer); +if AnswerL >= 2 then + begin + Data := Copy(Answer, 1, AnswerL - 2); + sw1 := Ord(Answer[AnswerL - 1]); + sw2 := Ord(Answer[AnswerL]); + if sw1 = GSMStatusResponseData then + begin + Data := Chr(sw2); + if not GetResponseFromCard(GCGetResponse, Data, sw1, sw2) then + begin + Data := ''; + sw1 := 0; + sw2 := 0; + Result := false; + end else Result := true; + end else Result := true; + end else + begin + Data := ''; + sw1 := 0; + sw2 := 0; + Result := false; + end; +end; + +function TPCSCConnector.GSMStatus: integer; +var + Answer : string; + sw1, sw2 : byte; +begin + GetResponseFromCard(GCGetStatus, Answer, sw1, sw2); + Result := (sw1 shl 8) + sw2; + if Result = GSMStatusOK then + begin + FGSMDirInfo := Answer; + FGSMCurrentFile := Copy(Answer, 5, 2); + end else + begin + FGSMDirInfo := ''; + end; +end; + +function TPCSCConnector.GSMSelect(const FileID: string): integer; +var + Answer : string; + sw1, sw2 : byte; +begin + Answer := FileID; + GetResponseFromCard(GCSelectFile, Answer, sw1, sw2); + Result := (sw1 shl 8) + sw2; + if Result = GSMStatusOK then + begin + FGSMCurrentFile := Copy(Answer, 5, 2); + if OrdD(Answer, 7) = GSMFileTypeEF then + begin + FGSMFileInfo := Answer; + end else + begin + FGSMDirInfo := Answer; + end; + end; +end; + +function TPCSCConnector.GSMReadBinary(const Offset, Length: integer; var Data: string): integer; +var + Command : string; + sw1, sw2 : byte; +begin + Command := GCReadBinary + Chr(Offset div 256) + Chr(Offset mod 256) + Chr(Length mod 256); + GetResponseFromCard(Command, Data, sw1, sw2); + Result := (sw1 shl 8) + sw2; + if Result = GSMStatusOK then + begin + end; +end; + +end. + diff --git a/__history/PCSCConnector.pas.~119~ b/__history/PCSCConnector.pas.~119~ new file mode 100644 index 0000000..230d8da --- /dev/null +++ b/__history/PCSCConnector.pas.~119~ @@ -0,0 +1,699 @@ +{******************************************************************} +{ } +{ PC/SC Interface component } +{ Helps you access a cardreader through Microsofts SmartCard API } +{ } +{ The Original Code is PCSCConnector.pas } +{ } +{ The Initial Developer of the Original Code is } +{ Norbert Huettisch (nobbi(at)nobbi.com) } +{ } +{ Any suggestions and improvements to the code are appreciated } +{ } +{ This Code uses a modified SCardErr.pas (included) } +{ This Code uses a modified WinSCard.pas (included) } +{ This code uses the original WinSmCrd.pas (included) } +{ } +{ All originally made by Chris Dickerson (chrisd(at)tsc.com), } +{ available as 'Interface units for the Microsoft Smart Card API' } +{ at the Project JEDI Homepage http://www.delphi-jedi.org } +{ } +{ Version info: } +{ 021230 - initial version } +{ 030101 - routed errors from 'init' to the OnError event } +{ } +{ } +{******************************************************************} +{ } +{ The contents of this file are subject to the } +{ } +{ Mozilla Public License Version 1.1 (the "License") } +{ } +{ You may not use this file except in compliance with the License. } +{ You may obtain a copy of the License at } +{ http://www.mozilla.org/MPL/ } +{ } +{ Software distributed under the License is distributed on an } +{ "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or } +{ implied. See the License for the specific language governing } +{ rights and limitations under the License. } +{ } +{******************************************************************} + +unit PCSCConnector; + +interface + +uses + Windows, Messages, Forms, Classes, SysUtils, + SCardErr, WinSCard, WinSmCrd; + +type + TErrSource = (esInit, esConnect, esGetStatus, esTransmit); + TNeededPIN = (npPIN1, npPIN2, npPUK1, npPUK2); + TDelimiters = set of Char; + + TPCSCErrorEvent = procedure(Sender: TObject; ErrSource: TErrSource; ErrCode: cardinal) of object; + TPCSCPinEvent = procedure(Sender: TObject; NeedPIN: TNeededPIN) of object; + +const + MAXAPDULENGTH = 260; // CLA + INS + P1..3 + 255Bytes + NOREADERSELECTED = -1; + SCARD_PCI_T0 : SCARD_IO_REQUEST = (dwProtocol:1; dbPciLength:8); + SCARD_PCI_T1 : SCARD_IO_REQUEST = (dwProtocol:2; dbPciLength:8); + SCARD_PROTOCOL_T0 = $00000001; + SCARD_PROTOCOL_T1 = $00000002; + SCARD_PROTOCOL_RAW = $00010000; + SCARD_PROTOCOL_UNK = $00000000; + + WM_CARDSTATE = WM_USER + 42; + + GSMStatusOK = $9000; + GSMStatusMemoryError = $9240; + GSMStatusNoEFSelected = $9400; + GSMStatusOutOfRange = $9402; + GSMStatusNotFound = $9404; + GSMStatusFCDoNotMatch = $9408; + GSMStatusCHVNeeded = $9802; + GSMStatusAuthFailed = $9804; + GSMStatusAuthFailedBl = $9840; + GSMStatusTechProblem = $6F00; + GSMStatusResponseData = $9F; + + GSMFileTypeRFU = 0; + GSMFileTypeMF = 1; + GSMFileTypeDF = 2; + GSMFileTypeEF = 4; + + GSMEfTransp = 0; + GSMEfLinFixed = 1; + GSMEfCyclic = 3; + +type + TPCSCConnector = class(TComponent) + + protected + FContext : cardinal; + FCardHandle : integer; + FConnected : boolean; + FNumReaders : integer; + FUseReaderNum : integer; + FReaderList : TStringlist; + FAttrProtocol : integer; + FAttrICCType : string; + FAttrCardATR : string; + FAttrVendorName : string; + FAttrVendorSerial : string; + FGSMCurrentFile : string; + FGSMFileInfo : string; + FGSMDirInfo : string; + FGSMVoltage30 : boolean; + FGSMVoltage18 : boolean; + + FOnReaderWaiting : TNotifyEvent; + FOnReaderListChange : TNotifyEvent; + FOnCardInserted : TNotifyEvent; + FOnCardActive : TNotifyEvent; + FOnCardRemoved : TNotifyEvent; + FOnCardInvalid : TNotifyEvent; + FOnError : TPCSCErrorEvent; + FOnCHVNeeded : TPCSCPinEvent; + + procedure SetReaderNum(Value: integer); + procedure MessageWndProc(var Msg: TMessage); + function ConnectSelectedReader: boolean; + procedure ProcessReaderState(const OldState,NewState: cardinal); + procedure GetReaderAttributes; + procedure GetCardAttributes; + procedure ClearReaderAttributes; + procedure ClearCardAttributes; + function IsReaderOpen: boolean; + function GetReaderState: cardinal; + procedure CloseAndDisconnect; + procedure CardInsertedAction; + procedure CardActiveAction; + procedure CardRemovedAction; + + public + constructor Create(AOwner: TComponent); override; + destructor Destroy; override; + function Init: boolean; + function Open: boolean; + procedure Close; + function Connect: boolean; + procedure Disconnect; + function GetResponseFromCard(const apdu: string): string; overload; + function GetResponseFromCard(const command: string; var data: string; var sw1, sw2: byte): boolean; overload; + + function GSMStatus: integer; + function GSMSelect(const FileID: string): integer; + function GSMReadBinary(const Offset, Length: integer; var Data: string): integer; + + published + property UseReaderNum: integer read FUseReaderNum write SetReaderNum default -1; + + property OnCardInserted: TNotifyEvent read FOnCardInserted write FOnCardInserted; + property OnCardActive: TNotifyEvent read FOnCardActive write FOnCardActive; + property OnCardRemoved: TNotifyEvent read FOnCardRemoved write FOnCardRemoved; + property OnCardInvalid: TNotifyEvent read FOnCardInvalid write FOnCardInvalid; + property OnReaderWaiting: TNotifyEvent read FOnReaderWaiting write FOnReaderWaiting; + property OnReaderListChange: TNotifyEvent read FOnReaderListChange write FOnReaderListChange; + property OnError: TPCSCErrorEvent read FOnError write FOnError; + property OnCHVNeeded: TPCSCPinEvent read FOnCHVNeeded write FOnCHVNeeded; + + property ReaderList: TStringList read FReaderList; + property NumReaders: integer read FNumReaders; + property Connected: boolean read FConnected; + property Opened: boolean read IsReaderOpen; + property ReaderState: cardinal read GetReaderState; + property AttrProtocol: integer read FAttrProtocol; + property AttrICCType: string read FAttrICCType; + property AttrCardATR: string read FAttrCardATR; + property AttrVendorName: string read FAttrVendorName; + property AttrVendorSerial: string read FAttrVendorSerial; + property GSMCurrentFile: string read FGSMCurrentFile; + property GSMFileInfo: string read FGSMFileInfo; + property GSMDirInfo: string read FGSMDirInfo; + property GSMVoltage30: boolean read FGSMVoltage30; + property GSMVoltage18: boolean read FGSMVoltage18; + end; + +procedure Register; + +implementation + +var + ActReaderState : cardinal; + LastReaderState : cardinal; + SelectedReader : String; + ReaderOpen : boolean; + NotifyHandle : HWND; + +const + + // GSM Commands + GCGetStatus = #$A0#$F2#$00#$00#$16; + GCGetResponse = #$A0#$C0#$00#$00; + GCSelectFile = #$A0#$A4#$00#$00#$02; + GCReadBinary = #$A0#$B0; + + GSMMasterFile = #$3f#$00; + DFgsm900 = #$7f#$20; + DFgsm1800 = #$7f#$21; + +procedure Register; +begin + RegisterComponents('More...', [TPCSCConnector]); +end; + +function SortOutSubstrings(const From:string; var t:array of string; const Delim:TDelimiters = [' ',';']; const ConcatDelim:boolean = true):integer; +var a,b,s,i : integer; + sep : boolean; +begin +a := 1; +b := Low(t); +s := 1; +i := 0; +sep := ConcatDelim; +t[b] := ''; + +while a <= Length(From) do + begin + if not (From[a] in Delim) then + begin + Inc(i); + sep := false; + end else + begin + if not sep then + begin + t[b] := Copy(From, s, i); + Inc(b); + if b > High(t) then Break; + t[b] := ''; + end; + if ConcatDelim then sep := true; + s := a + 1; + i := 0; + end; + Inc(a); + end; +if (b <= High(t)) and (i > 0) then + begin + t[b] := Copy(From, s, i); + Inc(b); + end; +for a := b + 1 to High(t) do t[a] := ''; +Result := b; +end; + +function OrdD(const From: string; const Index: integer): integer; +begin +if Index <= Length(From) then Result := Ord(From[Index]) + else Result := 0; +end; + +function CardWatcherThread(PContext: pointer): integer; +var + RetVar : cardinal; + RContext : cardinal; + RStates : array[0..1] of SCARD_READERSTATEA; +begin + try + RContext := cardinal(PContext^); + FillChar(RStates,SizeOf(RStates),#0); + RStates[0].szReader := PAnsichar(@SelectedReader); + RStates[0].pvUserData := nil; + RStates[0].dwEventState := ActReaderState; + while ReaderOpen do + begin + RStates[0].dwCurrentState := RStates[0].dwEventState; + RetVar := SCardGetStatusChangeA(RContext, -1, RStates, 1); + ActReaderState := RStates[0].dwEventState; + PostMessage(NotifyHandle, WM_CARDSTATE, RetVar, 0); + end; + finally + Result := 0; + end; +end; + +procedure TPCSCConnector.MessageWndProc(var Msg: TMessage); +begin + if (Msg.Msg = WM_CARDSTATE) then + begin + if Msg.WParam <> SCARD_S_SUCCESS then + if Assigned(FOnError) then FOnError(Self, esGetStatus, Msg.WParam); + if ActReaderState <> LastReaderState then + begin + ProcessReaderState(LastReaderState, ActReaderState); + end; + end + else Msg.Result := DefWindowProc(NotifyHandle, Msg.Msg, Msg.WParam, Msg.LParam); +end; + +constructor TPCSCConnector.Create(AOwner: TComponent); +begin + inherited Create(AOwner); + FReaderList := TStringlist.Create; + FContext := 0; + FCardHandle := 0; + FNumReaders := 0; + FUseReaderNum := -1; + FConnected := false; + ActReaderState := SCARD_STATE_UNAWARE; + LastReaderState := SCARD_STATE_UNAWARE; + ReaderOpen := false; + ClearReaderAttributes; + ClearCardAttributes; + if not (csDesigning in ComponentState) then NotifyHandle := AllocateHWnd(MessageWndProc); +end; + +destructor TPCSCConnector.Destroy; +begin + CloseAndDisconnect; + SCardReleaseContext(FContext); + FReaderList.Free; + if not (csDesigning in ComponentState) then DeallocateHWnd(NotifyHandle); + inherited Destroy; +end; + +function TPCSCConnector.Init: boolean; +var + RetVar : cardinal; + ReaderList : string; + ReaderListSize : integer; + v : array[0..MAXIMUM_SMARTCARD_READERS] of string; + i : integer; + +begin + Result := false; + FNumReaders := 0; + CloseAndDisconnect; + if SCardIsValidContext(FContext) = SCARD_S_SUCCESS then SCardReleaseContext(FContext); + RetVar := SCardEstablishContext(SCARD_SCOPE_USER, nil, nil, @FContext); + if RetVar = SCARD_S_SUCCESS then + begin + ReaderListSize := 0; + RetVar := SCardListReadersW(FContext, nil, nil, ReaderListSize); + if RetVar = SCARD_S_SUCCESS then + begin + SetLength(ReaderList, ReaderListSize); + SCardListReadersW(FContext, nil, Pointer(ReaderList), ReaderListSize); + FReaderList.Clear; + SortOutSubstrings(ReaderList,v,[#0]); + for i := 0 to MAXIMUM_SMARTCARD_READERS do + if v[i] <> '' then FReaderList.Add(v[i]); + FNumReaders := FReaderList.Count; + if FNumReaders > 0 then + begin + if Assigned(FOnReaderListChange) then FOnReaderListChange(Self); + Result := true; + end; + end else if Assigned(FOnError) then FOnError(Self, esInit, RetVar); + end else if Assigned(FOnError) then FOnError(Self, esInit, RetVar); +end; + +function TPCSCConnector.Open: boolean; +var + ThreadID : LongWord; +begin + CloseAndDisconnect; + if (FUseReaderNum > NOREADERSELECTED) and + (SCardIsValidContext(FContext) = SCARD_S_SUCCESS) then + begin + ReaderOpen := true; + ActReaderState := SCARD_STATE_UNAWARE; + LastReaderState := SCARD_STATE_UNAWARE; + BeginThread(nil, 0, CardWatcherThread, @FContext, 0, ThreadID); + Result := true; + end else Result := false; +end; + +procedure TPCSCConnector.Close; +begin + ReaderOpen := false; + SCardCancel(FContext); + if FConnected then Disconnect; +end; + +function TPCSCConnector.Connect: boolean; +begin + if FConnected then Disconnect; + if FUseReaderNum > NOREADERSELECTED then + if ConnectSelectedReader then FConnected := true + else FConnected := false; + Result := FConnected; +end; + +procedure TPCSCConnector.Disconnect; +begin + if FConnected then + begin + SCardDisconnect(FCardHandle, SCARD_RESET_CARD); + FConnected := false; + FCardHandle := 0; + end; +end; + +procedure TPCSCConnector.CloseAndDisconnect; +begin + if FConnected then Disconnect; + if ReaderOpen then Close; +end; + +function TPCSCConnector.ConnectSelectedReader: boolean; +var + RetVar : cardinal; +begin + RetVar := SCardConnectW(FContext, + PWideChar(SelectedReader), + SCARD_SHARE_EXCLUSIVE, + SCARD_PROTOCOL_Tx, + FCardHandle, + @FAttrProtocol); + case RetVar of + SCARD_S_SUCCESS : begin + CardActiveAction; + Result := true; + end; + SCARD_W_REMOVED_CARD : begin + Result := true; + end; + else begin + Result := false; + if Assigned(FOnError) then FOnError(Self, esConnect, RetVar); + end; + end; +end; + +procedure TPCSCConnector.ProcessReaderState(const OldState,NewState: cardinal); +var + CardInOld, CardInNew : boolean; + ReaderEmOld, ReaderEmNew : boolean; + CardMuteOld, CardMuteNew : boolean; + CardIgnore : boolean; + +begin +CardInOld := (OldState and SCARD_STATE_PRESENT) > 0; +CardInNew := (NewState and SCARD_STATE_PRESENT) > 0; +ReaderEmOld := (OldState and SCARD_STATE_EMPTY) > 0; +ReaderEmNew := (NewState and SCARD_STATE_EMPTY) > 0; +CardMuteOld := (OldState and SCARD_STATE_MUTE) > 0; +CardMuteNew := (NewState and SCARD_STATE_MUTE) > 0; +CardIgnore := (NewState and SCARD_STATE_IGNORE) > 0; + +if CardMuteNew and + not CardMuteold then if Assigned(FOnCardInvalid) then FOnCardInvalid(Self); + +if CardInNew and + not CardInOld and + not CardMuteNew and + not CardIgnore then CardInsertedAction; + +if CardInOld and + not CardInNew then CardRemovedAction; + +if ReaderEmNew and + not ReaderEmOld then begin + if Assigned(FOnReaderWaiting) then FOnReaderWaiting(Self); + end; + +LastReaderState := NewState; +end; + +procedure TPCSCConnector.CardInsertedAction; +begin + if Assigned(FOnCardInserted) then FOnCardInserted(Self); + if FConnected then CardActiveAction; +end; + +procedure TPCSCConnector.CardActiveAction; +begin + GetReaderAttributes; + if FAttrProtocol <> SCARD_PROTOCOL_UNK then + begin + GetCardAttributes; + if Assigned(FOnCardActive) then FOnCardActive(Self); + end; +end; + +procedure TPCSCConnector.CardRemovedAction; +begin + ClearReaderAttributes; + ClearCardAttributes; + if Assigned(FOnCardRemoved) then FOnCardRemoved(Self); + Disconnect; +end; + +procedure TPCSCConnector.SetReaderNum(Value: Integer); +begin + if Value <> FUseReaderNum then + begin + CloseAndDisconnect; + if Value < FReaderList.Count then + begin + SelectedReader := PChar(FReaderList[Value]); + FUseReaderNum := Value; + end else + begin + SelectedReader := ''; + FUseReaderNum := -1; + end; + end; +end; + +function TPCSCConnector.IsReaderOpen: boolean; +begin + Result := ReaderOpen; +end; + +function TPCSCConnector.GetReaderState: cardinal; +begin + Result := ActReaderState; +end; + +procedure TPCSCConnector.GetReaderAttributes; +var + RetVar : cardinal; + ABuf : string; + AIBuf : integer; + ALen : integer; +begin + ABuf := StringOfChar(#0, 127); + ALen := Length(ABuf); + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_ATR_STRING, Pointer(ABuf), @ALen); + if RetVar = SCARD_S_SUCCESS then FAttrCardATR := Copy(ABuf, 1, ALen) + else FAttrCardATR := ''; + + ALen := Length(ABuf); + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_VENDOR_NAME, Pointer(ABuf), @ALen); + if RetVar = SCARD_S_SUCCESS then FAttrVendorName := Copy(ABuf, 1, ALen) + else FAttrVendorName := ''; + + ALen := Length(ABuf); + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_VENDOR_IFD_SERIAL_NO, Pointer(ABuf), @ALen); + if RetVar = SCARD_S_SUCCESS then FAttrVendorSerial := Copy(ABuf, 1, ALen) + else FAttrVendorSerial := ''; + + ALen := SizeOf(AIBuf); + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_CURRENT_PROTOCOL_TYPE, @AIBuf, @ALen); + if RetVar = SCARD_S_SUCCESS then FAttrProtocol := AIBuf + else FAttrProtocol := 0; + + ALen := SizeOf(AIBuf); + AIBuf := 0; + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_ICC_TYPE_PER_ATR, @AIBuf, @ALen); + if RetVar = SCARD_S_SUCCESS then begin + case AIBuf of + 1 : FAttrICCType := 'ISO7816A'; + 2 : FAttrICCType := 'ISO7816S'; + else FAttrICCType := 'UNKNOWN'; + end; + end + else FAttrICCType := ''; +end; + +procedure TPCSCConnector.GetCardAttributes; +begin +if GSMSelect(DFgsm900) = GSMStatusOK then + begin + FGSMVoltage30 := (OrdD(FGSMDirInfo, 14) and $10) > 0; + FGSMVoltage18 := (OrdD(FGSMDirInfo, 14) and $20) > 0; + end; +end; + +procedure TPCSCConnector.ClearReaderAttributes; +begin + FAttrCardATR := ''; + FAttrVendorName := ''; + FAttrVendorSerial := ''; + FAttrProtocol := 0; + FAttrICCType := ''; +end; + +procedure TPCSCConnector.ClearCardAttributes; +begin + FGSMCurrentFile := ''; + FGSMFileInfo := ''; + FGSMDirInfo := ''; + FGSMVoltage30 := false; + FGSMVoltage18 := false; +end; + +function TPCSCConnector.GetResponseFromCard(const APdu: string): string; +var + RetVar : cardinal; + SBuf : string; + SLen : cardinal; + RBuf : string; + RLen : cardinal; + Ppci : Pointer; +begin +SBuf := APdu; +RBuf := StringOfChar(#0,MAXAPDULENGTH); +if Length(SBuf) <= MAXAPDULENGTH then + begin + case FAttrProtocol of + SCARD_PROTOCOL_T0 : Ppci := @SCARD_PCI_T0; + SCARD_PROTOCOL_T1 : Ppci := @SCARD_PCI_T1; + else Ppci := nil; + end; + SLen := Length(APdu); + RLen := Length(RBuf); + RetVar := SCardTransmit(FCardHandle, Ppci, Pointer(SBuf), SLen, nil, Pointer(RBuf), @RLen); + if RetVar = SCARD_S_SUCCESS then + begin + Result := Copy(RBuf,1,RLen); + end else + begin + Result := ''; + if Assigned(FOnError) then FOnError(Self, esTransmit, RetVar); + end; + end; +end; + +function TPCSCConnector.GetResponseFromCard(const Command: string; var Data: string; var sw1, sw2: byte): boolean; +var + Answer : string; + AnswerL : integer; +begin +Answer := GetResponseFromCard(Command + Data); +AnswerL := Length(Answer); +if AnswerL >= 2 then + begin + Data := Copy(Answer, 1, AnswerL - 2); + sw1 := Ord(Answer[AnswerL - 1]); + sw2 := Ord(Answer[AnswerL]); + if sw1 = GSMStatusResponseData then + begin + Data := Chr(sw2); + if not GetResponseFromCard(GCGetResponse, Data, sw1, sw2) then + begin + Data := ''; + sw1 := 0; + sw2 := 0; + Result := false; + end else Result := true; + end else Result := true; + end else + begin + Data := ''; + sw1 := 0; + sw2 := 0; + Result := false; + end; +end; + +function TPCSCConnector.GSMStatus: integer; +var + Answer : string; + sw1, sw2 : byte; +begin + GetResponseFromCard(GCGetStatus, Answer, sw1, sw2); + Result := (sw1 shl 8) + sw2; + if Result = GSMStatusOK then + begin + FGSMDirInfo := Answer; + FGSMCurrentFile := Copy(Answer, 5, 2); + end else + begin + FGSMDirInfo := ''; + end; +end; + +function TPCSCConnector.GSMSelect(const FileID: string): integer; +var + Answer : string; + sw1, sw2 : byte; +begin + Answer := FileID; + GetResponseFromCard(GCSelectFile, Answer, sw1, sw2); + Result := (sw1 shl 8) + sw2; + if Result = GSMStatusOK then + begin + FGSMCurrentFile := Copy(Answer, 5, 2); + if OrdD(Answer, 7) = GSMFileTypeEF then + begin + FGSMFileInfo := Answer; + end else + begin + FGSMDirInfo := Answer; + end; + end; +end; + +function TPCSCConnector.GSMReadBinary(const Offset, Length: integer; var Data: string): integer; +var + Command : string; + sw1, sw2 : byte; +begin + Command := GCReadBinary + Chr(Offset div 256) + Chr(Offset mod 256) + Chr(Length mod 256); + GetResponseFromCard(Command, Data, sw1, sw2); + Result := (sw1 shl 8) + sw2; + if Result = GSMStatusOK then + begin + end; +end; + +end. + diff --git a/__history/PCSCConnector.pas.~120~ b/__history/PCSCConnector.pas.~120~ new file mode 100644 index 0000000..7beaaa7 --- /dev/null +++ b/__history/PCSCConnector.pas.~120~ @@ -0,0 +1,699 @@ +{******************************************************************} +{ } +{ PC/SC Interface component } +{ Helps you access a cardreader through Microsofts SmartCard API } +{ } +{ The Original Code is PCSCConnector.pas } +{ } +{ The Initial Developer of the Original Code is } +{ Norbert Huettisch (nobbi(at)nobbi.com) } +{ } +{ Any suggestions and improvements to the code are appreciated } +{ } +{ This Code uses a modified SCardErr.pas (included) } +{ This Code uses a modified WinSCard.pas (included) } +{ This code uses the original WinSmCrd.pas (included) } +{ } +{ All originally made by Chris Dickerson (chrisd(at)tsc.com), } +{ available as 'Interface units for the Microsoft Smart Card API' } +{ at the Project JEDI Homepage http://www.delphi-jedi.org } +{ } +{ Version info: } +{ 021230 - initial version } +{ 030101 - routed errors from 'init' to the OnError event } +{ } +{ } +{******************************************************************} +{ } +{ The contents of this file are subject to the } +{ } +{ Mozilla Public License Version 1.1 (the "License") } +{ } +{ You may not use this file except in compliance with the License. } +{ You may obtain a copy of the License at } +{ http://www.mozilla.org/MPL/ } +{ } +{ Software distributed under the License is distributed on an } +{ "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or } +{ implied. See the License for the specific language governing } +{ rights and limitations under the License. } +{ } +{******************************************************************} + +unit PCSCConnector; + +interface + +uses + Windows, Messages, Forms, Classes, SysUtils, + SCardErr, WinSCard, WinSmCrd; + +type + TErrSource = (esInit, esConnect, esGetStatus, esTransmit); + TNeededPIN = (npPIN1, npPIN2, npPUK1, npPUK2); + TDelimiters = set of Char; + + TPCSCErrorEvent = procedure(Sender: TObject; ErrSource: TErrSource; ErrCode: cardinal) of object; + TPCSCPinEvent = procedure(Sender: TObject; NeedPIN: TNeededPIN) of object; + +const + MAXAPDULENGTH = 260; // CLA + INS + P1..3 + 255Bytes + NOREADERSELECTED = -1; + SCARD_PCI_T0 : SCARD_IO_REQUEST = (dwProtocol:1; dbPciLength:8); + SCARD_PCI_T1 : SCARD_IO_REQUEST = (dwProtocol:2; dbPciLength:8); + SCARD_PROTOCOL_T0 = $00000001; + SCARD_PROTOCOL_T1 = $00000002; + SCARD_PROTOCOL_RAW = $00010000; + SCARD_PROTOCOL_UNK = $00000000; + + WM_CARDSTATE = WM_USER + 42; + + GSMStatusOK = $9000; + GSMStatusMemoryError = $9240; + GSMStatusNoEFSelected = $9400; + GSMStatusOutOfRange = $9402; + GSMStatusNotFound = $9404; + GSMStatusFCDoNotMatch = $9408; + GSMStatusCHVNeeded = $9802; + GSMStatusAuthFailed = $9804; + GSMStatusAuthFailedBl = $9840; + GSMStatusTechProblem = $6F00; + GSMStatusResponseData = $9F; + + GSMFileTypeRFU = 0; + GSMFileTypeMF = 1; + GSMFileTypeDF = 2; + GSMFileTypeEF = 4; + + GSMEfTransp = 0; + GSMEfLinFixed = 1; + GSMEfCyclic = 3; + +type + TPCSCConnector = class(TComponent) + + protected + FContext : cardinal; + FCardHandle : integer; + FConnected : boolean; + FNumReaders : integer; + FUseReaderNum : integer; + FReaderList : TStringlist; + FAttrProtocol : integer; + FAttrICCType : string; + FAttrCardATR : string; + FAttrVendorName : string; + FAttrVendorSerial : string; + FGSMCurrentFile : string; + FGSMFileInfo : string; + FGSMDirInfo : string; + FGSMVoltage30 : boolean; + FGSMVoltage18 : boolean; + + FOnReaderWaiting : TNotifyEvent; + FOnReaderListChange : TNotifyEvent; + FOnCardInserted : TNotifyEvent; + FOnCardActive : TNotifyEvent; + FOnCardRemoved : TNotifyEvent; + FOnCardInvalid : TNotifyEvent; + FOnError : TPCSCErrorEvent; + FOnCHVNeeded : TPCSCPinEvent; + + procedure SetReaderNum(Value: integer); + procedure MessageWndProc(var Msg: TMessage); + function ConnectSelectedReader: boolean; + procedure ProcessReaderState(const OldState,NewState: cardinal); + procedure GetReaderAttributes; + procedure GetCardAttributes; + procedure ClearReaderAttributes; + procedure ClearCardAttributes; + function IsReaderOpen: boolean; + function GetReaderState: cardinal; + procedure CloseAndDisconnect; + procedure CardInsertedAction; + procedure CardActiveAction; + procedure CardRemovedAction; + + public + constructor Create(AOwner: TComponent); override; + destructor Destroy; override; + function Init: boolean; + function Open: boolean; + procedure Close; + function Connect: boolean; + procedure Disconnect; + function GetResponseFromCard(const apdu: string): string; overload; + function GetResponseFromCard(const command: string; var data: string; var sw1, sw2: byte): boolean; overload; + + function GSMStatus: integer; + function GSMSelect(const FileID: string): integer; + function GSMReadBinary(const Offset, Length: integer; var Data: string): integer; + + published + property UseReaderNum: integer read FUseReaderNum write SetReaderNum default -1; + + property OnCardInserted: TNotifyEvent read FOnCardInserted write FOnCardInserted; + property OnCardActive: TNotifyEvent read FOnCardActive write FOnCardActive; + property OnCardRemoved: TNotifyEvent read FOnCardRemoved write FOnCardRemoved; + property OnCardInvalid: TNotifyEvent read FOnCardInvalid write FOnCardInvalid; + property OnReaderWaiting: TNotifyEvent read FOnReaderWaiting write FOnReaderWaiting; + property OnReaderListChange: TNotifyEvent read FOnReaderListChange write FOnReaderListChange; + property OnError: TPCSCErrorEvent read FOnError write FOnError; + property OnCHVNeeded: TPCSCPinEvent read FOnCHVNeeded write FOnCHVNeeded; + + property ReaderList: TStringList read FReaderList; + property NumReaders: integer read FNumReaders; + property Connected: boolean read FConnected; + property Opened: boolean read IsReaderOpen; + property ReaderState: cardinal read GetReaderState; + property AttrProtocol: integer read FAttrProtocol; + property AttrICCType: string read FAttrICCType; + property AttrCardATR: string read FAttrCardATR; + property AttrVendorName: string read FAttrVendorName; + property AttrVendorSerial: string read FAttrVendorSerial; + property GSMCurrentFile: string read FGSMCurrentFile; + property GSMFileInfo: string read FGSMFileInfo; + property GSMDirInfo: string read FGSMDirInfo; + property GSMVoltage30: boolean read FGSMVoltage30; + property GSMVoltage18: boolean read FGSMVoltage18; + end; + +procedure Register; + +implementation + +var + ActReaderState : cardinal; + LastReaderState : cardinal; + SelectedReader : String; + ReaderOpen : boolean; + NotifyHandle : HWND; + +const + + // GSM Commands + GCGetStatus = #$A0#$F2#$00#$00#$16; + GCGetResponse = #$A0#$C0#$00#$00; + GCSelectFile = #$A0#$A4#$00#$00#$02; + GCReadBinary = #$A0#$B0; + + GSMMasterFile = #$3f#$00; + DFgsm900 = #$7f#$20; + DFgsm1800 = #$7f#$21; + +procedure Register; +begin + RegisterComponents('More...', [TPCSCConnector]); +end; + +function SortOutSubstrings(const From:string; var t:array of string; const Delim:TDelimiters = [' ',';']; const ConcatDelim:boolean = true):integer; +var a,b,s,i : integer; + sep : boolean; +begin +a := 1; +b := Low(t); +s := 1; +i := 0; +sep := ConcatDelim; +t[b] := ''; + +while a <= Length(From) do + begin + if not (From[a] in Delim) then + begin + Inc(i); + sep := false; + end else + begin + if not sep then + begin + t[b] := Copy(From, s, i); + Inc(b); + if b > High(t) then Break; + t[b] := ''; + end; + if ConcatDelim then sep := true; + s := a + 1; + i := 0; + end; + Inc(a); + end; +if (b <= High(t)) and (i > 0) then + begin + t[b] := Copy(From, s, i); + Inc(b); + end; +for a := b + 1 to High(t) do t[a] := ''; +Result := b; +end; + +function OrdD(const From: string; const Index: integer): integer; +begin +if Index <= Length(From) then Result := Ord(From[Index]) + else Result := 0; +end; + +function CardWatcherThread(PContext: pointer): integer; +var + RetVar : cardinal; + RContext : cardinal; + RStates : array[0..1] of SCARD_READERSTATEA; +begin + try + RContext := cardinal(PContext^); + FillChar(RStates,SizeOf(RStates),#0); + RStates[0].szReader := PAnsichar(SelectedReader); + RStates[0].pvUserData := nil; + RStates[0].dwEventState := ActReaderState; + while ReaderOpen do + begin + RStates[0].dwCurrentState := RStates[0].dwEventState; + RetVar := SCardGetStatusChangeA(RContext, -1, RStates, 1); + ActReaderState := RStates[0].dwEventState; + PostMessage(NotifyHandle, WM_CARDSTATE, RetVar, 0); + end; + finally + Result := 0; + end; +end; + +procedure TPCSCConnector.MessageWndProc(var Msg: TMessage); +begin + if (Msg.Msg = WM_CARDSTATE) then + begin + if Msg.WParam <> SCARD_S_SUCCESS then + if Assigned(FOnError) then FOnError(Self, esGetStatus, Msg.WParam); + if ActReaderState <> LastReaderState then + begin + ProcessReaderState(LastReaderState, ActReaderState); + end; + end + else Msg.Result := DefWindowProc(NotifyHandle, Msg.Msg, Msg.WParam, Msg.LParam); +end; + +constructor TPCSCConnector.Create(AOwner: TComponent); +begin + inherited Create(AOwner); + FReaderList := TStringlist.Create; + FContext := 0; + FCardHandle := 0; + FNumReaders := 0; + FUseReaderNum := -1; + FConnected := false; + ActReaderState := SCARD_STATE_UNAWARE; + LastReaderState := SCARD_STATE_UNAWARE; + ReaderOpen := false; + ClearReaderAttributes; + ClearCardAttributes; + if not (csDesigning in ComponentState) then NotifyHandle := AllocateHWnd(MessageWndProc); +end; + +destructor TPCSCConnector.Destroy; +begin + CloseAndDisconnect; + SCardReleaseContext(FContext); + FReaderList.Free; + if not (csDesigning in ComponentState) then DeallocateHWnd(NotifyHandle); + inherited Destroy; +end; + +function TPCSCConnector.Init: boolean; +var + RetVar : cardinal; + ReaderList : string; + ReaderListSize : integer; + v : array[0..MAXIMUM_SMARTCARD_READERS] of string; + i : integer; + +begin + Result := false; + FNumReaders := 0; + CloseAndDisconnect; + if SCardIsValidContext(FContext) = SCARD_S_SUCCESS then SCardReleaseContext(FContext); + RetVar := SCardEstablishContext(SCARD_SCOPE_USER, nil, nil, @FContext); + if RetVar = SCARD_S_SUCCESS then + begin + ReaderListSize := 0; + RetVar := SCardListReadersW(FContext, nil, nil, ReaderListSize); + if RetVar = SCARD_S_SUCCESS then + begin + SetLength(ReaderList, ReaderListSize); + SCardListReadersW(FContext, nil, Pointer(ReaderList), ReaderListSize); + FReaderList.Clear; + SortOutSubstrings(ReaderList,v,[#0]); + for i := 0 to MAXIMUM_SMARTCARD_READERS do + if v[i] <> '' then FReaderList.Add(v[i]); + FNumReaders := FReaderList.Count; + if FNumReaders > 0 then + begin + if Assigned(FOnReaderListChange) then FOnReaderListChange(Self); + Result := true; + end; + end else if Assigned(FOnError) then FOnError(Self, esInit, RetVar); + end else if Assigned(FOnError) then FOnError(Self, esInit, RetVar); +end; + +function TPCSCConnector.Open: boolean; +var + ThreadID : LongWord; +begin + CloseAndDisconnect; + if (FUseReaderNum > NOREADERSELECTED) and + (SCardIsValidContext(FContext) = SCARD_S_SUCCESS) then + begin + ReaderOpen := true; + ActReaderState := SCARD_STATE_UNAWARE; + LastReaderState := SCARD_STATE_UNAWARE; + BeginThread(nil, 0, CardWatcherThread, @FContext, 0, ThreadID); + Result := true; + end else Result := false; +end; + +procedure TPCSCConnector.Close; +begin + ReaderOpen := false; + SCardCancel(FContext); + if FConnected then Disconnect; +end; + +function TPCSCConnector.Connect: boolean; +begin + if FConnected then Disconnect; + if FUseReaderNum > NOREADERSELECTED then + if ConnectSelectedReader then FConnected := true + else FConnected := false; + Result := FConnected; +end; + +procedure TPCSCConnector.Disconnect; +begin + if FConnected then + begin + SCardDisconnect(FCardHandle, SCARD_RESET_CARD); + FConnected := false; + FCardHandle := 0; + end; +end; + +procedure TPCSCConnector.CloseAndDisconnect; +begin + if FConnected then Disconnect; + if ReaderOpen then Close; +end; + +function TPCSCConnector.ConnectSelectedReader: boolean; +var + RetVar : cardinal; +begin + RetVar := SCardConnectW(FContext, + PWideChar(SelectedReader), + SCARD_SHARE_EXCLUSIVE, + SCARD_PROTOCOL_Tx, + FCardHandle, + @FAttrProtocol); + case RetVar of + SCARD_S_SUCCESS : begin + CardActiveAction; + Result := true; + end; + SCARD_W_REMOVED_CARD : begin + Result := true; + end; + else begin + Result := false; + if Assigned(FOnError) then FOnError(Self, esConnect, RetVar); + end; + end; +end; + +procedure TPCSCConnector.ProcessReaderState(const OldState,NewState: cardinal); +var + CardInOld, CardInNew : boolean; + ReaderEmOld, ReaderEmNew : boolean; + CardMuteOld, CardMuteNew : boolean; + CardIgnore : boolean; + +begin +CardInOld := (OldState and SCARD_STATE_PRESENT) > 0; +CardInNew := (NewState and SCARD_STATE_PRESENT) > 0; +ReaderEmOld := (OldState and SCARD_STATE_EMPTY) > 0; +ReaderEmNew := (NewState and SCARD_STATE_EMPTY) > 0; +CardMuteOld := (OldState and SCARD_STATE_MUTE) > 0; +CardMuteNew := (NewState and SCARD_STATE_MUTE) > 0; +CardIgnore := (NewState and SCARD_STATE_IGNORE) > 0; + +if CardMuteNew and + not CardMuteold then if Assigned(FOnCardInvalid) then FOnCardInvalid(Self); + +if CardInNew and + not CardInOld and + not CardMuteNew and + not CardIgnore then CardInsertedAction; + +if CardInOld and + not CardInNew then CardRemovedAction; + +if ReaderEmNew and + not ReaderEmOld then begin + if Assigned(FOnReaderWaiting) then FOnReaderWaiting(Self); + end; + +LastReaderState := NewState; +end; + +procedure TPCSCConnector.CardInsertedAction; +begin + if Assigned(FOnCardInserted) then FOnCardInserted(Self); + if FConnected then CardActiveAction; +end; + +procedure TPCSCConnector.CardActiveAction; +begin + GetReaderAttributes; + if FAttrProtocol <> SCARD_PROTOCOL_UNK then + begin + GetCardAttributes; + if Assigned(FOnCardActive) then FOnCardActive(Self); + end; +end; + +procedure TPCSCConnector.CardRemovedAction; +begin + ClearReaderAttributes; + ClearCardAttributes; + if Assigned(FOnCardRemoved) then FOnCardRemoved(Self); + Disconnect; +end; + +procedure TPCSCConnector.SetReaderNum(Value: Integer); +begin + if Value <> FUseReaderNum then + begin + CloseAndDisconnect; + if Value < FReaderList.Count then + begin + SelectedReader := PChar(FReaderList[Value]); + FUseReaderNum := Value; + end else + begin + SelectedReader := ''; + FUseReaderNum := -1; + end; + end; +end; + +function TPCSCConnector.IsReaderOpen: boolean; +begin + Result := ReaderOpen; +end; + +function TPCSCConnector.GetReaderState: cardinal; +begin + Result := ActReaderState; +end; + +procedure TPCSCConnector.GetReaderAttributes; +var + RetVar : cardinal; + ABuf : string; + AIBuf : integer; + ALen : integer; +begin + ABuf := StringOfChar(#0, 127); + ALen := Length(ABuf); + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_ATR_STRING, Pointer(ABuf), @ALen); + if RetVar = SCARD_S_SUCCESS then FAttrCardATR := Copy(ABuf, 1, ALen) + else FAttrCardATR := ''; + + ALen := Length(ABuf); + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_VENDOR_NAME, Pointer(ABuf), @ALen); + if RetVar = SCARD_S_SUCCESS then FAttrVendorName := Copy(ABuf, 1, ALen) + else FAttrVendorName := ''; + + ALen := Length(ABuf); + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_VENDOR_IFD_SERIAL_NO, Pointer(ABuf), @ALen); + if RetVar = SCARD_S_SUCCESS then FAttrVendorSerial := Copy(ABuf, 1, ALen) + else FAttrVendorSerial := ''; + + ALen := SizeOf(AIBuf); + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_CURRENT_PROTOCOL_TYPE, @AIBuf, @ALen); + if RetVar = SCARD_S_SUCCESS then FAttrProtocol := AIBuf + else FAttrProtocol := 0; + + ALen := SizeOf(AIBuf); + AIBuf := 0; + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_ICC_TYPE_PER_ATR, @AIBuf, @ALen); + if RetVar = SCARD_S_SUCCESS then begin + case AIBuf of + 1 : FAttrICCType := 'ISO7816A'; + 2 : FAttrICCType := 'ISO7816S'; + else FAttrICCType := 'UNKNOWN'; + end; + end + else FAttrICCType := ''; +end; + +procedure TPCSCConnector.GetCardAttributes; +begin +if GSMSelect(DFgsm900) = GSMStatusOK then + begin + FGSMVoltage30 := (OrdD(FGSMDirInfo, 14) and $10) > 0; + FGSMVoltage18 := (OrdD(FGSMDirInfo, 14) and $20) > 0; + end; +end; + +procedure TPCSCConnector.ClearReaderAttributes; +begin + FAttrCardATR := ''; + FAttrVendorName := ''; + FAttrVendorSerial := ''; + FAttrProtocol := 0; + FAttrICCType := ''; +end; + +procedure TPCSCConnector.ClearCardAttributes; +begin + FGSMCurrentFile := ''; + FGSMFileInfo := ''; + FGSMDirInfo := ''; + FGSMVoltage30 := false; + FGSMVoltage18 := false; +end; + +function TPCSCConnector.GetResponseFromCard(const APdu: string): string; +var + RetVar : cardinal; + SBuf : string; + SLen : cardinal; + RBuf : string; + RLen : cardinal; + Ppci : Pointer; +begin +SBuf := APdu; +RBuf := StringOfChar(#0,MAXAPDULENGTH); +if Length(SBuf) <= MAXAPDULENGTH then + begin + case FAttrProtocol of + SCARD_PROTOCOL_T0 : Ppci := @SCARD_PCI_T0; + SCARD_PROTOCOL_T1 : Ppci := @SCARD_PCI_T1; + else Ppci := nil; + end; + SLen := Length(APdu); + RLen := Length(RBuf); + RetVar := SCardTransmit(FCardHandle, Ppci, Pointer(SBuf), SLen, nil, Pointer(RBuf), @RLen); + if RetVar = SCARD_S_SUCCESS then + begin + Result := Copy(RBuf,1,RLen); + end else + begin + Result := ''; + if Assigned(FOnError) then FOnError(Self, esTransmit, RetVar); + end; + end; +end; + +function TPCSCConnector.GetResponseFromCard(const Command: string; var Data: string; var sw1, sw2: byte): boolean; +var + Answer : string; + AnswerL : integer; +begin +Answer := GetResponseFromCard(Command + Data); +AnswerL := Length(Answer); +if AnswerL >= 2 then + begin + Data := Copy(Answer, 1, AnswerL - 2); + sw1 := Ord(Answer[AnswerL - 1]); + sw2 := Ord(Answer[AnswerL]); + if sw1 = GSMStatusResponseData then + begin + Data := Chr(sw2); + if not GetResponseFromCard(GCGetResponse, Data, sw1, sw2) then + begin + Data := ''; + sw1 := 0; + sw2 := 0; + Result := false; + end else Result := true; + end else Result := true; + end else + begin + Data := ''; + sw1 := 0; + sw2 := 0; + Result := false; + end; +end; + +function TPCSCConnector.GSMStatus: integer; +var + Answer : string; + sw1, sw2 : byte; +begin + GetResponseFromCard(GCGetStatus, Answer, sw1, sw2); + Result := (sw1 shl 8) + sw2; + if Result = GSMStatusOK then + begin + FGSMDirInfo := Answer; + FGSMCurrentFile := Copy(Answer, 5, 2); + end else + begin + FGSMDirInfo := ''; + end; +end; + +function TPCSCConnector.GSMSelect(const FileID: string): integer; +var + Answer : string; + sw1, sw2 : byte; +begin + Answer := FileID; + GetResponseFromCard(GCSelectFile, Answer, sw1, sw2); + Result := (sw1 shl 8) + sw2; + if Result = GSMStatusOK then + begin + FGSMCurrentFile := Copy(Answer, 5, 2); + if OrdD(Answer, 7) = GSMFileTypeEF then + begin + FGSMFileInfo := Answer; + end else + begin + FGSMDirInfo := Answer; + end; + end; +end; + +function TPCSCConnector.GSMReadBinary(const Offset, Length: integer; var Data: string): integer; +var + Command : string; + sw1, sw2 : byte; +begin + Command := GCReadBinary + Chr(Offset div 256) + Chr(Offset mod 256) + Chr(Length mod 256); + GetResponseFromCard(Command, Data, sw1, sw2); + Result := (sw1 shl 8) + sw2; + if Result = GSMStatusOK then + begin + end; +end; + +end. + diff --git a/__history/PCSCConnector.pas.~121~ b/__history/PCSCConnector.pas.~121~ new file mode 100644 index 0000000..705bd72 --- /dev/null +++ b/__history/PCSCConnector.pas.~121~ @@ -0,0 +1,699 @@ +{******************************************************************} +{ } +{ PC/SC Interface component } +{ Helps you access a cardreader through Microsofts SmartCard API } +{ } +{ The Original Code is PCSCConnector.pas } +{ } +{ The Initial Developer of the Original Code is } +{ Norbert Huettisch (nobbi(at)nobbi.com) } +{ } +{ Any suggestions and improvements to the code are appreciated } +{ } +{ This Code uses a modified SCardErr.pas (included) } +{ This Code uses a modified WinSCard.pas (included) } +{ This code uses the original WinSmCrd.pas (included) } +{ } +{ All originally made by Chris Dickerson (chrisd(at)tsc.com), } +{ available as 'Interface units for the Microsoft Smart Card API' } +{ at the Project JEDI Homepage http://www.delphi-jedi.org } +{ } +{ Version info: } +{ 021230 - initial version } +{ 030101 - routed errors from 'init' to the OnError event } +{ } +{ } +{******************************************************************} +{ } +{ The contents of this file are subject to the } +{ } +{ Mozilla Public License Version 1.1 (the "License") } +{ } +{ You may not use this file except in compliance with the License. } +{ You may obtain a copy of the License at } +{ http://www.mozilla.org/MPL/ } +{ } +{ Software distributed under the License is distributed on an } +{ "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or } +{ implied. See the License for the specific language governing } +{ rights and limitations under the License. } +{ } +{******************************************************************} + +unit PCSCConnector; + +interface + +uses + Windows, Messages, Forms, Classes, SysUtils, + SCardErr, WinSCard, WinSmCrd; + +type + TErrSource = (esInit, esConnect, esGetStatus, esTransmit); + TNeededPIN = (npPIN1, npPIN2, npPUK1, npPUK2); + TDelimiters = set of Char; + + TPCSCErrorEvent = procedure(Sender: TObject; ErrSource: TErrSource; ErrCode: cardinal) of object; + TPCSCPinEvent = procedure(Sender: TObject; NeedPIN: TNeededPIN) of object; + +const + MAXAPDULENGTH = 260; // CLA + INS + P1..3 + 255Bytes + NOREADERSELECTED = -1; + SCARD_PCI_T0 : SCARD_IO_REQUEST = (dwProtocol:1; dbPciLength:8); + SCARD_PCI_T1 : SCARD_IO_REQUEST = (dwProtocol:2; dbPciLength:8); + SCARD_PROTOCOL_T0 = $00000001; + SCARD_PROTOCOL_T1 = $00000002; + SCARD_PROTOCOL_RAW = $00010000; + SCARD_PROTOCOL_UNK = $00000000; + + WM_CARDSTATE = WM_USER + 42; + + GSMStatusOK = $9000; + GSMStatusMemoryError = $9240; + GSMStatusNoEFSelected = $9400; + GSMStatusOutOfRange = $9402; + GSMStatusNotFound = $9404; + GSMStatusFCDoNotMatch = $9408; + GSMStatusCHVNeeded = $9802; + GSMStatusAuthFailed = $9804; + GSMStatusAuthFailedBl = $9840; + GSMStatusTechProblem = $6F00; + GSMStatusResponseData = $9F; + + GSMFileTypeRFU = 0; + GSMFileTypeMF = 1; + GSMFileTypeDF = 2; + GSMFileTypeEF = 4; + + GSMEfTransp = 0; + GSMEfLinFixed = 1; + GSMEfCyclic = 3; + +type + TPCSCConnector = class(TComponent) + + protected + FContext : cardinal; + FCardHandle : integer; + FConnected : boolean; + FNumReaders : integer; + FUseReaderNum : integer; + FReaderList : TStringlist; + FAttrProtocol : integer; + FAttrICCType : string; + FAttrCardATR : string; + FAttrVendorName : string; + FAttrVendorSerial : string; + FGSMCurrentFile : string; + FGSMFileInfo : string; + FGSMDirInfo : string; + FGSMVoltage30 : boolean; + FGSMVoltage18 : boolean; + + FOnReaderWaiting : TNotifyEvent; + FOnReaderListChange : TNotifyEvent; + FOnCardInserted : TNotifyEvent; + FOnCardActive : TNotifyEvent; + FOnCardRemoved : TNotifyEvent; + FOnCardInvalid : TNotifyEvent; + FOnError : TPCSCErrorEvent; + FOnCHVNeeded : TPCSCPinEvent; + + procedure SetReaderNum(Value: integer); + procedure MessageWndProc(var Msg: TMessage); + function ConnectSelectedReader: boolean; + procedure ProcessReaderState(const OldState,NewState: cardinal); + procedure GetReaderAttributes; + procedure GetCardAttributes; + procedure ClearReaderAttributes; + procedure ClearCardAttributes; + function IsReaderOpen: boolean; + function GetReaderState: cardinal; + procedure CloseAndDisconnect; + procedure CardInsertedAction; + procedure CardActiveAction; + procedure CardRemovedAction; + + public + constructor Create(AOwner: TComponent); override; + destructor Destroy; override; + function Init: boolean; + function Open: boolean; + procedure Close; + function Connect: boolean; + procedure Disconnect; + function GetResponseFromCard(const apdu: string): string; overload; + function GetResponseFromCard(const command: string; var data: string; var sw1, sw2: byte): boolean; overload; + + function GSMStatus: integer; + function GSMSelect(const FileID: string): integer; + function GSMReadBinary(const Offset, Length: integer; var Data: string): integer; + + published + property UseReaderNum: integer read FUseReaderNum write SetReaderNum default -1; + + property OnCardInserted: TNotifyEvent read FOnCardInserted write FOnCardInserted; + property OnCardActive: TNotifyEvent read FOnCardActive write FOnCardActive; + property OnCardRemoved: TNotifyEvent read FOnCardRemoved write FOnCardRemoved; + property OnCardInvalid: TNotifyEvent read FOnCardInvalid write FOnCardInvalid; + property OnReaderWaiting: TNotifyEvent read FOnReaderWaiting write FOnReaderWaiting; + property OnReaderListChange: TNotifyEvent read FOnReaderListChange write FOnReaderListChange; + property OnError: TPCSCErrorEvent read FOnError write FOnError; + property OnCHVNeeded: TPCSCPinEvent read FOnCHVNeeded write FOnCHVNeeded; + + property ReaderList: TStringList read FReaderList; + property NumReaders: integer read FNumReaders; + property Connected: boolean read FConnected; + property Opened: boolean read IsReaderOpen; + property ReaderState: cardinal read GetReaderState; + property AttrProtocol: integer read FAttrProtocol; + property AttrICCType: string read FAttrICCType; + property AttrCardATR: string read FAttrCardATR; + property AttrVendorName: string read FAttrVendorName; + property AttrVendorSerial: string read FAttrVendorSerial; + property GSMCurrentFile: string read FGSMCurrentFile; + property GSMFileInfo: string read FGSMFileInfo; + property GSMDirInfo: string read FGSMDirInfo; + property GSMVoltage30: boolean read FGSMVoltage30; + property GSMVoltage18: boolean read FGSMVoltage18; + end; + +procedure Register; + +implementation + +var + ActReaderState : cardinal; + LastReaderState : cardinal; + SelectedReader : String; + ReaderOpen : boolean; + NotifyHandle : HWND; + +const + + // GSM Commands + GCGetStatus = #$A0#$F2#$00#$00#$16; + GCGetResponse = #$A0#$C0#$00#$00; + GCSelectFile = #$A0#$A4#$00#$00#$02; + GCReadBinary = #$A0#$B0; + + GSMMasterFile = #$3f#$00; + DFgsm900 = #$7f#$20; + DFgsm1800 = #$7f#$21; + +procedure Register; +begin + RegisterComponents('More...', [TPCSCConnector]); +end; + +function SortOutSubstrings(const From:string; var t:array of string; const Delim:TDelimiters = [' ',';']; const ConcatDelim:boolean = true):integer; +var a,b,s,i : integer; + sep : boolean; +begin +a := 1; +b := Low(t); +s := 1; +i := 0; +sep := ConcatDelim; +t[b] := ''; + +while a <= Length(From) do + begin + if not (From[a] in Delim) then + begin + Inc(i); + sep := false; + end else + begin + if not sep then + begin + t[b] := Copy(From, s, i); + Inc(b); + if b > High(t) then Break; + t[b] := ''; + end; + if ConcatDelim then sep := true; + s := a + 1; + i := 0; + end; + Inc(a); + end; +if (b <= High(t)) and (i > 0) then + begin + t[b] := Copy(From, s, i); + Inc(b); + end; +for a := b + 1 to High(t) do t[a] := ''; +Result := b; +end; + +function OrdD(const From: string; const Index: integer): integer; +begin +if Index <= Length(From) then Result := Ord(From[Index]) + else Result := 0; +end; + +function CardWatcherThread(PContext: pointer): integer; +var + RetVar : cardinal; + RContext : cardinal; + RStates : array[0..1] of SCARD_READERSTATEA; +begin + try + RContext := cardinal(PContext^); + FillChar(RStates,SizeOf(RStates),#0); + RStates[0].szReader := 'ACS ACR122 0'; //PAnsichar(SelectedReader); + RStates[0].pvUserData := nil; + RStates[0].dwEventState := ActReaderState; + while ReaderOpen do + begin + RStates[0].dwCurrentState := RStates[0].dwEventState; + RetVar := SCardGetStatusChangeA(RContext, -1, RStates, 1); + ActReaderState := RStates[0].dwEventState; + PostMessage(NotifyHandle, WM_CARDSTATE, RetVar, 0); + end; + finally + Result := 0; + end; +end; + +procedure TPCSCConnector.MessageWndProc(var Msg: TMessage); +begin + if (Msg.Msg = WM_CARDSTATE) then + begin + if Msg.WParam <> SCARD_S_SUCCESS then + if Assigned(FOnError) then FOnError(Self, esGetStatus, Msg.WParam); + if ActReaderState <> LastReaderState then + begin + ProcessReaderState(LastReaderState, ActReaderState); + end; + end + else Msg.Result := DefWindowProc(NotifyHandle, Msg.Msg, Msg.WParam, Msg.LParam); +end; + +constructor TPCSCConnector.Create(AOwner: TComponent); +begin + inherited Create(AOwner); + FReaderList := TStringlist.Create; + FContext := 0; + FCardHandle := 0; + FNumReaders := 0; + FUseReaderNum := -1; + FConnected := false; + ActReaderState := SCARD_STATE_UNAWARE; + LastReaderState := SCARD_STATE_UNAWARE; + ReaderOpen := false; + ClearReaderAttributes; + ClearCardAttributes; + if not (csDesigning in ComponentState) then NotifyHandle := AllocateHWnd(MessageWndProc); +end; + +destructor TPCSCConnector.Destroy; +begin + CloseAndDisconnect; + SCardReleaseContext(FContext); + FReaderList.Free; + if not (csDesigning in ComponentState) then DeallocateHWnd(NotifyHandle); + inherited Destroy; +end; + +function TPCSCConnector.Init: boolean; +var + RetVar : cardinal; + ReaderList : string; + ReaderListSize : integer; + v : array[0..MAXIMUM_SMARTCARD_READERS] of string; + i : integer; + +begin + Result := false; + FNumReaders := 0; + CloseAndDisconnect; + if SCardIsValidContext(FContext) = SCARD_S_SUCCESS then SCardReleaseContext(FContext); + RetVar := SCardEstablishContext(SCARD_SCOPE_USER, nil, nil, @FContext); + if RetVar = SCARD_S_SUCCESS then + begin + ReaderListSize := 0; + RetVar := SCardListReadersW(FContext, nil, nil, ReaderListSize); + if RetVar = SCARD_S_SUCCESS then + begin + SetLength(ReaderList, ReaderListSize); + SCardListReadersW(FContext, nil, Pointer(ReaderList), ReaderListSize); + FReaderList.Clear; + SortOutSubstrings(ReaderList,v,[#0]); + for i := 0 to MAXIMUM_SMARTCARD_READERS do + if v[i] <> '' then FReaderList.Add(v[i]); + FNumReaders := FReaderList.Count; + if FNumReaders > 0 then + begin + if Assigned(FOnReaderListChange) then FOnReaderListChange(Self); + Result := true; + end; + end else if Assigned(FOnError) then FOnError(Self, esInit, RetVar); + end else if Assigned(FOnError) then FOnError(Self, esInit, RetVar); +end; + +function TPCSCConnector.Open: boolean; +var + ThreadID : LongWord; +begin + CloseAndDisconnect; + if (FUseReaderNum > NOREADERSELECTED) and + (SCardIsValidContext(FContext) = SCARD_S_SUCCESS) then + begin + ReaderOpen := true; + ActReaderState := SCARD_STATE_UNAWARE; + LastReaderState := SCARD_STATE_UNAWARE; + BeginThread(nil, 0, CardWatcherThread, @FContext, 0, ThreadID); + Result := true; + end else Result := false; +end; + +procedure TPCSCConnector.Close; +begin + ReaderOpen := false; + SCardCancel(FContext); + if FConnected then Disconnect; +end; + +function TPCSCConnector.Connect: boolean; +begin + if FConnected then Disconnect; + if FUseReaderNum > NOREADERSELECTED then + if ConnectSelectedReader then FConnected := true + else FConnected := false; + Result := FConnected; +end; + +procedure TPCSCConnector.Disconnect; +begin + if FConnected then + begin + SCardDisconnect(FCardHandle, SCARD_RESET_CARD); + FConnected := false; + FCardHandle := 0; + end; +end; + +procedure TPCSCConnector.CloseAndDisconnect; +begin + if FConnected then Disconnect; + if ReaderOpen then Close; +end; + +function TPCSCConnector.ConnectSelectedReader: boolean; +var + RetVar : cardinal; +begin + RetVar := SCardConnectW(FContext, + PWideChar(SelectedReader), + SCARD_SHARE_EXCLUSIVE, + SCARD_PROTOCOL_Tx, + FCardHandle, + @FAttrProtocol); + case RetVar of + SCARD_S_SUCCESS : begin + CardActiveAction; + Result := true; + end; + SCARD_W_REMOVED_CARD : begin + Result := true; + end; + else begin + Result := false; + if Assigned(FOnError) then FOnError(Self, esConnect, RetVar); + end; + end; +end; + +procedure TPCSCConnector.ProcessReaderState(const OldState,NewState: cardinal); +var + CardInOld, CardInNew : boolean; + ReaderEmOld, ReaderEmNew : boolean; + CardMuteOld, CardMuteNew : boolean; + CardIgnore : boolean; + +begin +CardInOld := (OldState and SCARD_STATE_PRESENT) > 0; +CardInNew := (NewState and SCARD_STATE_PRESENT) > 0; +ReaderEmOld := (OldState and SCARD_STATE_EMPTY) > 0; +ReaderEmNew := (NewState and SCARD_STATE_EMPTY) > 0; +CardMuteOld := (OldState and SCARD_STATE_MUTE) > 0; +CardMuteNew := (NewState and SCARD_STATE_MUTE) > 0; +CardIgnore := (NewState and SCARD_STATE_IGNORE) > 0; + +if CardMuteNew and + not CardMuteold then if Assigned(FOnCardInvalid) then FOnCardInvalid(Self); + +if CardInNew and + not CardInOld and + not CardMuteNew and + not CardIgnore then CardInsertedAction; + +if CardInOld and + not CardInNew then CardRemovedAction; + +if ReaderEmNew and + not ReaderEmOld then begin + if Assigned(FOnReaderWaiting) then FOnReaderWaiting(Self); + end; + +LastReaderState := NewState; +end; + +procedure TPCSCConnector.CardInsertedAction; +begin + if Assigned(FOnCardInserted) then FOnCardInserted(Self); + if FConnected then CardActiveAction; +end; + +procedure TPCSCConnector.CardActiveAction; +begin + GetReaderAttributes; + if FAttrProtocol <> SCARD_PROTOCOL_UNK then + begin + GetCardAttributes; + if Assigned(FOnCardActive) then FOnCardActive(Self); + end; +end; + +procedure TPCSCConnector.CardRemovedAction; +begin + ClearReaderAttributes; + ClearCardAttributes; + if Assigned(FOnCardRemoved) then FOnCardRemoved(Self); + Disconnect; +end; + +procedure TPCSCConnector.SetReaderNum(Value: Integer); +begin + if Value <> FUseReaderNum then + begin + CloseAndDisconnect; + if Value < FReaderList.Count then + begin + SelectedReader := PChar(FReaderList[Value]); + FUseReaderNum := Value; + end else + begin + SelectedReader := ''; + FUseReaderNum := -1; + end; + end; +end; + +function TPCSCConnector.IsReaderOpen: boolean; +begin + Result := ReaderOpen; +end; + +function TPCSCConnector.GetReaderState: cardinal; +begin + Result := ActReaderState; +end; + +procedure TPCSCConnector.GetReaderAttributes; +var + RetVar : cardinal; + ABuf : string; + AIBuf : integer; + ALen : integer; +begin + ABuf := StringOfChar(#0, 127); + ALen := Length(ABuf); + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_ATR_STRING, Pointer(ABuf), @ALen); + if RetVar = SCARD_S_SUCCESS then FAttrCardATR := Copy(ABuf, 1, ALen) + else FAttrCardATR := ''; + + ALen := Length(ABuf); + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_VENDOR_NAME, Pointer(ABuf), @ALen); + if RetVar = SCARD_S_SUCCESS then FAttrVendorName := Copy(ABuf, 1, ALen) + else FAttrVendorName := ''; + + ALen := Length(ABuf); + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_VENDOR_IFD_SERIAL_NO, Pointer(ABuf), @ALen); + if RetVar = SCARD_S_SUCCESS then FAttrVendorSerial := Copy(ABuf, 1, ALen) + else FAttrVendorSerial := ''; + + ALen := SizeOf(AIBuf); + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_CURRENT_PROTOCOL_TYPE, @AIBuf, @ALen); + if RetVar = SCARD_S_SUCCESS then FAttrProtocol := AIBuf + else FAttrProtocol := 0; + + ALen := SizeOf(AIBuf); + AIBuf := 0; + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_ICC_TYPE_PER_ATR, @AIBuf, @ALen); + if RetVar = SCARD_S_SUCCESS then begin + case AIBuf of + 1 : FAttrICCType := 'ISO7816A'; + 2 : FAttrICCType := 'ISO7816S'; + else FAttrICCType := 'UNKNOWN'; + end; + end + else FAttrICCType := ''; +end; + +procedure TPCSCConnector.GetCardAttributes; +begin +if GSMSelect(DFgsm900) = GSMStatusOK then + begin + FGSMVoltage30 := (OrdD(FGSMDirInfo, 14) and $10) > 0; + FGSMVoltage18 := (OrdD(FGSMDirInfo, 14) and $20) > 0; + end; +end; + +procedure TPCSCConnector.ClearReaderAttributes; +begin + FAttrCardATR := ''; + FAttrVendorName := ''; + FAttrVendorSerial := ''; + FAttrProtocol := 0; + FAttrICCType := ''; +end; + +procedure TPCSCConnector.ClearCardAttributes; +begin + FGSMCurrentFile := ''; + FGSMFileInfo := ''; + FGSMDirInfo := ''; + FGSMVoltage30 := false; + FGSMVoltage18 := false; +end; + +function TPCSCConnector.GetResponseFromCard(const APdu: string): string; +var + RetVar : cardinal; + SBuf : string; + SLen : cardinal; + RBuf : string; + RLen : cardinal; + Ppci : Pointer; +begin +SBuf := APdu; +RBuf := StringOfChar(#0,MAXAPDULENGTH); +if Length(SBuf) <= MAXAPDULENGTH then + begin + case FAttrProtocol of + SCARD_PROTOCOL_T0 : Ppci := @SCARD_PCI_T0; + SCARD_PROTOCOL_T1 : Ppci := @SCARD_PCI_T1; + else Ppci := nil; + end; + SLen := Length(APdu); + RLen := Length(RBuf); + RetVar := SCardTransmit(FCardHandle, Ppci, Pointer(SBuf), SLen, nil, Pointer(RBuf), @RLen); + if RetVar = SCARD_S_SUCCESS then + begin + Result := Copy(RBuf,1,RLen); + end else + begin + Result := ''; + if Assigned(FOnError) then FOnError(Self, esTransmit, RetVar); + end; + end; +end; + +function TPCSCConnector.GetResponseFromCard(const Command: string; var Data: string; var sw1, sw2: byte): boolean; +var + Answer : string; + AnswerL : integer; +begin +Answer := GetResponseFromCard(Command + Data); +AnswerL := Length(Answer); +if AnswerL >= 2 then + begin + Data := Copy(Answer, 1, AnswerL - 2); + sw1 := Ord(Answer[AnswerL - 1]); + sw2 := Ord(Answer[AnswerL]); + if sw1 = GSMStatusResponseData then + begin + Data := Chr(sw2); + if not GetResponseFromCard(GCGetResponse, Data, sw1, sw2) then + begin + Data := ''; + sw1 := 0; + sw2 := 0; + Result := false; + end else Result := true; + end else Result := true; + end else + begin + Data := ''; + sw1 := 0; + sw2 := 0; + Result := false; + end; +end; + +function TPCSCConnector.GSMStatus: integer; +var + Answer : string; + sw1, sw2 : byte; +begin + GetResponseFromCard(GCGetStatus, Answer, sw1, sw2); + Result := (sw1 shl 8) + sw2; + if Result = GSMStatusOK then + begin + FGSMDirInfo := Answer; + FGSMCurrentFile := Copy(Answer, 5, 2); + end else + begin + FGSMDirInfo := ''; + end; +end; + +function TPCSCConnector.GSMSelect(const FileID: string): integer; +var + Answer : string; + sw1, sw2 : byte; +begin + Answer := FileID; + GetResponseFromCard(GCSelectFile, Answer, sw1, sw2); + Result := (sw1 shl 8) + sw2; + if Result = GSMStatusOK then + begin + FGSMCurrentFile := Copy(Answer, 5, 2); + if OrdD(Answer, 7) = GSMFileTypeEF then + begin + FGSMFileInfo := Answer; + end else + begin + FGSMDirInfo := Answer; + end; + end; +end; + +function TPCSCConnector.GSMReadBinary(const Offset, Length: integer; var Data: string): integer; +var + Command : string; + sw1, sw2 : byte; +begin + Command := GCReadBinary + Chr(Offset div 256) + Chr(Offset mod 256) + Chr(Length mod 256); + GetResponseFromCard(Command, Data, sw1, sw2); + Result := (sw1 shl 8) + sw2; + if Result = GSMStatusOK then + begin + end; +end; + +end. + diff --git a/__history/PCSCConnector.pas.~122~ b/__history/PCSCConnector.pas.~122~ new file mode 100644 index 0000000..10b1d6e --- /dev/null +++ b/__history/PCSCConnector.pas.~122~ @@ -0,0 +1,701 @@ +{******************************************************************} +{ } +{ PC/SC Interface component } +{ Helps you access a cardreader through Microsofts SmartCard API } +{ } +{ The Original Code is PCSCConnector.pas } +{ } +{ The Initial Developer of the Original Code is } +{ Norbert Huettisch (nobbi(at)nobbi.com) } +{ } +{ Any suggestions and improvements to the code are appreciated } +{ } +{ This Code uses a modified SCardErr.pas (included) } +{ This Code uses a modified WinSCard.pas (included) } +{ This code uses the original WinSmCrd.pas (included) } +{ } +{ All originally made by Chris Dickerson (chrisd(at)tsc.com), } +{ available as 'Interface units for the Microsoft Smart Card API' } +{ at the Project JEDI Homepage http://www.delphi-jedi.org } +{ } +{ Version info: } +{ 021230 - initial version } +{ 030101 - routed errors from 'init' to the OnError event } +{ } +{ } +{******************************************************************} +{ } +{ The contents of this file are subject to the } +{ } +{ Mozilla Public License Version 1.1 (the "License") } +{ } +{ You may not use this file except in compliance with the License. } +{ You may obtain a copy of the License at } +{ http://www.mozilla.org/MPL/ } +{ } +{ Software distributed under the License is distributed on an } +{ "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or } +{ implied. See the License for the specific language governing } +{ rights and limitations under the License. } +{ } +{******************************************************************} + +unit PCSCConnector; + +interface + +uses + Windows, Messages, Forms, Classes, SysUtils, + SCardErr, WinSCard, WinSmCrd; + +type + TErrSource = (esInit, esConnect, esGetStatus, esTransmit); + TNeededPIN = (npPIN1, npPIN2, npPUK1, npPUK2); + TDelimiters = set of Char; + + TPCSCErrorEvent = procedure(Sender: TObject; ErrSource: TErrSource; ErrCode: cardinal) of object; + TPCSCPinEvent = procedure(Sender: TObject; NeedPIN: TNeededPIN) of object; + +const + MAXAPDULENGTH = 260; // CLA + INS + P1..3 + 255Bytes + NOREADERSELECTED = -1; + SCARD_PCI_T0 : SCARD_IO_REQUEST = (dwProtocol:1; dbPciLength:8); + SCARD_PCI_T1 : SCARD_IO_REQUEST = (dwProtocol:2; dbPciLength:8); + SCARD_PROTOCOL_T0 = $00000001; + SCARD_PROTOCOL_T1 = $00000002; + SCARD_PROTOCOL_RAW = $00010000; + SCARD_PROTOCOL_UNK = $00000000; + + WM_CARDSTATE = WM_USER + 42; + + GSMStatusOK = $9000; + GSMStatusMemoryError = $9240; + GSMStatusNoEFSelected = $9400; + GSMStatusOutOfRange = $9402; + GSMStatusNotFound = $9404; + GSMStatusFCDoNotMatch = $9408; + GSMStatusCHVNeeded = $9802; + GSMStatusAuthFailed = $9804; + GSMStatusAuthFailedBl = $9840; + GSMStatusTechProblem = $6F00; + GSMStatusResponseData = $9F; + + GSMFileTypeRFU = 0; + GSMFileTypeMF = 1; + GSMFileTypeDF = 2; + GSMFileTypeEF = 4; + + GSMEfTransp = 0; + GSMEfLinFixed = 1; + GSMEfCyclic = 3; + +type + TPCSCConnector = class(TComponent) + + protected + FContext : cardinal; + FCardHandle : integer; + FConnected : boolean; + FNumReaders : integer; + FUseReaderNum : integer; + FReaderList : TStringlist; + FAttrProtocol : integer; + FAttrICCType : string; + FAttrCardATR : string; + FAttrVendorName : string; + FAttrVendorSerial : string; + FGSMCurrentFile : string; + FGSMFileInfo : string; + FGSMDirInfo : string; + FGSMVoltage30 : boolean; + FGSMVoltage18 : boolean; + + FOnReaderWaiting : TNotifyEvent; + FOnReaderListChange : TNotifyEvent; + FOnCardInserted : TNotifyEvent; + FOnCardActive : TNotifyEvent; + FOnCardRemoved : TNotifyEvent; + FOnCardInvalid : TNotifyEvent; + FOnError : TPCSCErrorEvent; + FOnCHVNeeded : TPCSCPinEvent; + + procedure SetReaderNum(Value: integer); + procedure MessageWndProc(var Msg: TMessage); + function ConnectSelectedReader: boolean; + procedure ProcessReaderState(const OldState,NewState: cardinal); + procedure GetReaderAttributes; + procedure GetCardAttributes; + procedure ClearReaderAttributes; + procedure ClearCardAttributes; + function IsReaderOpen: boolean; + function GetReaderState: cardinal; + procedure CloseAndDisconnect; + procedure CardInsertedAction; + procedure CardActiveAction; + procedure CardRemovedAction; + + public + constructor Create(AOwner: TComponent); override; + destructor Destroy; override; + function Init: boolean; + function Open: boolean; + procedure Close; + function Connect: boolean; + procedure Disconnect; + function GetResponseFromCard(const apdu: string): string; overload; + function GetResponseFromCard(const command: string; var data: string; var sw1, sw2: byte): boolean; overload; + + function GSMStatus: integer; + function GSMSelect(const FileID: string): integer; + function GSMReadBinary(const Offset, Length: integer; var Data: string): integer; + + published + property UseReaderNum: integer read FUseReaderNum write SetReaderNum default -1; + + property OnCardInserted: TNotifyEvent read FOnCardInserted write FOnCardInserted; + property OnCardActive: TNotifyEvent read FOnCardActive write FOnCardActive; + property OnCardRemoved: TNotifyEvent read FOnCardRemoved write FOnCardRemoved; + property OnCardInvalid: TNotifyEvent read FOnCardInvalid write FOnCardInvalid; + property OnReaderWaiting: TNotifyEvent read FOnReaderWaiting write FOnReaderWaiting; + property OnReaderListChange: TNotifyEvent read FOnReaderListChange write FOnReaderListChange; + property OnError: TPCSCErrorEvent read FOnError write FOnError; + property OnCHVNeeded: TPCSCPinEvent read FOnCHVNeeded write FOnCHVNeeded; + + property ReaderList: TStringList read FReaderList; + property NumReaders: integer read FNumReaders; + property Connected: boolean read FConnected; + property Opened: boolean read IsReaderOpen; + property ReaderState: cardinal read GetReaderState; + property AttrProtocol: integer read FAttrProtocol; + property AttrICCType: string read FAttrICCType; + property AttrCardATR: string read FAttrCardATR; + property AttrVendorName: string read FAttrVendorName; + property AttrVendorSerial: string read FAttrVendorSerial; + property GSMCurrentFile: string read FGSMCurrentFile; + property GSMFileInfo: string read FGSMFileInfo; + property GSMDirInfo: string read FGSMDirInfo; + property GSMVoltage30: boolean read FGSMVoltage30; + property GSMVoltage18: boolean read FGSMVoltage18; + end; + +procedure Register; + +implementation + +var + ActReaderState : cardinal; + LastReaderState : cardinal; + SelectedReader : String; + ReaderOpen : boolean; + NotifyHandle : HWND; + +const + + // GSM Commands + GCGetStatus = #$A0#$F2#$00#$00#$16; + GCGetResponse = #$A0#$C0#$00#$00; + GCSelectFile = #$A0#$A4#$00#$00#$02; + GCReadBinary = #$A0#$B0; + + GSMMasterFile = #$3f#$00; + DFgsm900 = #$7f#$20; + DFgsm1800 = #$7f#$21; + +procedure Register; +begin + RegisterComponents('More...', [TPCSCConnector]); +end; + +function SortOutSubstrings(const From:string; var t:array of string; const Delim:TDelimiters = [' ',';']; const ConcatDelim:boolean = true):integer; +var a,b,s,i : integer; + sep : boolean; +begin +a := 1; +b := Low(t); +s := 1; +i := 0; +sep := ConcatDelim; +t[b] := ''; + +while a <= Length(From) do + begin + if not (From[a] in Delim) then + begin + Inc(i); + sep := false; + end else + begin + if not sep then + begin + t[b] := Copy(From, s, i); + Inc(b); + if b > High(t) then Break; + t[b] := ''; + end; + if ConcatDelim then sep := true; + s := a + 1; + i := 0; + end; + Inc(a); + end; +if (b <= High(t)) and (i > 0) then + begin + t[b] := Copy(From, s, i); + Inc(b); + end; +for a := b + 1 to High(t) do t[a] := ''; +Result := b; +end; + +function OrdD(const From: string; const Index: integer): integer; +begin +if Index <= Length(From) then Result := Ord(From[Index]) + else Result := 0; +end; + +function CardWatcherThread(PContext: pointer): integer; +var + RetVar : cardinal; + RContext : cardinal; + AnsiReader: AnsiString; + RStates : array[0..1] of SCARD_READERSTATEA; +begin + try + RContext := cardinal(PContext^); + FillChar(RStates,SizeOf(RStates),#0); + AnsiReader := AnsiString(SelectedReader); + RStates[0].szReader := 'ACS ACR122 0'; //PAnsichar(SelectedReader); + RStates[0].pvUserData := nil; + RStates[0].dwEventState := ActReaderState; + while ReaderOpen do + begin + RStates[0].dwCurrentState := RStates[0].dwEventState; + RetVar := SCardGetStatusChangeA(RContext, -1, RStates, 1); + ActReaderState := RStates[0].dwEventState; + PostMessage(NotifyHandle, WM_CARDSTATE, RetVar, 0); + end; + finally + Result := 0; + end; +end; + +procedure TPCSCConnector.MessageWndProc(var Msg: TMessage); +begin + if (Msg.Msg = WM_CARDSTATE) then + begin + if Msg.WParam <> SCARD_S_SUCCESS then + if Assigned(FOnError) then FOnError(Self, esGetStatus, Msg.WParam); + if ActReaderState <> LastReaderState then + begin + ProcessReaderState(LastReaderState, ActReaderState); + end; + end + else Msg.Result := DefWindowProc(NotifyHandle, Msg.Msg, Msg.WParam, Msg.LParam); +end; + +constructor TPCSCConnector.Create(AOwner: TComponent); +begin + inherited Create(AOwner); + FReaderList := TStringlist.Create; + FContext := 0; + FCardHandle := 0; + FNumReaders := 0; + FUseReaderNum := -1; + FConnected := false; + ActReaderState := SCARD_STATE_UNAWARE; + LastReaderState := SCARD_STATE_UNAWARE; + ReaderOpen := false; + ClearReaderAttributes; + ClearCardAttributes; + if not (csDesigning in ComponentState) then NotifyHandle := AllocateHWnd(MessageWndProc); +end; + +destructor TPCSCConnector.Destroy; +begin + CloseAndDisconnect; + SCardReleaseContext(FContext); + FReaderList.Free; + if not (csDesigning in ComponentState) then DeallocateHWnd(NotifyHandle); + inherited Destroy; +end; + +function TPCSCConnector.Init: boolean; +var + RetVar : cardinal; + ReaderList : string; + ReaderListSize : integer; + v : array[0..MAXIMUM_SMARTCARD_READERS] of string; + i : integer; + +begin + Result := false; + FNumReaders := 0; + CloseAndDisconnect; + if SCardIsValidContext(FContext) = SCARD_S_SUCCESS then SCardReleaseContext(FContext); + RetVar := SCardEstablishContext(SCARD_SCOPE_USER, nil, nil, @FContext); + if RetVar = SCARD_S_SUCCESS then + begin + ReaderListSize := 0; + RetVar := SCardListReadersW(FContext, nil, nil, ReaderListSize); + if RetVar = SCARD_S_SUCCESS then + begin + SetLength(ReaderList, ReaderListSize); + SCardListReadersW(FContext, nil, Pointer(ReaderList), ReaderListSize); + FReaderList.Clear; + SortOutSubstrings(ReaderList,v,[#0]); + for i := 0 to MAXIMUM_SMARTCARD_READERS do + if v[i] <> '' then FReaderList.Add(v[i]); + FNumReaders := FReaderList.Count; + if FNumReaders > 0 then + begin + if Assigned(FOnReaderListChange) then FOnReaderListChange(Self); + Result := true; + end; + end else if Assigned(FOnError) then FOnError(Self, esInit, RetVar); + end else if Assigned(FOnError) then FOnError(Self, esInit, RetVar); +end; + +function TPCSCConnector.Open: boolean; +var + ThreadID : LongWord; +begin + CloseAndDisconnect; + if (FUseReaderNum > NOREADERSELECTED) and + (SCardIsValidContext(FContext) = SCARD_S_SUCCESS) then + begin + ReaderOpen := true; + ActReaderState := SCARD_STATE_UNAWARE; + LastReaderState := SCARD_STATE_UNAWARE; + BeginThread(nil, 0, CardWatcherThread, @FContext, 0, ThreadID); + Result := true; + end else Result := false; +end; + +procedure TPCSCConnector.Close; +begin + ReaderOpen := false; + SCardCancel(FContext); + if FConnected then Disconnect; +end; + +function TPCSCConnector.Connect: boolean; +begin + if FConnected then Disconnect; + if FUseReaderNum > NOREADERSELECTED then + if ConnectSelectedReader then FConnected := true + else FConnected := false; + Result := FConnected; +end; + +procedure TPCSCConnector.Disconnect; +begin + if FConnected then + begin + SCardDisconnect(FCardHandle, SCARD_RESET_CARD); + FConnected := false; + FCardHandle := 0; + end; +end; + +procedure TPCSCConnector.CloseAndDisconnect; +begin + if FConnected then Disconnect; + if ReaderOpen then Close; +end; + +function TPCSCConnector.ConnectSelectedReader: boolean; +var + RetVar : cardinal; +begin + RetVar := SCardConnectW(FContext, + PWideChar(SelectedReader), + SCARD_SHARE_EXCLUSIVE, + SCARD_PROTOCOL_Tx, + FCardHandle, + @FAttrProtocol); + case RetVar of + SCARD_S_SUCCESS : begin + CardActiveAction; + Result := true; + end; + SCARD_W_REMOVED_CARD : begin + Result := true; + end; + else begin + Result := false; + if Assigned(FOnError) then FOnError(Self, esConnect, RetVar); + end; + end; +end; + +procedure TPCSCConnector.ProcessReaderState(const OldState,NewState: cardinal); +var + CardInOld, CardInNew : boolean; + ReaderEmOld, ReaderEmNew : boolean; + CardMuteOld, CardMuteNew : boolean; + CardIgnore : boolean; + +begin +CardInOld := (OldState and SCARD_STATE_PRESENT) > 0; +CardInNew := (NewState and SCARD_STATE_PRESENT) > 0; +ReaderEmOld := (OldState and SCARD_STATE_EMPTY) > 0; +ReaderEmNew := (NewState and SCARD_STATE_EMPTY) > 0; +CardMuteOld := (OldState and SCARD_STATE_MUTE) > 0; +CardMuteNew := (NewState and SCARD_STATE_MUTE) > 0; +CardIgnore := (NewState and SCARD_STATE_IGNORE) > 0; + +if CardMuteNew and + not CardMuteold then if Assigned(FOnCardInvalid) then FOnCardInvalid(Self); + +if CardInNew and + not CardInOld and + not CardMuteNew and + not CardIgnore then CardInsertedAction; + +if CardInOld and + not CardInNew then CardRemovedAction; + +if ReaderEmNew and + not ReaderEmOld then begin + if Assigned(FOnReaderWaiting) then FOnReaderWaiting(Self); + end; + +LastReaderState := NewState; +end; + +procedure TPCSCConnector.CardInsertedAction; +begin + if Assigned(FOnCardInserted) then FOnCardInserted(Self); + if FConnected then CardActiveAction; +end; + +procedure TPCSCConnector.CardActiveAction; +begin + GetReaderAttributes; + if FAttrProtocol <> SCARD_PROTOCOL_UNK then + begin + GetCardAttributes; + if Assigned(FOnCardActive) then FOnCardActive(Self); + end; +end; + +procedure TPCSCConnector.CardRemovedAction; +begin + ClearReaderAttributes; + ClearCardAttributes; + if Assigned(FOnCardRemoved) then FOnCardRemoved(Self); + Disconnect; +end; + +procedure TPCSCConnector.SetReaderNum(Value: Integer); +begin + if Value <> FUseReaderNum then + begin + CloseAndDisconnect; + if Value < FReaderList.Count then + begin + SelectedReader := PChar(FReaderList[Value]); + FUseReaderNum := Value; + end else + begin + SelectedReader := ''; + FUseReaderNum := -1; + end; + end; +end; + +function TPCSCConnector.IsReaderOpen: boolean; +begin + Result := ReaderOpen; +end; + +function TPCSCConnector.GetReaderState: cardinal; +begin + Result := ActReaderState; +end; + +procedure TPCSCConnector.GetReaderAttributes; +var + RetVar : cardinal; + ABuf : string; + AIBuf : integer; + ALen : integer; +begin + ABuf := StringOfChar(#0, 127); + ALen := Length(ABuf); + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_ATR_STRING, Pointer(ABuf), @ALen); + if RetVar = SCARD_S_SUCCESS then FAttrCardATR := Copy(ABuf, 1, ALen) + else FAttrCardATR := ''; + + ALen := Length(ABuf); + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_VENDOR_NAME, Pointer(ABuf), @ALen); + if RetVar = SCARD_S_SUCCESS then FAttrVendorName := Copy(ABuf, 1, ALen) + else FAttrVendorName := ''; + + ALen := Length(ABuf); + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_VENDOR_IFD_SERIAL_NO, Pointer(ABuf), @ALen); + if RetVar = SCARD_S_SUCCESS then FAttrVendorSerial := Copy(ABuf, 1, ALen) + else FAttrVendorSerial := ''; + + ALen := SizeOf(AIBuf); + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_CURRENT_PROTOCOL_TYPE, @AIBuf, @ALen); + if RetVar = SCARD_S_SUCCESS then FAttrProtocol := AIBuf + else FAttrProtocol := 0; + + ALen := SizeOf(AIBuf); + AIBuf := 0; + RetVar := SCardGetAttrib(FCardHandle, SCARD_ATTR_ICC_TYPE_PER_ATR, @AIBuf, @ALen); + if RetVar = SCARD_S_SUCCESS then begin + case AIBuf of + 1 : FAttrICCType := 'ISO7816A'; + 2 : FAttrICCType := 'ISO7816S'; + else FAttrICCType := 'UNKNOWN'; + end; + end + else FAttrICCType := ''; +end; + +procedure TPCSCConnector.GetCardAttributes; +begin +if GSMSelect(DFgsm900) = GSMStatusOK then + begin + FGSMVoltage30 := (OrdD(FGSMDirInfo, 14) and $10) > 0; + FGSMVoltage18 := (OrdD(FGSMDirInfo, 14) and $20) > 0; + end; +end; + +procedure TPCSCConnector.ClearReaderAttributes; +begin + FAttrCardATR := ''; + FAttrVendorName := ''; + FAttrVendorSerial := ''; + FAttrProtocol := 0; + FAttrICCType := ''; +end; + +procedure TPCSCConnector.ClearCardAttributes; +begin + FGSMCurrentFile := ''; + FGSMFileInfo := ''; + FGSMDirInfo := ''; + FGSMVoltage30 := false; + FGSMVoltage18 := false; +end; + +function TPCSCConnector.GetResponseFromCard(const APdu: string): string; +var + RetVar : cardinal; + SBuf : string; + SLen : cardinal; + RBuf : string; + RLen : cardinal; + Ppci : Pointer; +begin +SBuf := APdu; +RBuf := StringOfChar(#0,MAXAPDULENGTH); +if Length(SBuf) <= MAXAPDULENGTH then + begin + case FAttrProtocol of + SCARD_PROTOCOL_T0 : Ppci := @SCARD_PCI_T0; + SCARD_PROTOCOL_T1 : Ppci := @SCARD_PCI_T1; + else Ppci := nil; + end; + SLen := Length(APdu); + RLen := Length(RBuf); + RetVar := SCardTransmit(FCardHandle, Ppci, Pointer(SBuf), SLen, nil, Pointer(RBuf), @RLen); + if RetVar = SCARD_S_SUCCESS then + begin + Result := Copy(RBuf,1,RLen); + end else + begin + Result := ''; + if Assigned(FOnError) then FOnError(Self, esTransmit, RetVar); + end; + end; +end; + +function TPCSCConnector.GetResponseFromCard(const Command: string; var Data: string; var sw1, sw2: byte): boolean; +var + Answer : string; + AnswerL : integer; +begin +Answer := GetResponseFromCard(Command + Data); +AnswerL := Length(Answer); +if AnswerL >= 2 then + begin + Data := Copy(Answer, 1, AnswerL - 2); + sw1 := Ord(Answer[AnswerL - 1]); + sw2 := Ord(Answer[AnswerL]); + if sw1 = GSMStatusResponseData then + begin + Data := Chr(sw2); + if not GetResponseFromCard(GCGetResponse, Data, sw1, sw2) then + begin + Data := ''; + sw1 := 0; + sw2 := 0; + Result := false; + end else Result := true; + end else Result := true; + end else + begin + Data := ''; + sw1 := 0; + sw2 := 0; + Result := false; + end; +end; + +function TPCSCConnector.GSMStatus: integer; +var + Answer : string; + sw1, sw2 : byte; +begin + GetResponseFromCard(GCGetStatus, Answer, sw1, sw2); + Result := (sw1 shl 8) + sw2; + if Result = GSMStatusOK then + begin + FGSMDirInfo := Answer; + FGSMCurrentFile := Copy(Answer, 5, 2); + end else + begin + FGSMDirInfo := ''; + end; +end; + +function TPCSCConnector.GSMSelect(const FileID: string): integer; +var + Answer : string; + sw1, sw2 : byte; +begin + Answer := FileID; + GetResponseFromCard(GCSelectFile, Answer, sw1, sw2); + Result := (sw1 shl 8) + sw2; + if Result = GSMStatusOK then + begin + FGSMCurrentFile := Copy(Answer, 5, 2); + if OrdD(Answer, 7) = GSMFileTypeEF then + begin + FGSMFileInfo := Answer; + end else + begin + FGSMDirInfo := Answer; + end; + end; +end; + +function TPCSCConnector.GSMReadBinary(const Offset, Length: integer; var Data: string): integer; +var + Command : string; + sw1, sw2 : byte; +begin + Command := GCReadBinary + Chr(Offset div 256) + Chr(Offset mod 256) + Chr(Length mod 256); + GetResponseFromCard(Command, Data, sw1, sw2); + Result := (sw1 shl 8) + sw2; + if Result = GSMStatusOK then + begin + end; +end; + +end. + diff --git a/__history/PCSCConnectorD2007.dpk.~1~ b/__history/PCSCConnectorD2007.dpk.~1~ new file mode 100644 index 0000000..484f4e1 --- /dev/null +++ b/__history/PCSCConnectorD2007.dpk.~1~ @@ -0,0 +1,36 @@ +package PCSCConnectorD2007; + +{$R *.res} +{$R 'PCSCConnector.dcr'} +{$ALIGN 8} +{$ASSERTIONS ON} +{$BOOLEVAL OFF} +{$DEBUGINFO ON} +{$EXTENDEDSYNTAX ON} +{$IMPORTEDDATA ON} +{$IOCHECKS ON} +{$LOCALSYMBOLS ON} +{$LONGSTRINGS ON} +{$OPENSTRINGS ON} +{$OPTIMIZATION ON} +{$OVERFLOWCHECKS OFF} +{$RANGECHECKS OFF} +{$REFERENCEINFO ON} +{$SAFEDIVIDE OFF} +{$STACKFRAMES OFF} +{$TYPEDADDRESS OFF} +{$VARSTRINGCHECKS ON} +{$WRITEABLECONST OFF} +{$MINENUMSIZE 1} +{$IMAGEBASE $400000} +{$DESCRIPTION 'PCSC SmartCard Component D2007'} +{$IMPLICITBUILD ON} + +requires + rtl, + vcl; + +contains + PCSCConnector in 'PCSCConnector.pas'; + +end.