トップ回答者
Windows XP x64 でのHIDデバイスアクセス

質問
-
こんにちは。
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では正常に動作していたのですが、どこを間違えているのでしょうか?
回答
-
こんにちは。
まさか・・・と思いつつ、試しました。見事、C & SDKでも同じ結果、つまりHIDデバイスが列挙できません。
念のためググってみると、どうやらHidD_GetHidGuidの返すGUIDがあやしいようで、ぽつりぽつりですが同じところでひっかかっている人を見つけました。
もしかするとWindows XP x64では、マウス、キーボードは、HidD_GetHidGuidの返すGUIDからは列挙できない仕様となったのでしょうか。Windows 2003 ServerやWindows Viastaもそうなってるんでしょうか。
結局、上記ソースには問題が無いと思われます。ただ、x64下のVisual Studio 2005では、pinvokeを含むコードの開発をする際、x86でなら受けられる恩恵が無く、問題点を探すのに苦労しそうです。
Hongliangさん、お付き合いいただきありがとうございました。
すべての返信
-
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
ほかにも、おかしなところがありますか?
-
下手に既存レスを編集して文字化けになるのがいやなので、追加はこっちに書きます。
ほかに試したこととしては、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はオプショナルで、今件では使わないのでヌルポにしています。どこか、勘違いがありますでしょうか。
-
こんにちは。
まさか・・・と思いつつ、試しました。見事、C & SDKでも同じ結果、つまりHIDデバイスが列挙できません。
念のためググってみると、どうやらHidD_GetHidGuidの返すGUIDがあやしいようで、ぽつりぽつりですが同じところでひっかかっている人を見つけました。
もしかするとWindows XP x64では、マウス、キーボードは、HidD_GetHidGuidの返すGUIDからは列挙できない仕様となったのでしょうか。Windows 2003 ServerやWindows Viastaもそうなってるんでしょうか。
結局、上記ソースには問題が無いと思われます。ただ、x64下のVisual Studio 2005では、pinvokeを含むコードの開発をする際、x86でなら受けられる恩恵が無く、問題点を探すのに苦労しそうです。
Hongliangさん、お付き合いいただきありがとうございました。