ページ 11

アプリでUSBドライブ監視時にUSBの抜去ができない。

Posted: 2012年5月22日(火) 12:07
by ヨシカワ
先日に続き恐縮ですが、質問をさせてください。

アプリ側でUSBのファイル変更の監視を行っています。
この時に、タスクトレイの「ハードウェアを安全に取り外してメディアを取り出す」からUSBの取り外しを行うと、
「このデバイスは現在使用中です。・・・・・」というエラーが発生します。

USBドライブの監視を以下のサイトを参考にしています。
方法はドライブ単位にReadDirectoryChanges()を使用したファイルアクセスのチェックです。
http://d.hatena.ne.jp/seraphy/20120506


■質問
上記のWindowsのエラーを回避してUSBの抜去をすることは可能でしょうか?
こちらで検討したところ、常時CreateFileでオープンしているため、不可能だと思っています。


■調査範囲
一応原因は把握しており、CreateFileでドライブ自体をオープンしているため、OS側がUSBドライブを使用中と判断したためだと認識しています。

現状の実装はWindowのサービス上で実装しています。
USB挿入時のイベント(SERVICE_CONTROL_DEVICEEVENT)を取得後に、監視を開始。
抜去時のイベントでリソースの開放を行っています。

物理的にUSBを抜いた場合はSERVICE_CONTROL_DEVICEEVENTは発生しますが、上記の抜き方では発生しません。






・コードの一部記載します

HANDLE m_hDir = ::CreateFile(strDirToWatch, //USBドライブのパス
FILE_LIST_DIRECTORY,
FILE_SHARE_READ | FILE_SHARE_WRITE ,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS |
FILE_FLAG_OVERLAPPED,
NULL);



-- 中略 --

BOOL b = ReadDirectoryChangesW(m_hDir, pBuf, nBufSize, TRUE, m_cOpt.dwWatchMode, 0, &m_Overlapped, 0);
if(!b) {
break;
}

-- 中略 --
ファイルアクセスがあったファイルのチェック

Re: アプリでUSBドライブ監視時にUSBの抜去ができない。

Posted: 2012年5月22日(火) 12:12
by softya(ソフト屋)
前回のトピックが解決になっていないので解決にするか前回のトピックで続きをお願いします。

Re: アプリでUSBドライブ監視時にUSBの抜去ができない。

Posted: 2012年5月22日(火) 12:15
by ヨシカワ
ご指摘ありがとうございます。前質問のステータスを変更しました。

Re: アプリでUSBドライブ監視時にUSBの抜去ができない。

Posted: 2012年5月22日(火) 12:26
by softya(ソフト屋)
OSの管理としては資源がアプリによって確保されている以上はUSBを切り離すことは簡単では無いと思います。
Usbstor.sysから取り外し依頼イベントをアプリに通知する仕組みがあれば良いのですが・・・。少し調べてみます。

Re: アプリでUSBドライブ監視時にUSBの抜去ができない。

Posted: 2012年5月22日(火) 12:46
by softya(ソフト屋)
確実な方法は以下の様な方法みたいですね。
「USBメモリのファイル監視について - Insider.NET - @IT」
http://www.atmarkit.co.jp/bbs/phpBB/vie ... 33&forum=7

Re: アプリでUSBドライブ監視時にUSBの抜去ができない。

Posted: 2012年5月22日(火) 22:09
by dig
ヨシカワ さんが書きました:先日に続き恐縮ですが、質問をさせてください。

アプリ側でUSBのファイル変更の監視を行っています。
この時に、タスクトレイの「ハードウェアを安全に取り外してメディアを取り出す」からUSBの取り外しを行うと、
「このデバイスは現在使用中です。・・・・・」というエラーが発生します。

USBドライブの監視を以下のサイトを参考にしています。
方法はドライブ単位にReadDirectoryChanges()を使用したファイルアクセスのチェックです。
http://d.hatena.ne.jp/seraphy/20120506

■質問
上記のWindowsのエラーを回避してUSBの抜去をすることは可能でしょうか?
こちらで検討したところ、常時CreateFileでオープンしているため、不可能だと思っています。

■調査範囲
一応原因は把握しており、CreateFileでドライブ自体をオープンしているため、OS側がUSBドライブを使用中と判断したためだと認識しています。

現状の実装はWindowのサービス上で実装しています。
USB挿入時のイベント(SERVICE_CONTROL_DEVICEEVENT)を取得後に、監視を開始。
抜去時のイベントでリソースの開放を行っています。

物理的にUSBを抜いた場合はSERVICE_CONTROL_DEVICEEVENTは発生しますが、上記の抜き方では発生しません。
Windowsサービスですか...サービスではやったことないのであくまで推測となります。間違ってたらすいません。

WM_DEVICECHANGEを捕捉でき、かつwparamを取得できるのであればデバイス取り外し要求メッセージであるDBT_DEVICEQUERYREMOVEを
捕捉し、デバイスの監視をそこで終了させればいけるような気がします。
もし監視終了がタイミング的に間に合わずデバイスの除去に失敗した場合は更にデバイス取り外し要求が失敗したことを表すDBT_DEVICEQUERYREMOVEFAILEDメッセージを捕捉し、アプリ側で停止、
除去してみるというのはどうでしょうか?
(ちなみにDBT_DEVICEQUERYREMOVEなどはRegisterDeviceNotification() を呼び出しておかないとメッセージが来なかったはずです。少なくともウィンドウアプリでは...
また、多機能カードリーダ(SD、XD、CFなど対応)の取り外し要求メッセージはこれで捕捉できるかどうかわかりません。)


しかしながら、どういうアプリケーションかは知りませんが、2度挿したら差分チェックするというのは意味があるのでしょうか?
ユニーク値の保存もどこまでやるのかはわかりませんが、キッチリやらないとあまり意味がないように思います。

例えば
F:にusbAデバイスを挿す→Aを抜く→usbBデバイスをF:に挿す→Bを抜く→またusbAをF:に挿す。今度はCとAを交互に...と以下ループ。

こういったことを繰り返された場合どうするのでしょうか?永遠と配列か何かでユニーク値を保存していくのでしょうか?
コンビニの店頭にある写真印刷機のような長期稼動を前提とするプログラムの場合はこれではマズイような気もします。

以上、参考になれば幸いです。