DOBON.NET DOBON.NETプログラミング掲示板過去ログ

USBメモリのシリアル取得について

環境/言語:[XP、VB.NET、VS2008]
分類:[.NET]

いつも勉強させて頂いています。

USBメモリを差し込んだ時にシリアルを取得したいと考えています。
WM_DEVICECHANGEにて判断し、ManagementObjectでシリアル取得の際にエラーが
出てしまいます。(DisconnectedContextが検出されました)

以下ソースです。

Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
    Select Case m.Msg
        Case WM_DEVICECHANGE
            Select Case m.WParam.ToInt32
                Case DBT.DBT_DEVICEARRIVAL
                    Try
                        Dim searcher As New ManagementObjectSearcher( _
                            "root\CIMV2", _
                            "SELECT * FROM Win32_DiskDrive where InterfaceType='USB'")
                        For Each queryObj As ManagementObject In searcher.Get()
                            Console.WriteLine("-----------------------------------")
                            Console.WriteLine("Win32_USBController instance")
                            Console.WriteLine("-----------------------------------")
                            Console.WriteLine("DeviceID: {0}", queryObj("DeviceID"))
                            Console.WriteLine("PNPDeviceID: {0}", queryObj("PNPDeviceID"))
                        Next
                    Catch err As ManagementException
                        MessageBox.Show("An error occurred while querying for WMI data: " & err.Message)
                    End Try
                    MessageBox.Show("USB挿し込み")
                Case DBT.DBT_DEVICEREMOVECOMPLETE
            End Select
        Case Else
    End Select
    MyBase.WndProc(m)
End Sub

searcher.Get()の部分でエラーが発生します。

コンテキスト 0x210358 が切断されました。
COM コンポーネント上の要求のサービスに使用されるプロキシは存在しません。
これは、破損またはデータの損失を発生させる可能性があります。
この問題を回避するには、その内部に存在する 
COM コンポーネントを示す RuntimeCallableWrappers の使用が完了するまで、
すべてのコンテキストおよびアパートメントが完全に有効であることを
確認してください。

基本的なエラーかと想像できますが、初心者の為理解できません。
どなたかご教授お願い致します。
■No27263に返信(hikamoさんの記事)
> WndProc
このタイミングでは WMI にアクセスしない方が良い気がします。
WMI へのアクセスは比較的低速なので。

> シリアルを取得したいと考えています。
別スレッドにして、遅延実行してみては如何でしょう?
それで解決するかどうかはわかりませんが。。。

> 初心者の為理解できません。
初心者レベルのコードでは無いように見えます。(^^;
魔界の仮面弁士さんの方法で試したところうまくいきました。

簡易に別スレッドを立ててテストしてみました。

    Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
        Select Case m.Msg
            Case WM_DEVICECHANGE
                Select Case m.WParam.ToInt32
                    Case DBT.DBT_DEVICEARRIVAL
                        Dim t As New Thread(New ThreadStart(AddressOf worker))
                        t.Start()
                    Case DBT.DBT_DEVICEREMOVECOMPLETE
                End Select
            Case Else
        End Select
        MyBase.WndProc(m)
    End Sub

    Sub worker()
        Try
            Dim Licences() As String = {"XXXXXXX", "XXXXXXX"} '指定したシリアル
            Dim searcher As New ManagementObjectSearcher( _
                "root\CIMV2", _
                "SELECT * FROM Win32_DiskDrive where InterfaceType='USB'")
            For Each queryObj As ManagementObject In searcher.Get()
                Find_Flg = False
                For i As Int16 = 0 To Licences.Length - 1
                    If Licences(i) <> queryObj("PNPDeviceID") Then 'シリアルが一致しない場合
                       '省略・・・・ 
                       Eject(queryObj("DeviceID")) 'CM_Request_Device_Ejectにて取り外し
                    End If
                Next
            Next
        Catch err As ManagementException
            MessageBox.Show("An error occurred while querying for WMI data: " & err.Message)
        End Try
    End Sub

USBメモリ検知 → あらかじめ登録されているシリアルか確認 →
未登録 → デバイスの自動取り外し

という流れでうまくテストできました。
有難う御座いました。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板