Delphi XE5 で、FeliCa IDm を読む
下のサンプルコードで、 nanaco カード、ENEOS カード の IDm (カードごとに違う製造ID) が読めました。
Amazon などで、無地のカードが購入できますので、何かに使えそうです。
カードのリーダ/ライタは、デバイスマネージャーでは、「近接通信デバイス」 として認識されます。
※最近のノートパソコンでは、標準で、FeliCa ポート がついているものがあります。

■スクリーンショット
接続されているリード/ライタは、内蔵と外付けのもの、2個認識されています。

■ソースコード
※株式会社ソフテック様 「非接触ICカード技術"FeliCa(フェリカ)"のIDm読み取り方法」を、ほぼそのまま、Delphi に書き換えています。感謝!
※WinSCard.pas は、こちら
unit Unit3;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm3 = class(TForm)
Button1: TButton;
Edit1: TEdit;
Edit2: TEdit;
Edit3: TEdit;
Memo1: TMemo;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form3: TForm3;
implementation
{$R *.dfm}
// WinSCard.pas(Copyright (C) 1996 Microsoft Corporation.)が必要
uses WinSCard;
// PC/SC(Personal Computer / Smart Card)インターフェイス規格
// 参照:EternalWindows http://eternalwindows.jp/security/scard/scard00.html
// 情報元:株式会社ソフテック http://www.softech.co.jp/mm_140205_pc.htm
// FeliCa 製造ID(IDm)読み取り
procedure TForm3.Button1Click(Sender: TObject);
const
SCARD_S_SUCCESS = 0;
SCARD_PROTOCOL_T0 = $0001;
SCARD_PROTOCOL_T1 = $0002;
var
hContext: LongInt;
hCard : LongInt;
ActiveProtocol : DWORD;
AutoAllocate : LongInt;
lResult : LongInt;
ReaderLen : LongInt;
State : LongInt;
AtrLen : LongInt;
Atr : array[0..63] of BYTE;
SendCommand : array [0..4] of BYTE;
RecvBuffer : array [0..255] of BYTE;
ResponseSize : DWORD;
ReaderName :array [0..255] of WideChar;
i, j : integer;
s : string;
sl : TStringList;
begin
Edit1.Text := '';
Edit2.Text := '';
Edit3.Text := '';
Memo1.Lines.Clear;
// 送信コマンド
// カードのIDmを取得するためのGetDataコマンド
SendCommand[0] := $FF;
SendCommand[1] := $CA;
SendCommand[2] := $00;
SendCommand[3] := $00;
SendCommand[4] := $00;
ReaderLen := sizeof( ReaderName );
ResponseSize := sizeof(RecvBuffer);
// リソースマネージャ(Smart Card Resouce Manager)に接続し、ハンドルを取得
lResult := SCardEstablishContext( SCARD_SCOPE_USER, nil, nil, @hContext );
if lResult = SCARD_S_SUCCESS then begin
// リソースマネージャのハンドル
Edit1.Text := IntToHex(hContext, 8);
// 配列を初期化
FillMemory(@ReaderName, SizeOf(ReaderName), 0);
// PCに接続されているPC/SC対応のリーダ/ライタの一覧を取得
// リーダー/ライターの名称を取得
// この名称は、カードに接続する関数を呼び出す場合に必要
// mszGroups : nil = SCARD_ALL_READERS と同じ
lResult := SCardListReadersW( hContext, SCARD_ALL_READERS{ nil}, @ReaderName, AutoAllocate);
if lResult = SCARD_S_SUCCESS then begin
sl := TStringList.Create;
try
// FeliCa ポートがあるパソコンのため
// 複数接続されているリーダ/ライタの名称を切り分け
s := '';
for i := 0 to Length(ReaderName) -2 do begin
if (ReaderName[i] <> #00) then s := s + ReaderName[i]
else begin
sl.Add(s);
if (ReaderName[i+1] <> #00) then s := ''
else break;
end;
end;
// 接続されているリーダ/ライタの名称を表示
Memo1.Lines.Assign(sl);
if sl.Count > 0 then begin
for i := 0 to sl.Count -1 do begin
for j := 0 to Length(sl[i]) - 1 do ReaderName[j] := sl[i][j+1];
ReaderName[Length(sl[i])] := #00;
// リーダ/ライタの名称
Edit2.Text := String(ReaderName);
// リーダ/ライタに接続されたカードに接続
lResult := SCardConnectW( hContext, @ReaderName, SCARD_SHARE_SHARED,
SCARD_PROTOCOL_T0 or SCARD_PROTOCOL_T1, hCard, @ActiveProtocol );
if lResult = SCARD_S_SUCCESS then begin
// カードの状態、プロトコル、ATRを取得
lResult := SCardStatusW( hCard, nil, ReaderLen, State, @ActiveProtocol, nil, AtrLen);
if lResult = SCARD_S_SUCCESS then begin
lResult := SCardStatusW( hCard, ReaderName, ReaderLen, State, @ActiveProtocol, @Atr, AtrLen);
if lResult = SCARD_S_SUCCESS then begin
// FeliCaカードであるかの判断
if( Atr[13] = $00) and (Atr[14] = $3B ) then begin
// カードにコマンドを送信し、データを受信
// 送信コマンド:APDU(Application Protocol Data Unit)と呼ばれるバイナリデータ
lResult := SCardTransmit( hCard, nil , @SendCommand, sizeof(SendCommand), nil,
@RecvBuffer, @ResponseSize );
if (lResult = SCARD_S_SUCCESS ) then begin
s := '';
// 8バイトのバイト列(製造者コード:2バイト + カード識別番号:6バイト)
for j := 0 to ResponseSize - 3 do s := s + IntToHex(RecvBuffer[j], 2) + ' ';
// カードの製造ID(IDm)
Edit3.Text := s;
Break;
end;
end;
end;
end;
end;
// カードとの通信を切断
SCardDisconnect( hCard, SCARD_LEAVE_CARD );
end;
end;
finally
sl.Free;
end;
end;
end;
// リソースマネージャを解放
SCardReleaseContext( hContext );
end;
end.