奇怪的是,我已经围绕这个问题,但它仍然让我感到烦恼。我通过发送过长的写入来处理它,并使用填充零;代码工作但发送几百个不必要的字节。具体来说,我需要发送正好992字节的数据包而不是7或19字节的数据包。然而,我的问题仍然存在,为什么当我不能时,罗技代码能够进行7或19字节写入。
我遇到了一个特定代码块失败或成功的问题,这取决于传递给它的数据长度。这对我没有意义;我显然做错了什么,但我不知道是什么。
我有三种情况,我正在尝试使用以下代码块,它将字节流写入USB设备(两个Logitech G系列键盘之一):
Friend Function WriteData(ByVal Keyboard As GSeriesKeyboard, ByVal Data() As Byte) As Integer
Dim BytesWritten As Integer = Data.Length
Dim Success As Boolean = Win32.WriteFile(Keyboard.ExternalIOHandle, Data, Data.Length, BytesWritten, Nothing)
Dim ErrorCode As Integer = GetLastError()
Return ErrorCode
End Function
<DllImport("kernel32.dll", SetlastError:=True)> Friend Shared Function WriteFile( _
ByVal File As SafeFileHandle, _
ByVal Buffer() As Byte, _
ByVal NumberOfBytesToWrite As Integer, _
ByRef NumberOfBytesWritten As Integer, _
ByRef Overlapped As System.Threading.NativeOverlapped) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
在第一种情况下,我传递了一个992字节的流,写入成功完成。在第二种和第三种情况下,我写入7或19个字节,WriteFile为7个字节生成错误ERROR_INVALID_USER_BUFFER,或者为19个字节生成ERROR_INVALID_PARAMETER。我打开了阅读和写作的句柄,没有重叠。
使用USBTrace时,我可以看到默认的Logitech程序能够毫无问题地编写所有三种情况,但我自己的代码只能编写992字节的情况。无论我将代码编译为x86还是x64,这种行为都是一样的。
我用来打开句柄的代码是:
Friend Function OpenInterface(ByVal KeyboardPath As String) As SafeFileHandle
Dim SecurityData As New SECURITY_ATTRIBUTES()
Dim security As New DirectorySecurity()
Dim DescriptorBinary As Byte() = security.GetSecurityDescriptorBinaryForm()
Dim SecurityDescriptorPtr As IntPtr = Marshal.AllocHGlobal(DescriptorBinary.Length)
SecurityData.nLength = Marshal.SizeOf(SecurityData)
Marshal.Copy(DescriptorBinary, 0, SecurityDescriptorPtr, DescriptorBinary.Length)
SecurityData.lpSecurityDescriptor = SecurityDescriptorPtr
Dim Handle As SafeFileHandle = Win32.CreateFile(KeyboardPath, GENERIC_READ Or GENERIC_WRITE, _
FILE_SHARE_READ Or FILE_SHARE_WRITE, SecurityData, _
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)
If Handle.IsInvalid Then
Dim ErrorInfo As New ComponentModel.Win32Exception()
Debug.Print("Failed to get device IO handle: " & ErrorInfo.Message)
End If
Return Handle
End Function
Friend Overridable Function BitmapToLcdFormat(ByVal SourceBitmap As Bitmap) As Byte()
'Base class is for the generic B&W 160x43 LCD. Override for G19 if I ever get my hands on one
Dim Data As Byte() = New Byte(991) {}
' USBTrace says 992 bytes
Dim Image(640 * 48) As Byte 'Temp array for image conversion. Adds additional 5 lines of unused pixels to avoid an out-of-bounds error
Dim BitmapData As BitmapData = SourceBitmap.LockBits(New Rectangle(0, 0, 160, 43), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb)
Marshal.Copy(BitmapData.Scan0, Image, 0, (640 * 43))
Data(0) = &H3 'Set-LCD
Dim output As Integer = 32 'First byte of image data starts at byte 32; 960 bytes of image data
Dim ImageOffset As Integer = 0
For Row As Integer = 0 To 5
For Column As Integer = 0 To (SourceBitmap.Width << 2) - 1 Step 4
Dim r As Integer = _
((Image(ImageOffset + Column + BitmapData.Stride * 0) And &H80) >> 7) Or _
((Image(ImageOffset + Column + BitmapData.Stride * 1) And &H80) >> 6) Or _
((Image(ImageOffset + Column + BitmapData.Stride * 2) And &H80) >> 5) Or _
((Image(ImageOffset + Column + BitmapData.Stride * 3) And &H80) >> 4) Or _
((Image(ImageOffset + Column + BitmapData.Stride * 4) And &H80) >> 3) Or _
((Image(ImageOffset + Column + BitmapData.Stride * 5) And &H80) >> 2) Or _
((Image(ImageOffset + Column + BitmapData.Stride * 6) And &H80) >> 1) Or _
((Image(ImageOffset + Column + BitmapData.Stride * 7) And &H80) >> 0)
Data(output) = CByte(r)
output += 1
Next
ImageOffset += BitmapData.Stride * 8
Next
SourceBitmap.UnlockBits(BitmapData)
Return Data
End Function
调用WriteData()的确切代码块如下:
(Logitech G15)
HardwareInterface.WriteData(Me, New Byte() {2, 0, 0, 0, 0, 0, 0})
(Logitech G510)
HardwareInterface.WriteData(Me, New Byte() {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
(Both; the one that works)
HardwareInterface.WriteData(Me, BitmapToLcdFormat(NewImage)) 'Build 992-byte LCD-format bitmap from source iumage
这些特定命令用于将板上的宏(“G”)键重新映射到不同的字符代码,在这种情况下,00禁用该键。任何拥有G15 / G19 / G510键盘的人都可以通过禁用他们的Logitech游戏面板软件并重新插入键盘来看到这一点。 G3在记事本中会像F3一样(找到下一个),但在重新启动游戏面板软件后,它将不再这样做。
答案 0 :(得分:1)
我很抱歉这不是一个真正有用的答案,因为我很确定你所看到的是特定于你的特定场景,我完全不知道这个场景。
但在我看来,你所看到的最可能的原因是这个。你写的不是一个真正的文件(你无疑知道)它只是键盘的一个接口,它表现为一个文件。因此,您可以看到与普通文件完全不同的行为,这并不奇怪。您可以在大多数时间写入文件系统中的文件。使用键盘可能需要遵循协议才能使其正常工作。
我认为这里发生的事情是,你试图写的东西失败了,它们并没有被试图写在正确的状态。无论出于何种原因,键盘在你编写它们时都不会指望它们。
你说你可以看到他们被USBTrace接受了。这意味着有一个正确的状态,可以正确地写在那里。
我开始调查您正在使用键盘进行的交互顺序,并考虑可能影响键盘处理输入的能力。
答案 1 :(得分:1)
尝试写一个偶数个字节?