ここのところ忙しくて中々ブログを更新することが出来ず。週末もちょっと部屋の模様替えなど、ゆっくりできませんでした。USB HIDデバイスにアクセスする為の何か汎用的なクラスを作るかな、と書いてしまったので、早速。
仕事でいろいろなコードを書いてきているのですが、USBデバイスを直接制御することについては経験がありません。ま、他のシステムデバイスと同じような感じで良いのかな、と調べ始めたところ、やはり同じような作法でいけそうです。エンドポイント、パイプなど細かいところはOSやってくれます。アプリを書く上で、恐らくUSBデバイスの接続、切り離しの検知、データの送受信(Report)が基本動作になるのかなと思います。
デバイスの検知については、Win32 Native Codeであれば、Windowのメッセージループの中でWM_DEVICECHANGEを受け取る事ができますが、マネージド・コードではそもそもメッセージループという考え方が表向きには無いので、似たことをするコードを書かなくてはなりません。具体的には、WM_DEVICECHANGEというメッセージが送られてきたら、デバイスが接続されたのか、切り離されたのかを確認します。そして、そのデバイスのベンダーIDとプロダクトIDから、対象としているデバイスかどうかを確認します。対象としているデバイスである場合は、必要な処理を行います。
では、どうやってメッセージを受け取るのかというと、FormなどのクラスにはWndProc(ref Message)という継承可能なメソッドを定義されています。これをoverrideし、必要な処理を行います。例えばこのような感じです。
Visual Studioのメニューから「File」→ 「New」 → 「Project」を選択し、「Windows Forms Application」を選択します。
すいません。私は普段英語版しか使わないので、スクリーンショットも英語です。
プロジェクトが作成された、フォームのコードに以下を追加します。HIDデバイスを接続、切り離しをする度に、この関数が呼び出されることが確認できます。
public void ParseMessages(ref Message msg)
{
if (msg.Msg == Win32Stub.WM_DEVICECHANGE)
{
switch (msg.WParam.ToInt32())
{
case Win32Stub.DBT_DEVICEARRIVAL:
if (OnDeviceArrived != null)
{
OnDeviceArrived(this, new EventArgs());
CheckDevicePresent();
}
break;
case Win32Stub.DBT_DEVICEREMOVECOMPLETE:
if (OnDeviceRemoved != null)
{
OnDeviceRemoved(this, new EventArgs());
CheckDevicePresent();
}
break;
}
}
}
(OnDeviceRemoved(), OnDeviceArrived()は独自に定義しているイベントです。全てのソースは最後に公開します。って、まだ全部書いていなので)
サポートしているデバイスが接続された場合、自動的に接続し通信を開始する必要がある場合などは、DBT_DEVICEARRIVALを処理する中で対象デバイスの確認、及び接続(CreateFileを使用)処理を行います。
次回は、システム上に登録されているデバイスの検知方法について見ていきたいと思います。