動作環境WinXP/Win7,VB2008
USBメモリを自動で取り外すコードを作成しています。
WinXPではうまく行きましたが、Win7ではうまく行きません。
解決策をどなたかご教授お願いします。
取り外すUSBはセキュアUSBメモリです。
処理手順は以下の通りです。
1.SetupDiGetClassDevs()を使って、デバイスを列挙。
2.GetDeviceIDを使ってDeviceIDを取得。
※後述しますがWin7の場合DeviceIDが正しく取得できていないようです。
3.DeviceIDがターゲットUSBメモリのDeviceIDと一致したら
CM_Request_Device_EjectWを投げて、USBメモリを外す。
コードは以下の通り
Dim GUID_DEVINTERFACE_VOLUME As Guid =
New Guid(&H53F5630D, &HB6BF, &H11D0, &H94, &HF2, &H0, &HA0, &HC9, &H1E, &HFB, &H8B)
Dim hDevInfo As Integer = SetupDiGetClassDevs(GUID_DEVINTERFACE_VOLUME, IntPtr.Zero, 0, DIGCF_PRESENT + DIGCF_DEVICEINTERFACE)
If hDevInfo <> INVALID_HANDLE_VALUE Then
Dim MemberIndex As Integer = 0
Dim did As New SP_DEVINFO_DATA
did.cbSize = Marshal.SizeOf(did)
Dim didPtr As IntPtr = Marshal.AllocHGlobal(did.cbSize)
Marshal.StructureToPtr(did, didPtr, True)
While SetupDiEnumDeviceInfo(hDevInfo, MemberIndex, didPtr) <> 0
Marshal.PtrToStructure(didPtr, did)
Dim pDevInst As Integer
Dim BusDeviceID As String = ""
CM_Get_Parent(pDevInst, did.DevInst, 0)
CM_Get_Parent(pDevInst, pDevInst, 0)
BusDeviceID = GetDeviceID(pDevInst)
//このときBusDeviceIDの取得値がWinXPとWin7で
//違っている
//WinXP:列挙した中にUSBメモリのID
// USB\VID_0411&PID_013D\0700078B0CAC1001
// が出てくる。
//Win7:列挙したIDは全てHTREE\ROOT\0となっている。
If BusDeviceID = "USB\VID_" & VID & "&PID_" & PID & _
"\" & SN Then
If CM_Request_Device_EjectW(pDevInst, IntPtr.Zero, _
IntPtr.Zero, 0, 0) = 0 Then
Res = 0
Exit While
Else
Res = 1
Exit While
End If
End If
・
・
・
権限の問題です。
※ 管理者権限付で実行したらどうなりますか?
以上。参考まで
不具合は管理者権限で実行した結果です。
GetDeviceID(pDevInst)で取得したデバイスIDが
WinXP(正)とWin7(誤)で違うのが原因のようです
が、なぜ違うのかがわかりません。
SetupDiEnumDeviceInfoで取得したdidPtrが正し
アドレスを差していないのでは?と思っています
がどう対処すればよいかわかりません。
WinXPの場合:列挙した中にUSBメモリのデバイスID
USB\VID_0411&PID_013D\0700078B0CAC1001
が出てくる。
Win7の場合 :列挙したIDは全てHTREE\ROOT\0となっている。
->このため、CM_Request_Device_EjectWが効か
ない。
Win7 も、32bitですよネ?
ソースコードの内容は未確認ですが・・・
自作やインターネットで拾ってきたコードでは、問題なく
イジェクトできています。
ガジェットでイジェクトするものも正常に動作しています
ので何でしょうかネ〜
以上。
32bitです。
オショウさん。支障なければ、問題なくイジェクト
できたコードを紹介していただければ助かります。
フリーソフトUnhotplug.exe(conaさん作)を呼び出し
てイジェクトするコードも作ってみましたが、これは
問題ありませんでした。
但し、外部アプリでイジェクトするのでなく、コード
を実装してイジェクトしたいと考えています。
SetupDiGetClassDevs は、そのPCのドライブ数分、呼び出している
動作になっていますか?
列挙するので、該当するGUID数分ループする動作となりますので、そ
の一部のコードでは何とも・・・
イジェクトするにはいくつかの方法がありますので、あなたの方法と
は違う方法なので、どこがとは指摘できませんが、CM_Get_Parent を
2回行っている部分で、正しく動作しているのかご確認下さい。
以上。参考まで
>SetupDiGetClassDevs は、そのPCのドライブ数分、
>呼び出している動作になっていますか?
Dim GUID_DEVINTERFACE_VOLUME As Guid = New Guid(&H53F5630D, &HB6BF, &H11D0, &H94, &HF2, &H0, &HA0, &HC9, &H1E, &HFB, &H8B)
Dim hDevInfo As Integer = SetupDiGetClassDevs(GUID_DEVINTERFACE_VOLUME, IntPtr.Zero, 0, DIGCF_PRESENT + DIGCF_DEVICEINTERFACE)
でhDevInfoを取得して
While SetupDiEnumDeviceInfo(hDevInfo, MemberIndex, didPtr) <> 0
で0になるまで繰り返しています。
Whileループ時にレジストリをみるとWin7は別のキーを見ているようです。
<WinXPの場合>
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\DeviceClasses
\{53F5630DHB6BF11D094F20A0C91EFB8B}を見ている感じ
(IDの戻りはUSB\VID_0411&PID_013D\0700078B0CAC1001など
ドライブのインスタンスIDが帰ってくる)
<Win7の場合>
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Enumを見ている
感じ(IDの戻りはHTREE\ROOT\0のみ)
>CM_Get_Parent を
>2回行っている部分で、正しく動作しているのかご確認下さい。
連休のため、手元にWin7がありません。
連休明けに確認します。
何がしかの値が返ってきていたのは確認しましたが、
この値が正しいかどうかはどこを見て確認すればよい
でしょうか?
http://www.codeproject.com/Articles/13530/Eject-USB-disks-using-C
http://winofsql.jp/VA003334/usb080803163310.htm
それらで研究されては?
以上。参考まで
>http://www.codeproject.com/Articles/13530/Eject-USB-disks-using-C
>http://winofsql.jp/VA003334/usb080803163310.htm
オショウさん紹介ありがとうございます。
紹介があったコードも、以前、demo版UsbEject.exeを
ネットから落として確認してみました。その時は実行
時にエラーが発生したので使用を諦めた気がします。
来週、Win7 PCにC#の開発環境を入れて、デバッグ環境
で状況を調べてみます。
Win7 32bit で、そのソースコードをリコンパイルして
正常に動作してます。管理者権限いるけど・・・
以上。
>正常に動作してます。管理者権限いるけど・・・
オショウさん了解。
連休中で手元にWin7がないので来週早速
やってみます。
>Win7 32bit で、そのソースコードをリコンパイルして
>正常に動作してます。管理者権限いるけど・・・
紹介があったUsbEject.slnをWin7 32bitでリコンパイルして、
デバッグモードで実行してみましたが、「アクセス拒否」エ
ラーがでてうまくいきませんでした。
そこで、管理者権限で問い合わせがあります。
アドミニ権限のユーザーアカウントで実行しましたが、
Volume.cs 185行
throw new Win32Exception(Marshal.GetLastWin32Error());
で"アクセスが拒否されました。"のエラーがでています。
ユーザーアカウントの権限設定以外に何か設定が必要ですか?
ネットで調べると、メッセージによっては予めセキュリティ特権
を有効にするコードを追加する必要があるようですが。。。。
☆C#の話になってしましましたが、上手く言った後VBに移植します。
Volume.cs 185行?
そんなに行数ありませんが・・・改行コードの変換のダイアログが
出ませんでしたか?
因みに、何も変更せず、app.manifest を追加し、
<requestedExecutionLevel level="asInvokerr" uiAccess="false" />
を、
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
に変更しただけです。(アイコンとマニフェストの部分も変更)
因みに、そのPCにログインする際のユーザーは、管理者権限を
有せない設定のユーザーですか?
もしくはActiveDirectoryに参加しているPCですか?
Admin権限を持っているユーザーでも、管理者権限はUACダイ
アログで有効にしないと、管理者権限で実行されないので注意
が必要です。
以上。
><requestedExecutionLevel level="requireAdministrator" >uiAccess="false" >/>
>に変更しただけです。(アイコンとマニフェストの部分も変更)
この設定にC#デバッグ環境を変更したら上手く動作しました。
(USBが外せました)
時間がかかりそうですが、早速、VBへ移植します。
>Admin権限を持っているユーザーでも、管理者権限はUACダイ
>アログで有効にしないと、管理者権限で実行されないので注意
>が必要です。
先週からWin7用のプログラムを作り始めましたが、WinXPの感覚
でいました。アドミニでログインしても、WinXPとは違い一部の
権限は制限がかかっているのですね。
コードはC#ですがWinXP・Win7でもUSBが外せるコードが見つかっ
たので、VB移植を頑張ってみます。
このスレッドは「解決」です。
オショウさんありがとうございました。
ツイート | ![]() |