Discussion:
リムーバブルメディアの抜き差し検出
(too old to reply)
とっちゃん
2004-06-18 08:28:10 UTC
Permalink
とっちゃんです。

リムーバブルメディア(USBなんかのメディアリーダー)の
抜き差しの検出方法を探しています。

英語も含めGoogleは当たってみましたが
MSDNにあるのと同じ程度の情報しかヒットせず、ほとんど
足がかりがつかめていないというところです。

まだ、XPでしかテストしていないのですが、起動時に

DEV_BROADCAST_DEVICEINTERFACE notifyFilter;
ZeroMemory( &notifyFilter, sizeof(notifyFilter) );
notifyFilter.dbcc_size = sizeof(notifyFilter);
notifyFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
RegisterDeviceNotification( m_hWnd, &notifyFilter,
DEVICE_NOTIFY_WINDOW_HANDLE|
DEVICE_NOTIFY_ALL_INTERFACE_CLASSES );

で通知を受けるようにしてやることで
USBのストレージデバイスそのものの抜き差しは
通知が来るようになりました。

この状態で通知が来るのは

接続時が

EventType =DBT_DEVNODES_CHANGED

EventType =DBT_DEVICEARRIVAL
devicetype=DBT_DEVTYP_DEVICEINTERFACE
classguid =Unknown({A5DCBF10-6530-11D2-901F-00C04FB951ED})

EventType =DBT_DEVNODES_CHANGED

EventType =DBT_DEVICEARRIVAL
devicetype=DBT_DEVTYP_DEVICEINTERFACE
classguid =GUID_DEVINTERFACE_DISK

EventType =DBT_DEVNODES_CHANGED

EventType =DBT_DEVICEARRIVAL
devicetype=DBT_DEVTYP_DEVICEINTERFACE
classguid =GUID_DEVINTERFACE_PARTITION

EventType =DBT_DEVNODES_CHANGED

EventType =DBT_DEVICEARRIVAL
devicetype=DBT_DEVTYP_DEVICEINTERFACE
classguid =GUID_DEVINTERFACE_VOLUME

EventType =DBT_DEVNODES_CHANGED

EventType =DBT_DEVICEARRIVAL
devicetype=DBT_DEVTYP_VOLUME
flags =0
unitmask =0x00000008

EventType =DBT_DEVNODES_CHANGED

で、取り外したときが

EventType =DBT_DEVNODES_CHANGED

EventType =DBT_DEVNODES_CHANGED

EventType =DBT_DEVICEREMOVECOMPLETE
devicetype=DBT_DEVTYP_DEVICEINTERFACE
classguid =GUID_DEVINTERFACE_VOLUME

EventType =DBT_DEVNODES_CHANGED

EventType =DBT_DEVICEREMOVECOMPLETE
devicetype=DBT_DEVTYP_VOLUME
flags =0
unitmask =0x00000008

EventType =DBT_DEVICEREMOVECOMPLETE
devicetype=DBT_DEVTYP_DEVICEINTERFACE
classguid =GUID_DEVINTERFACE_PARTITION

EventType =DBT_DEVICEREMOVECOMPLETE
devicetype=DBT_DEVTYP_DEVICEINTERFACE
classguid =GUID_DEVINTERFACE_DISK

EventType =DBT_DEVICEREMOVECOMPLETE
devicetype=DBT_DEVTYP_DEVICEINTERFACE
classguid =Unknown({A5DCBF10-6530-11D2-901F-00C04FB951ED})

です。
メディアを抜き差ししただけではWM_DEVICECHANGE 自体が来ません。

もしかしたら他のメッセージとかなのかなと思いつつも
SDKレベルではこれ以上の情報は SetupDi 系APIくらいしか
記述がないため、どこへ向かえばいいのかもわからないという状態です。

XPだと、メディアを入れると自動的に何をしますかってダイアログが
出るので、何らかの手段で検出方法を持っているとは思うのですが。

どうにもならなければポーリングするという方法もあるのですが、
メディア状態を監視していることが主体のソフトではないので
(オプションというよりも、ほとんどおまけみたいな機能)
これは最後手段にと思っています。

元々WM_DEVICECHANGE は CDのメディアチェックでやってたので
段取りそのものは難なく用意できたのですが肝心の通知が
来なくて先に進めない状態です。

OS限定でもいいので通知の受け取り手段を知っている方がいたら
ヒントだけでも教えていただけないでしょうか。
とんちんかんちんかとちん
2004-06-18 08:50:54 UTC
Permalink
$B$0$0$C$?$i$$$-$J$***@hF,$K%R%C%H$7$^$7$?$,!"(B

http://www.google.com/search?q=WM_DEVICECHANGE&lr=&ie=UTF-8&oe=UTF-8&hl=ja&btnI=I'm+Feeling+Lucky

$B$3$N!V%^%$%/%m%=%U%H(B $B%5%]!<%H5;=Q>pJs(B - 842473 $B!W$H$OL54X78$G$9$+!)(B


_/_/_/ $B$H$s$A$s$+$s$A$s$+$H$A$s(B
_/_/_/ http://homepage2.nifty.com/t-katochin/
とっちゃん
2004-06-18 09:09:31 UTC
Permalink
$B$H$C$A$c$s$G$9!#(B
http://www.google.com/search?q=WM_DEVICECHANGE&lr=&ie=UTF-8&oe=UTF-8&hl=ja&btnI=I'm+Feeling+Lucky
Post by とんちんかんちんかとちん
$B$3$N!V%^%$%/%m%=%U%H(B $B%5%]!<%H5;=Q>pJs(B - 842473 $B!W$H$OL54X78$G$9$+!)(B
$B$3$l$H$OL54X78$G$9!#(B

$B$^$@%A%'%C%/$G$-$F$$$J$$$N$G$9$,!"(B
RegisterDeviceNotification $B$G$NEPO?$r(B

GUID_IO_XXX $B$N(B DEV_BROADCAST_HANDLE $B$G$d$l$P8!=P$G$-$k$N$+$b(B
$B$H$$$&$H$3$m$^$G$?$I$jCe$-$^$7$?!#(B

$B$3$A$i$O!"C1=c$K=hM}$7$?$N$G$O$&$^$/9T$+$J$$(B($BEPO?$K<:GT(B)$B$H$$$&$3$H$@$1$O(B
$B$o$+$C$?$N$G(B SetupDi $B7O$G%j%9%H%"%C%W$7$F$d$kI,MW$,$"$k$H;W$o$l$^$9$,(B
$B:#$N$H$3$m!"$J$K$r%j%9%H%"%C%W$9$l$P$$$$$+$,$o$+$C$F$J$$$N$G;n$7$F$^$;$s!#(B

$B$H$j$"$($:!"(BWM_DEVICECHANGE$B$GAw$i$l$F$-$?4{CN$N(BID$B$rJR$CC<$+$i(B
$B;n$7$F$_$h$&$H;W$C$F$^$9$,!";H$C$?$3$H$J$$$N$G2?$rJ];}$7$F$*$/$+$+$i(B
$BD4$Y$J$$$H$J$i$J$$$N$G!"$^$@$<$s$<$s%3!<%I$K$J$C$F$^$;$s(B(^^;
とんちんかんちんかとちん
2004-06-18 09:13:11 UTC
Permalink
$B$J$s$+<+J,$N%l%9$O$a$A$c$/$A$c30$7$F$^$9$M!#(B

$B$"$l!)$h$/9M$($?$i!"(B
$B$3$N>uBV$GDLCN$,Mh$k$N$O(B
$B!D(B($BCfN,(B)$B!D(B
EventType =DBT_DEVICEARRIVAL
$B!D(B($BCfN,(B)$B!D(B
$B$G!"<h$j30$7$?$H$-$,(B
$B!D(B($BCfN,(B)$B!D(B
EventType =DBT_DEVICEREMOVECOMPLETE
$B!D(B($BCfN,(B)$B!D(B
$B$G$9!#(B
$B$3$l$C$F!"!VK\Mh$N7k2L!W$r8@$C$F$^$9!)$=$l$H$b(B
$B!V8=>u$3$&$J$j$^$9!W$C$F8@$C$F$^$9!)(B

$B!V8=>u$3$&$J$j$^$9!W$G$"$l$P!"(B
$B@\B3;~$O$A$c$s$H(B EventType =DBT_DEVICEARRIVAL $B$,Mh$F$k$7!"(B
$B<h$j30$7;~$K$O(B EventType =DBT_DEVICEREMOVECOMPLETE $B$,(B
$B$A$c$s$HMh$F$$$k$H$$$&$3$H$G$9$h$M!)!)(B

$B$G$"$l$P!"$d$j$?$$$3$H$O$9$G$KK~$?$7$F$i$C$7$c$$$^$;$s!)(B


_/_/_/ $B$H$s$A$s$+$s$A$s$+$H$A$s(B
_/_/_/ http://homepage2.nifty.com/t-katochin/
とんちんかんちんかとちん
2004-06-18 09:16:58 UTC
Permalink
$B$"!"$4$a$s$J$5$$!#(B

$B#U#S#B%9%H%l!<%8%G%P%$%9$OMh$k$1$I!"(B
$B#U#S#B%j%`!<%P%V%k%G%P%$%9$OMh$J$$$H$$$&$3$H$J$s$G$9$M!)(B
$BFq$7$=$&$G$9$M!#(B

$B%4%_%l%9$G$9$_$^$;$s$G$7$?!#(B

_/_/_/ $B$H$s$A$s$+$s$A$s$+$H$A$s(B
_/_/_/ http://homepage2.nifty.com/t-katochin/
とっちゃん
2004-06-18 09:21:15 UTC
Permalink
$B$H$C$A$c$s$G$9!#(B
$B!V8=>u$3$&$J$j$^$9!W$G$9!#(B
$B$3$N%a%C%;!<%8$NN.$l$O!"%O!<%I%&%'%"$=$N$b$N$r$D$1$?$O$:$7$?(B
$B$N;~$KMh$k$b$N$G$9!#(B
$BB?J,!"(BUSB$B%a%b%j!<%9%H%l!<%8$@$H$3$l$G(BOK$B$@$H;W$&$s$G$9$,!"(B
$B%a%G%#%"%j!<%@!<$@$H$=$NCf$N%a%G%#%"$NH4$-:9$7$J$N$G!"(B
$B$=$C$A$^$G$OCe$F$$$J$$$s$G$9$h!#(B
$B$3$N$X$s$G$9$M!#(B

$B$b$&0l8D$N$[$&$K$b=q$$$F$"$j$^$9$,!"B>$K$b$=$l$i$7$$$N$,8+$D$+$C$?$N$G(B
$B$3$l$+$i<B83%3!<%I$r$*$3$9$H$3$m$G$9!#(B
$B<RFb$K$b%O!<%I$h$j$J$3$H$r$d$C$F$k?M4V$b$$$J$$$N$G!"8IFH$KD4$Y$F$k$H$3$m$G(B
$B$9!#(B
とっちゃん
2004-06-19 06:20:38 UTC
Permalink
とっちゃんです。

その後、糸口が見つかり、なんとか検出できるようになりました。

ということで解決策です。
まだ、片手落ち(動的な追加についていっていない)のですが、
それも、最初のイベントリストから取り込めるので、そちらは
省略です。

まだ、動作確認が取れているのは XP だけですが、
ドキュメントによると検出に使うイベントは 2000/XP のみということです。

ということで、以下コードの抜粋です。
コピー&ペーストなコードなので、抜け落ちはあるかも。

// 検索関数(抜粋)

GUID guid = GUID_DEVINTERFACE_DISK;
DWORD dwFlags = DIGCF_PRESENT|DIGCF_DEVICEINTERFACE;
if( bGuidIsInterface ) dwFlags |= DIGCF_DEVICEINTERFACE;
HDEVINFO hDevInfo = ::SetupDiGetClassDevs( &guid, NULL, m_hWnd, dwFlags );

if( hDevInfo != INVALID_HANDLE_VALUE ){
DWORD dwIndex = 0;
SP_DEVINFO_DATA devInfoData;
ZeroMemory( &devInfoData, sizeof(devInfoData) );
devInfoData.cbSize = sizeof(devInfoData);
while( ::SetupDiEnumDeviceInfo( hDevInfo, dwIndex, &devInfoData ) ){
SP_DEVICE_INTERFACE_DATA devInterfaceData;
ZeroMemory( &devInterfaceData, sizeof(devInterfaceData) );
devInterfaceData.cbSize = sizeof(devInterfaceData);
DWORD dwIndex2 = 0;
while( ::SetupDiEnumInterfaceDevice( hDevInfo, &devInfoData, &guid,
dwIndex2, &devInterfaceData ) ){
if( devInterfaceData.Flags & SPINT_ACTIVE ){
DWORD cbLength;
if( !::SetupDiGetDeviceInterfaceDetail( hDevInfo, &devInterfaceData,
NULL, 0, &cbLength, NULL ) &&
GetLastError() == ERROR_INSUFFICIENT_BUFFER )
{
cbLength += sizeof(TCHAR);
SP_DEVICE_INTERFACE_DETAIL_DATA* pDetailData =
static_cast<SP_DEVICE_INTERFACE_DETAIL_DATA*>( malloc( cbLength ) );
ZeroMemory( pDetailData, cbLength );
pDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
::SetupDiGetDeviceInterfaceDetail( hDevInfo, &devInterfaceData,
pDetailData, cbLength, &cbLength, NULL );
ConnectDevice( pDetailData->DevicePath ); // 接続関数を呼び出し
free( pDetailData );
}
}
dwIndex2++;
}
}
SetupDiDestroyDeviceInfoList( hDevInfo );
}
}
// 接続関数 省略しているが、トップレベルウィンドウのメンバー関数(m_hWndは
トップレベルウィンドウ)

list<DEVICE_CONNECT_INFO> m_lstConnectInfos; クラスメンバー
struct DEVICE_CONENCT_INFO
{
HANDLE hDevice; // 監視中のデバイスのハンドル
HDEVNOTIFY hDevNotify; // 通知ハンドル
};

void ConnectDevice( pDetailData->DevicePath )
{
DEVICE_CONENCT_INFO devConInfo;
devConInfo.hDevice = ::CreateFile( lpszDevicePath, GENERIC_READ, 0, NULL,
OPEN_EXISTING, 0, NULL );
if( devConInfo.hDevice != INVALID_HANDLE_VALUE ){
DEV_BROADCAST_HANDLE notifyFilter;
ZeroMemory( &notifyFilter, sizeof(notifyFilter) );
notifyFilter.dbch_size = sizeof(notifyFilter);
notifyFilter.dbch_devicetype = DBT_DEVTYP_HANDLE;
notifyFilter.dbch_handle = devConInfo.hDevice;
devConInfo.hDevNotify = ::RegisterDeviceNotification( m_hWnd,
&notifyFilter, DEVICE_NOTIFY_WINDOW_HANDLE );
if( devConInfo.hDevNotify == NULL ){
// 監視できない
CloseHandle( devConInfo.hDevice );
}
else{
m_lstConnectInfos.push_back( devConInfo ); //
}
}
}

以上でWM_DEVICECHANGE に
wParam = DBT_CUSTOMEVENT lParam = DEV_BROADCAST_HANDLE*
でイベントが発行されます。
メディアが挿入された場合は
GUID_IO_MEDIA_ARRIVAL
取り除かれた場合は
GUID_IO_MEDIA_REMOVAL
が呼び出されます

ヘッダーで必要なものは
#include <dbt.h>
#include <devguid.h>
#include <setupapi.h>
#include <ioevent.h>

です。
なお、XP に対応したヘッダーがない場合は
PlatformSDK をダウンロードしてくればOKです。

動的な追加は
EventType =DBT_DEVICEARRIVAL
devicetype=DBT_DEVTYP_DEVICEINTERFACE
classguid =GUID_DEVINTERFACE_DISK
このイベントで接続関数(ConnectDevice) を呼べば追加されます。

デバイスが取り外されるときにデバイスのハンドルを
閉じる必要があります。

このあたりの段取りは Toaster というサンプルに載っています。
MSDN で検索するとヒットする日本語KBの JP263832 にリンクがあります。
リンク先は ms のサイトです。
多分、WEBでも検索できると思いますが、チェックしてません。
なお、このサンプルは Windows 2000 の DDK にあるものらしいです。

とりあえず何とかなったので、他のOSでどういう風な通知が来るか
などを検証してみます。
とっちゃん
2004-06-19 08:13:25 UTC
Permalink
とっちゃんです。

その後のチェック結果です。

少なくとも今回書き起こしたテストコードでは XP 以外の
環境(2003は環境がないため未確認)でのメディア抜き差しの
イベントは来ないということがわかりました。

確認環境は ME/2000(98はドライバがないので未確認)です。
MEでこないので、98もおそらくだめだと思います。

ドライバはME/2000/XPともにMSの汎用ドライバです。

以下環境ごとの詳細です。
・ME
GUID_DEVINTERFACE_DISK ではなにもリストアップされない。
(そのためドライバの詳細情報はわからない)

RegisterDeviceNotification で特定のデバイスインターフェースを指定しても
デバイスの詳細までは通知にのってこない。

デバイスの接続などを通知する場合は
GUID_DEVINTERFACE_DISK または
GUID_DEVINTERFACE_VOLUME で良いらしい(他は未確認)。

デバイス接続時の構造体は DEV_BROADCAST_DEVNODE がくる。

・2000
メディアの抜き差しイベント
GUID_IO_MEDIA_ARRIVAL/GUID_IO_MEDIA_REMOVAL
はこないが、それ以外はほぼXPと同じ。

結局のところ、最低公約数で求めていくと
「デバイスの抜き差しのみ確認可能」
となります。

MSDN の該当イベントのところには XP からみたいなことが書かれてあるので
(VC7に付属のMSDNにはイベントそのものがありません)期待していなかったのですが
...

環境限定ではありますが、一応の解決を見れたのでここから先へ進むかどうかは
アプリに実装するかどうかで変わってきます。

成り行きを見守っていた方がいたら申し訳ないですが、この先は期待しないでくださ
い。

Continue reading on narkive:
Loading...