Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
KANSoftWare

Обнаружение нового NFC-токена с использованием WinAPI в Delphi

Delphi , ОС и Железо , Windows

 

В этой статье мы рассмотрим, как обнаруживать появление нового NFC-токена с использованием WinAPI в Delphi. Проблема заключается в том, что стандартные события, такие как SCardAccessStartedEvent и WM_DEVICECHANGE, не всегда работают корректно для обнаружения новых NFC-токенов. В этой статье мы рассмотрим возможные решения и предложим альтернативные подходы для улучшения обнаружения новых NFC-токенов.

Введение

NFC (Near Field Communication) — это технология беспроводной связи, которая используется для обмена данными между устройствами на небольшом расстоянии. В Delphi можно использовать WinAPI для взаимодействия с NFC-устройствами и токенами. Однако стандартные события, такие как SCardAccessStartedEvent и WM_DEVICECHANGE, не всегда корректно обнаруживают появление нового NFC-токена.

Стандартные события и их недостатки

SCardAccessStartedEvent

SCardAccessStartedEvent — это событие, которое используется для обнаружения начала доступа к NFC-токену. Однако, как указано в вопросе, это событие срабатывает дважды, но не всегда корректно обнаруживает появление нового NFC-токена.

constructor TEventThread.Create;
begin
  inherited Create(True);
  FEventHandle := SCardAccessStartedEvent;
  if FEventHandle = 0 then
    raise Exception.Create('Failed to access started event');
  FreeOnTerminate := True;
end;

WM_DEVICECHANGE

WM_DEVICECHANGE — это событие, которое используется для обнаружения изменений в подключенных устройствах. Однако, как указано в вопросе, это событие срабатывает с wParam=7, что соответствует DBT_DEVNODES_CHANGED, а не DBT_DEVICEARRIVAL или DBT_DEVICEREMOVECOMPLETE. В этом случае, информация о добавленном или удаленном устройстве не предоставляется, и вам нужно самостоятельно сканировать устройства, чтобы определить изменения.

procedure TMainF.WMDeviceChange(var Msg: TMessage);
begin
  case Msg.WParam of
    DBT_DEVICEARRIVAL:
      MOutput.Lines.Add('Device arrived');
    DBT_DEVICEREMOVECOMPLETE:
      MOutput.Lines.Add('Device removed');
  end;
end;

Решение проблемы

Для улучшения обнаружения нового NFC-токена можно использовать комбинацию событий и дополнительных проверок. Мы можем использовать WM_DEVICECHANGE для обнаружения изменений в подключенных устройствах и затем сканировать устройства для определения появления нового NFC-токена.

Обновленный код для обнаружения нового NFC-токена

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls,
  WinSCard, SCardErr, WinSmCrd;

type
  TEventThread = class(TThread)
  private
    FEventHandle: THandle;
    FLastDeviceCount: Integer;
  protected
    procedure Execute; override;
  public
    constructor Create;
    destructor Destroy; override;
  end;

  TMainF = class(TForm)
    BReadManually: TButton;
    MOutput: TMemo;
    BStartEventThread: TButton;
    PButtons: TPanel;
    procedure BReadManuallyClick(Sender: TObject);
    procedure BStartEventThreadClick(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure WMDeviceChange(var Msg: TMessage); message WM_DEVICECHANGE;
  private
    { Private declarations }
    eventthread: TEventThread;
  public
    { Public declarations }
  end;

var
  MainF: TMainF;

implementation

const
  DBT_DEVICEARRIVAL                = $8000;  // system detected a new device
  DBT_DEVICEQUERYREMOVE            = $8001;  // wants to remove, may fail
  DBT_DEVICEQUERYREMOVEFAILED      = $8002;  // removal aborted
  DBT_DEVICEREMOVEPENDING          = $8003;  // about to remove, still avail.
  DBT_DEVICEREMOVECOMPLETE         = $8004;  // device is gone
  DBT_DEVICETYPESPECIFIC           = $8005;  // type specific event
  DBT_CUSTOMEVENT                  = $8006;  // user-defined event

procedure TMainF.BReadManuallyClick(Sender: TObject);
var
  scc: SCardContext;
  readers, debug: integer;
  name: array of WideChar;
  cardhandle: SCardHandle;
  activeprotocol: DWORD;
  request: WinSCard.PSCARD_IO_REQUEST;
  cmdread: array[0..4] of Byte;
  recvbuff: array[0..511] of Byte;
begin
  if (SCardEstablishContext(SCARD_SCOPE_SYSTEM, nil, nil, @scc) <> SCARD_S_SUCCESS) then
    RaiseLastOSError;
  if (SCardListReadersW(scc, nil, nil, readers) <> SCARD_S_SUCCESS) then
    RaiseLastOSError;
  SetLength(name, readers);
  if SCardListReadersW(scc, nil, PWideChar(name), readers) <> SCARD_S_SUCCESS then
    RaiseLastOSError;
  debug := SCardConnectW(scc, PWideChar(name), SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 OR SCARD_PROTOCOL_T1, cardhandle, @activeprotocol);
  if (debug <> SCARD_SUCCESS) then
    RaiseLastOSError
  else begin
    request := Getg_rgSCard(activeprotocol);

    cmdread[0] := $00;
    cmdread[1] := $00;
    cmdread[2] := $00;
    cmdread[3] := $00;
    cmdread[4] := $00;
    try
      if (SCardTransmit(cardhandle, request, PByte(@cmdread[0]), SizeOf(cmdread), nil, PByte(@recvbuff[0]), @recvbuff) <> SCARD_S_SUCCESS) then
        RaiseLastOSError;
    finally
      SCardDisconnect(cardhandle, SCARD_LEAVE_CARD);
    end;
  end;
end;

procedure TMainF.BStartEventThreadClick(Sender: TObject);
begin
  eventthread := TEventThread.Create;
  eventthread.Start;
end;

procedure TMainF.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  eventthread.Terminate;
  CanClose := eventthread.Terminated;
end;

procedure TMainF.WMDeviceChange(var Msg: TMessage);
begin
  case Msg.WParam of
    DBT_DEVICEARRIVAL:
      MOutput.Lines.Add('Device arrived');
    DBT_DEVICEREMOVECOMPLETE:
      MOutput.Lines.Add('Device removed');
  end;
  eventthread.ScanDevices;
end;

{ TEventThread }

constructor TEventThread.Create;
begin
  inherited Create(True);
  FEventHandle := SCardAccessStartedEvent;
  if FEventHandle = 0 then
    raise Exception.Create('Failed to access started event');
  FreeOnTerminate := True;
  FLastDeviceCount := 0;
end;

destructor TEventThread.Destroy;
begin
  inherited Destroy;
end;

procedure TEventThread.Execute;
begin
  while not Terminated do
  begin
    if WaitForSingleObject(FEventHandle, INFINITE) = WAIT_OBJECT_0 then
    begin
      Synchronize(procedure
      begin
        ShowMessage('Event occurred!');
      end);
      SCardReleaseStartedEvent;
    end;
  end;
end;

procedure TEventThread.ScanDevices;
var
  scc: SCardContext;
  readers, debug: integer;
  name: array of WideChar;
  i: Integer;
begin
  if SCardEstablishContext(SCARD_SCOPE_SYSTEM, nil, nil, @scc) <> SCARD_S_SUCCESS then
    Exit;
  try
    if SCardListReadersW(scc, nil, nil, readers) <> SCARD_S_SUCCESS then
      Exit;
    SetLength(name, readers);
    if SCardListReadersW(scc, nil, PWideChar(name), readers) <> SCARD_S_SUCCESS then
      Exit;

    if readers > FLastDeviceCount then
    begin
      for i := FLastDeviceCount + 1 to readers do
      begin
        MOutput.Lines.Add('New NFC token detected: ' + name[i - 1]);
      end;
    end;

    FLastDeviceCount := readers;
  finally
    SCardReleaseContext(scc);
  end;
end;

Обновленный код для обнаружения нового NFC-токена

В этом примере мы добавили метод ScanDevices в класс TEventThread, который сканирует подключенные устройства и проверяет, появилось ли новое NFC-токен. Если появилось, он выводит сообщение о новом NFC-токене.

procedure TEventThread.ScanDevices;
var
  scc: SCardContext;
  readers, debug: integer;
  name: array of WideChar;
  i: Integer;
begin
  if SCardEstablishContext(SCARD_SCOPE_SYSTEM, nil, nil, @scc) <> SCARD_S_SUCCESS then
    Exit;
  try
    if SCardListReadersW(scc, nil, nil, readers) <> SCARD_S_SUCCESS then
      Exit;
    SetLength(name, readers);
    if SCardListReadersW(scc, nil, PWideChar(name), readers) <> SCARD_S_SUCCESS then
      Exit;

    if readers > FLastDeviceCount then
    begin
      for i := FLastDeviceCount + 1 to readers do
      begin
        MOutput.Lines.Add('New NFC token detected: ' + name[i - 1]);
      end;
    end;

    FLastDeviceCount := readers;
  finally
    SCardReleaseContext(scc);
  end;
end;

Запуск сканирования при изменении устройств

Мы также обновили обработчик WM_DEVICECHANGE, чтобы вызывать метод ScanDevices при обнаружении изменений в подключенных устройствах.

procedure TMainF.WMDeviceChange(var Msg: TMessage);
begin
  case Msg.WParam of
    DBT_DEVICEARRIVAL:
      MOutput.Lines.Add('Device arrived');
    DBT_DEVICEREMOVECOMPLETE:
      MOutput.Lines.Add('Device removed');
  end;
  eventthread.ScanDevices;
end;

Альтернативные подходы

Использование SCardGetStatusChange

Вместо использования SCardAccessStartedEvent и WM_DEVICECHANGE, можно использовать SCardGetStatusChange, который позволяет получать обновления состояния устройств. Этот подход может быть более надежным для обнаружения новых NFC-токенов.

procedure TEventThread.Execute;
var
  statusChange: TSCardStatus;
  statusChangeCount: DWORD;
  i: Integer;
begin
  while not Terminated do
  begin
    statusChangeCount := 0;
    if SCardGetStatusChange(FEventHandle, INFINITE, @statusChange, 1, @statusChangeCount) = SCARD_S_SUCCESS then
    begin
      for i := 0 to statusChangeCount - 1 do
      begin
        if (statusChange[i].dwEventMask and SCARD_STATE_PRESENT) <> 0 then
        begin
          Synchronize(procedure
          begin
            MOutput.Lines.Add('New NFC token detected: ' + statusChange[i].szReader);
          end);
        end;
      end;
    end;
  end;
end;

Использование SCardGetStatusChange с периодическим сканированием

Если SCardGetStatusChange не работает корректно, можно использовать периодическое сканирование устройств с использованием таймера.

procedure TEventThread.Execute;
begin
  while not Terminated do
  begin
    Sleep(1000);
    ScanDevices;
  end;
end;

Заключение

В этой статье мы рассмотрели проблему обнаружения нового NFC-токена с использованием WinAPI в Delphi и предложили несколько решений. Мы обновили код для обнаружения нового NFC-токена, используя комбинацию событий и дополнительных проверок. Также мы рассмотрели альтернативные подходы, такие как использование SCardGetStatusChange и периодического сканирования устройств. Эти решения могут помочь улучшить обнаружение новых NFC-токенов в вашем приложении.

Создано по материалам из источника по ссылке.

Статья описывает способы обнаружения новых NFC-токенов с использованием WinAPI в Delphi, рассматривая недостатки стандартных событий и предлагая альтернативные подходы для улучшения процесса обнаружения.


Комментарии и вопросы

Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.


:: Главная :: Windows ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-12-22 20:14:06
2025-06-16 16:28:26/0.0056681632995605/1