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
-
-
-
-
-
-
-
\ 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
+
+
+
+
+
+ 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.