⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pcscconnector.pas

📁 Delphi 用的PSCS控件即例子程序,本人稍作修改了例子程序
💻 PAS
📖 第 1 页 / 共 2 页
字号:
{******************************************************************}
{                                                                  }
{ 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 := SCardListReadersA(FContext, nil, nil, ReaderListSize);
    if RetVar = SCARD_S_SUCCESS then
      begin
      SetLength(ReaderList, ReaderListSize);
      SCardListReadersA(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);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -