none
Windows XP x64 でのHIDデバイスアクセス RRS feed

  • 質問

  • こんにちは。

    Visual Studio 2005を利用しています。開発環境をWindows XP Professional x64 Editionに変えてみたため、過去作ったプログラムの動作確認をしました。
    すると、HIDデバイスの検索処理が正常に動作しないことに気づきました。

    PCにはマウス、キーボードがUSBで接続されており、これらはHIDデバイスとして認識されているにもかかわらず、SetupDiEnumDeviceInterfacesで列挙できないのです。(最初の呼び出しでFalseが返り、GetLastErrorが259)

    以下、現象が再現するサンプルコードです。
    (Form1にBottun1とTextBox1を配置しています。TextBox1はMultilineがTrueです。)


    ここに書いていたコードに編集で手を入れたら、文字化けオンパレード・・・
    どうやっても対策できないので、コードを削除し、以下の返信レスに修正済みのコードを記述しました。


    Windows XP、Windows2000では正常に動作していたのですが、どこを間違えているのでしょうか?
    2006年9月12日 7:14

回答

  • こんにちは。

    まさか・・・と思いつつ、試しました。見事、C & SDKでも同じ結果、つまりHIDデバイスが列挙できません。

    念のためググってみると、どうやらHidD_GetHidGuidの返すGUIDがあやしいようで、ぽつりぽつりですが同じところでひっかかっている人を見つけました。
    もしかするとWindows XP x64では、マウス、キーボードは、HidD_GetHidGuidの返すGUIDからは列挙できない仕様となったのでしょうか。Windows 2003 ServerやWindows Viastaもそうなってるんでしょうか。

    結局、上記ソースには問題が無いと思われます。ただ、x64下のVisual Studio 2005では、pinvokeを含むコードの開発をする際、x86でなら受けられる恩恵が無く、問題点を探すのに苦労しそうです。

    Hongliangさん、お付き合いいただきありがとうございました。
    2006年9月14日 8:11

すべての返信

  • 流し見ただけですしご使用の関数や構造体の仕様も存じませんが、

    tHwndParent As Integer

    tNullPointer As Integer

    とかいかにも不自然(名前と型が一致していない)ですね。

    2006年9月12日 8:37
  • Hongliangさん、こんにちは。

    値渡しなのでいいか、とそのままにしてしまいました。また、SpDeviceInterfaceData構造体のReserved要素もULONG_PTRなので、64ビット環境では8バイト、と修正してみました。
    ですが、状況は変わりません。Debug.PrintでSpDeviceInterfaceData構造体のサイズは変化していることは確認したのですが、エラーコード1784が返るわけでもなく、まるでHIDデバイスなど接続されていないといわんばかりです。

    以下、修正済みコードです。
    (コードを何度も掲載すると無駄に長くなるので、最初レスのサンプルコードを修正しようとしたら、文字化けの嵐・・・)



    Imports System.Runtime.InteropServices
    Public Class Form1
        Private Declare Sub GetHidGuid Lib "hid.dll" Alias "HidD_GetHidGuid" ( _
            ByRef tGuid As Guid _
            )
        Private Declare Function SetupDiGetClassDevs Lib "setupapi.dll" Alias "SetupDiGetClassDevsW" ( _
            ByRef tGuid As Guid, _
            ByVal tEnumerator As String, _
            ByVal tHwndParent As IntPtr, _
            ByVal tFlags As DIGCF _
            ) As IntPtr
        Private Declare Function SetupDiDestroyDeviceInfoList Lib "setupapi.dll" ( _
            ByVal tHwndDeviceInfo As IntPtr _
            ) As Boolean
        Private Declare Function SetupDiEnumDeviceInterfaces Lib "setupapi.dll" ( _
            ByVal tHwndDeviceInfo As IntPtr, _
            ByVal tNullPointer As IntPtr, _
            ByRef tGuid As Guid, _
            ByVal tMemberIndex As Integer, _
            ByRef tDeviceInterfaceData As SpDeviceInterfaceData _
            ) As Boolean
        Private Enum DIGCF As Integer
            PRESENT = &H2
            ALLCLASSES = &H4
            PROFILE = &H8
            DEVICEINTERFACE = &H10
        End Enum
        <StructLayout(LayoutKind.Sequential)> _
        Private Structure SpDeviceInterfaceData
            Public cbSize As Integer
            Public InterfaceClassGuid As Guid
            Public Flags As Integer
            Public Reserved As IntPtr
        End Structure
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim wGuid As New Guid
            Dim hHIDDeviceInfo As IntPtr
            GetHidGuid(wGuid)
            TextBox1.AppendText(wGuid.ToString & Environment.NewLine)
            hHIDDeviceInfo = SetupDiGetClassDevs(wGuid, vbNullString, IntPtr.Zero, DIGCF.PRESENT Or DIGCF.DEVICEINTERFACE)
            TextBox1.AppendText("Handle: 0x" & Hex(hHIDDeviceInfo.ToInt64) & Environment.NewLine)
            Dim wIndex As Integer = 0
            Do
                Dim wDeviceInterfaceData As SpDeviceInterfaceData
                wDeviceInterfaceData.cbSize = Marshal.SizeOf(wDeviceInterfaceData)
                Debug.Print(wDeviceInterfaceData.cbSize.ToString)
                If SetupDiEnumDeviceInterfaces(hHIDDeviceInfo, IntPtr.Zero, wGuid, wIndex, wDeviceInterfaceData) = False Then
                    TextBox1.AppendText(wIndex.ToString & ": End(" & Marshal.GetLastWin32Error.ToString & ")" & Environment.NewLine)
                    Exit Do
                End If
                TextBox1.AppendText(wIndex.ToString & ": ")
                TextBox1.AppendText("Size(" & wDeviceInterfaceData.cbSize.ToString & ") ")
                TextBox1.AppendText("Guid(" & wDeviceInterfaceData.InterfaceClassGuid.ToString & ") ")
                TextBox1.AppendText("Flags(" & wDeviceInterfaceData.Flags.ToString & ")" & Environment.NewLine)
                wIndex += 1
            Loop
            SetupDiDestroyDeviceInfoList(hHIDDeviceInfo)
        End Sub
    End Class

     

    ほかにも、おかしなところがありますか?

    2006年9月12日 10:51
  • 下手に既存レスを編集して文字化けになるのがいやなので、追加はこっちに書きます。

    ほかに試したこととしては、SpDeviceInterfaceData(SP_DEVICE_INTEFACE_DATA)の構造体パッキングの問題を疑って、



            For wSize As Integer = 6 To 200
                Dim wDDBuf As IntPtr = Marshal.AllocHGlobal(wSize)
                Marshal.WriteInt32(wDDBuf, wSize)
                Dim wRet As Boolean = SetupDiEnumDeviceInterfaces(hHIDDeviceInfo, IntPtr.Zero, wGuid, wIndex, wDDBuf)
                Dim wErrorCode As Integer = Marshal.GetLastWin32Error
                TextBox1.AppendText(wSize.ToString & ": " & wRet.ToString & "(" & wErrorCode.ToString & ")" & Environment.NewLine)
                Marshal.FreeHGlobal(wDDBuf)
            Next

     

    というコードで、6バイトから200バイトまでサイズを変化させて見ました。が、戻り値は常にFalse、GetLastErrorは259(ERROR_NO_MORE_ITEMS)のままです。
    このときの、SetupDiEnumDeviceInterfacesのプロトタイプは、


        Private Declare Function SetupDiEnumDeviceInterfaces Lib "setupapi.dll" ( _
            ByVal tHwndDeviceInfo As IntPtr, _
            ByVal tNullPointer As IntPtr, _
            ByRef tGuid As Guid, _
            ByVal tMemberIndex As Integer, _
            <[In](), Out()> ByVal tDeviceInterfaceData As IntPtr _
            ) As Boolean

     

    のようにしています。
    SetupDiEnumDeviceInterfacesをヘルプで確認すると、


    BOOL SetupDiEnumDeviceInterfaces(
      HDEVINFO DeviceInfoSet,
      PSP_DEVINFO_DATA DeviceInfoData,
      const GUID* InterfaceClassGuid,
      DWORD MemberIndex,
      PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData
    );

     

    のように定義されています。このうち第2引数のPSP_DEVICE_DATAはオプショナルで、今件では使わないのでヌルポにしています。

    どこか、勘違いがありますでしょうか。

    2006年9月13日 0:34
  • x64 環境を持っていないので検証すらできませんが……。

    その返値となると、まず C 言語と Platform SDK つかって API が有効かどうかから問題を切り分ける必要があるような気がします。

    C & SDK で有効なら、SDK での関数や構造体の定義と異なっているところがないか、とか。

    2006年9月13日 10:08
  • こんにちは。

    まさか・・・と思いつつ、試しました。見事、C & SDKでも同じ結果、つまりHIDデバイスが列挙できません。

    念のためググってみると、どうやらHidD_GetHidGuidの返すGUIDがあやしいようで、ぽつりぽつりですが同じところでひっかかっている人を見つけました。
    もしかするとWindows XP x64では、マウス、キーボードは、HidD_GetHidGuidの返すGUIDからは列挙できない仕様となったのでしょうか。Windows 2003 ServerやWindows Viastaもそうなってるんでしょうか。

    結局、上記ソースには問題が無いと思われます。ただ、x64下のVisual Studio 2005では、pinvokeを含むコードの開発をする際、x86でなら受けられる恩恵が無く、問題点を探すのに苦労しそうです。

    Hongliangさん、お付き合いいただきありがとうございました。
    2006年9月14日 8:11