はじめに
今回の記事は、WpfでシリアルポートにUSBデバイスを抜き差しした際にプログラムで検出する方法についてです。
例えば、良く利用されるものを挙げるのであればUSBメモリ、USBカメラがあります。
以下ではシリアルポートにUSBメモリを抜き差しを行った時に検出出来るプログラムを作成します。
使うのは、Windowプロシージャです。
Windowプロシージャとは?
Windowsでは、利用しているアプリケーションにWindowsから送信されたメッセージを処理する関数のことをWindowプロシージャと言います。
C#の場合にWindowプロシージャを利用する関数
protected IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
引数は4つです。
・hwndはWindowへのハンドル
・msgはメッセージコード
・wParamとIParamには、メッセージに関連する追加データが格納
上記の引数に含まれるメッセージコードを確認します。
シリアルポートでデバイスの抜き差しが行われると、ここにメッセージコードがセットされます。
Windowプロシージャの使い方
一般的な利用方法は、第2引数メッセージコードをswitch文を使用してメッセージ毎に処理を分岐するように利用します。
switch (msg)
{
case XXX: // 任意のメッセージ
// etc
}
参考にしたサイト
ウィンドウ プロシージャの記述 - Win32 apps
ウィンドウ プロシージャの記述
WpfでWindowプロシージャをフックする方法
フックとは、メッセージやマウスアクションなどのイベントをアプリケーションがインターセプトできるメカニズムのこと。
フックの概要-MSDM
実行アプリのハンドルを取得
まずは、実行するアプリのハンドルを取得します。
IntPtr hWnd = new WindowInteropHelper(System.Windows.Application.Current.MainWindow).EnsureHandle();
HwndSourceオブジェクトを取得してすべてのウィンドウ メッセージを受け取るイベント ハンドラーを追加
HwndSource source = HwndSource.FromHwnd(hWnd);
source.AddHook(new HwndSourceHook(WndProc));
HwndSource.FromHwnd(IntPtr) メソッド (System.Windows.Interop)
指定したウィンドウの HwndSource オブジェクトを返します。
HwndSource.AddHook(HwndSourceHook) メソッド (System.Windows.Interop)
すべてのウィンドウ メッセージを受け取るイベント ハンドラーを追加します。
UsbDeviceWatcherクラス
以下でUSBメモリを抜き差しを行った時に検出するクラス作成します。
using System;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Interop;
//name space
namespace ScrennTransmittionSample.Model
{
/// <summary>
/// USBデバイス監視クラス
/// </summary>
public class UsbDeviceWatcher
{
/// <summary>
/// Windowメッセージ
/// </summary>
private enum WindowMessage
{
WM_DEVICECHANGE = 0x00000219
}
/// <summary>
/// Windowハンドル
/// </summary>
IntPtr _hWnd;
HwndSourceHook _hock;
/// <summary>
/// コンストラクタ
/// </summary>
public UsbDeviceWatcher()
{
_hWnd = new WindowInteropHelper(System.Windows.Application.Current.MainWindow).EnsureHandle();
}
/// <summary>
/// USBデバイス検出開始
/// </summary>
public void WatchStart()
{
HwndSource source = HwndSource.FromHwnd(_hWnd);
_hock = new HwndSourceHook(WndProc);
source.AddHook(_hock);
}
/// <summary>
/// USBデバイス検出停止
/// </summary>
public void WatachStop()
{
if (_hock != null)
{
HwndSource source = HwndSource.FromHwnd(_hWnd);
source.RemoveHook(_hock);
_hock = null;
}
}
/// <summary>
/// Windowsからのメッセージを受け取るWindowsプロシージャ
/// </summary>
protected IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
switch ((WindowMessage)msg)
{
case WindowMessage.WM_DEVICECHANGE:
Task.Run(() => CheckUSBDevices());
break;
default:
break;
}
return IntPtr.Zero;
}
/// <summary>
/// static関数 USBデバイス検出
/// </summary>
public static void CheckUSBDevices()
{
int count = 0;
using (var searcher = new System.Management.ManagementObjectSearcher(@"SELECT * FROM Win32_PnPEntity WHERE Service='USBSTOR'"))
{
System.Management.ManagementObjectCollection collection = searcher.Get();
foreach (var device in collection)
{
//取得したデバイスに対する処理
count++;
}
//その他処理を記述.
// リソース解放.
collection.Dispose();
}
/*それ以降の処理を記述*/
}
}
}
実行
//デバイス検出クラスインスタンス化
UsbDeviceWatcher watacher = new UsbDeviceWatcher();
//デバイス監視スタート
watacher.WatchStart();
//デバイス監視停止
watacher.WatachStop();
USBデバイスを差し込んだ時の実行結果。(※上記クラスには記載していませんが、メッセージボックスの処理を追加)
参考
デバイスのUSB接続状況を監視するアプリの作成 - Qiita
#はじめにWindowsを使っていると、時々USBデバイスを外した時の音が聞こえるようになりました。(ポロン↓、ポンポロロン↑)接続の音も聞こえているため、おそらくは接続が一瞬切れているのだと思…
コメント