私の勤務先は職員証がFelicaカードになっています。この職員証を使用し,勤怠打刻や各ゲートの入退管理をしています。
たまたま,Sony製FelicaリーダーのパソリPC-S300が手元に余っていたので,この職員証の情報を記録するような仕組みを作れないと思い試作しました。
目次
コード本体
VBAで作成しています。Windows標準APIを使用するため,新しく何かをインストールする必要がありません。
Option Explicit
' *********************
' API宣言
' *********************
Private Declare PtrSafe Function SCardEstablishContext Lib "winscard.dll" ( _
ByVal dwScope As Long, _
ByVal pvReserved1 As Long, _
ByVal pvReserved2 As Long, _
ByRef phContext As LongPtr) As LongPtr
Private Declare PtrSafe Function SCardListReaders Lib "winscard.dll" Alias "SCardListReadersA" ( _
ByVal hContext As LongPtr, _
ByVal mzGroup As String, _
ByVal ReaderList As String, _
ByRef pcchReaders As Long) As LongPtr
Private Declare PtrSafe Function SCardConnectA Lib "winscard.dll" ( _
ByVal hContext As LongPtr, _
ByVal szReaderName As String, _
ByVal dwShareMode As Long, _
ByVal dwPrefProtocol As Long, _
ByRef hCard As LongPtr, _
ByRef activeProtocol As Long) As LongPtr
Private Declare PtrSafe Function SCardTransmit Lib "winscard.dll" ( _
ByVal hCard As LongPtr, _
ByRef pioSendRequest As Any, _
ByRef sendbuff As Byte, _
ByVal SendBuffLen As Long, _
ByRef pioRecvRequest As Any, _
ByRef RecvBuff As Byte, _
ByRef RecvBuffLen As Long) As LongPtr
Private Declare PtrSafe Function SCardDisconnect Lib "winscard.dll" ( _
ByVal hCard As LongPtr, _
ByVal Disposition As Long) As LongPtr
Private Declare PtrSafe Function SCardReleaseContext Lib "winscard.dll" ( _
ByVal hContext As LongPtr) As LongPtr
' *********************
' 定数の定義
' *********************
Private Const SCARD_SCOPE_USER As Long = 0
Private Const SCARD_SHARE_SHARED As Long = 2
Private Const SCARD_PROTOCOL_T1 As Long = 2
Private Const SCARD_LEAVE_CARD As Long = 0
Private Const MAX_READER_NAME As Long = 256
Private Const MAX_RECEIVE_BUFFER As Long = 255
' *********************
' エラーメッセージの定義
' *********************
Private Const ERR_INIT_FAILED As String = "ERROR:初期化処理に失敗しました。"
Private Const ERR_NO_READER As String = "ERROR:カードリーダが見つかりません。"
Private Const ERR_NO_CARD As String = "ERROR:正しいカードをセットしてください。"
Private Const ERR_TRANSMIT As String = "ERROR:ID取得エラー(Transmit:{0})"
Private Const ERR_READ_ABNORMAL As String = "ERROR:ID取得エラー(読込異常:{0},{1})"
Private Const ERR_DISCONNECT As String = "ERROR:切断エラー {0}"
' *********************
' 関数本体
' *********************
Public Function ReadUID() As String
Dim hContext As LongPtr
Dim readerName As String
Dim result As String
' コンテキストを確立
result = EstablishContext(hContext)
If Left(result, 5) = "ERROR" Then
ReadUID = result
Exit Function
End If
' カードリーダーを取得
result = GetReader(hContext, readerName)
If Left(result, 5) = "ERROR" Then
ReadUID = result
Exit Function
End If
' カードに接続してUIDを読み取る
result = ConnectAndReadCard(hContext, readerName)
' コンテキストを解放
Call SCardReleaseContext(hContext)
ReadUID = result
End Function
Private Function EstablishContext(ByRef hContext As LongPtr) As String
Dim ret As LongPtr
ret = SCardEstablishContext(SCARD_SCOPE_USER, 0, 0, hContext)
If ret <> 0 Then
EstablishContext = ERR_INIT_FAILED
Else
EstablishContext = "SUCCESS"
End If
End Function
Private Function GetReader(ByVal hContext As LongPtr, ByRef readerName As String) As String
Dim ret As LongPtr
Dim pcchReaders As Long
Dim mszReaders As String
Dim readerArray() As String
pcchReaders = MAX_READER_NAME
' リーダー名称取得
mszReaders = String$(pcchReaders, vbNullChar)
ret = SCardListReaders(hContext, vbNullString, mszReaders, pcchReaders)
If ret <> 0 Then
GetReader = ERR_NO_READER
Exit Function
End If
readerArray = Split(mszReaders, vbNullChar)
readerName = readerArray(0)
GetReader = "SUCCESS"
End Function
Private Function ConnectAndReadCard(ByVal hContext As LongPtr, ByVal readerName As String) As String
Dim hCard As LongPtr
Dim activeProtocol As Long
Dim ret As LongPtr
Dim sendBuffer(4) As Byte
Dim recvBuffer(MAX_RECEIVE_BUFFER - 1) As Byte
Dim recvLen As Long
Dim i As Long
Dim cardData As String
' カード接続
ret = SCardConnectA(hContext, readerName, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T1, hCard, activeProtocol)
If ret <> 0 Then
ConnectAndReadCard = ERR_NO_CARD
Exit Function
End If
' 送信バッファ設定
sendBuffer(0) = &HFF: sendBuffer(1) = &HCA: sendBuffer(2) = &H0: sendBuffer(3) = &H0: sendBuffer(4) = &H0
' データ受信
recvLen = MAX_RECEIVE_BUFFER
ret = SCardTransmit(hCard, ByVal 0&, sendBuffer(0), 5, ByVal 0&, recvBuffer(0), recvLen)
If ret <> 0 Then
ConnectAndReadCard = Replace(ERR_TRANSMIT, "{0}", Hex(ret))
GoTo DisconnectCard
End If
' データチェック
If recvBuffer(recvLen - 2) <> &H90 Then
ConnectAndReadCard = Replace(Replace(ERR_READ_ABNORMAL, "{0}", Hex(recvBuffer(0))), "{1}", Hex(recvBuffer(1)))
GoTo DisconnectCard
End If
' UIDの取得
cardData = ""
For i = 0 To 7
If Chr(recvBuffer(i)) <> Space(1) Then
cardData = cardData & Right("0" & Hex(recvBuffer(i)), 2)
End If
Next i
ConnectAndReadCard = cardData
DisconnectCard:
' カード切断
ret = SCardDisconnect(hCard, SCARD_LEAVE_CARD)
If ret <> 0 Then
ConnectAndReadCard = Replace(ERR_DISCONNECT, "{0}", Hex(ret))
End If
End Function
コメント
コメント一覧 (3件)
管理人様。
初めてご連絡させていただきます。株式会社TKアジャイルの高柳と申します。
最近、ディープAIを調査しておりまして、たまたま当社ブログで公開しているコードをAIで盗用チェック確認したところ、貴サイトがヒットしましたので、念のためご連絡させていただいた次第です。
もちろん、AIの盗用チェックが100%とは思っておりませんし、当社サイトの内容と貴社サイトの内容が100%一致していないことも承知しています。(パッとみた感じでは、学生レベルでも可能な書き換え内容のようには見えますが。。。)
つきましては、本記事につきまして、もし仮に当社記事をインスパイアされたのであれば、その旨を明記していただくか、あるいは当該記事の非公開をご検討いただけないでしょうか?
HP等をご覧になればお分かりかと思いますが、当社ではエクセル関連事業を本業(ビジネス)として展開しておりますので、管理人さまのご対応によりましては、当社コンプライアンス規定に基づき、発信者開示・内容証明郵便送付の処置を行った上、改善がない場合は法的処理の検討となりますことをあらかじめご理解ください。(当社は穏便解決を望んでおります。念のため)
以上、善処のご検討をお願いします
株式会社TKアジャイル
高柳様
コメントいただきありがとうございます。
ご連絡いただきました件、拝見いたしました。
まず初めに、当方では当該記事の作成にあたり、複数の公開情報を参考にしながら独自に検討・実装を行っており、ご指摘の貴社記事のみを特段参照したものではないことを申し添えます。
また、当該記事におけるコード記述、機能実装、エラーハンドリング、全体構成等において、貴社記事と明確な相違点が存在することも確認しております。
具体的には、以下の点が異なっております。
・当方記事では、各API呼び出し(SCardEstablishContext、SCardConnect等)を個別関数化し、モジュール分割と再利用性を重視した設計を行っている
・エラー発生時の処理について、エラーコードに応じたメッセージの詳細分岐を追加している
・送信・受信バッファの処理手順について、別途ラップ関数化することで汎用性を向上させている
・コードコメントおよびロジック説明を、オリジナルの記述で行っている
・UID抽出処理においても、異なる変数管理手法(カードデータ文字列生成ロジックの違い)を採用している
これらの違いから、当方記事は独自に創作されたものであり、著作権法上保護されるべき「独自の表現」を不正に利用したものではないと認識しております。
もっとも、当方記事の作成過程において貴社記事の内容も参考にさせていただいております。
その点につきましては、発信者様へのリスペクトが十分でなかったことを反省しております。
したがいまして、当方記事内に、貴社サイトを参考にした旨の明記を加える対応をさせていただきたく存じます。
ご対応ありがとうございました