开发者

WriteFile failing depending on length of data to write?

EDIT

Oddly enough, I've worked around this issue, but it's still annoying me. I worked around it by sending too-long writes, with padded zeroes; the code works but sends a few hundred unnecessary bytes. Specifically, I need to send exactly 992-byte packets instead of 7 or 19-byte packets. My question still stands however, why is the Logitech code able to make 7- or 19-byte writes when I cannot.


I'm running into an issue where a specific block of code fails or succeeds apparently depending on the length of the data passed to it. This makes no sense to me; I'm obviously doing something wrong but I can't tell what.

I have three cases where I'm trying to use the following block of code, which writes a byte stream to a USB device (one of two Logitech G-Series keyboards):

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

In the first case, I'm passing a 992-byte stream and the write completes successfully. In the second and third cases, I'm writing either 7 or 19 bytes, and WriteFile generates the errors ERROR_INVALID_USER_BUFFER for 7 bytes, or ERROR_INVALID_PARAMETER for 19 bytes. I've opened the handle for reading and writing, non-overlapped.

When using USBTrace, I can see that the default Logitech program is able to write all three cases without trouble, but my own code can only write the 992-byte case. This behavior is the same whether I compile my code as x86 or x64.

The code I'm using to open the handle is this:

    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(o开发者_C百科utput) = CByte(r)

                output += 1
            Next
            ImageOffset += BitmapData.Stride * 8
        Next
        SourceBitmap.UnlockBits(BitmapData)
        Return Data
    End Function

The exact code blocks that call WriteData() are the following:

(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

These specific commands are used to remap the macro ("G") keys on the boards to different character codes, in this case 00 disables the key. Anyone with a G15/G19/G510 keyboard can see this by disabling their Logitech gamepanel software and re-plugging the keyboard. G3 will act like F3 in notepad (find next), but after restarting the gamepanel software it will no longer do so.


I'm sorry this is not a Really Useful Answer, as I'm quite sure that what you are seeing is specific to your particular scenario, and I don't know this scenario in its entirety.

But the most likely reason to what you are seeing in my opinion is this. What you are writing to is not a real file (as you undoubtedly know) it's just an interface to your keyboard, that is surfaced as a file. Because of this, it is not a surprise, that you see completely different set of behaviour from a normal file. You can write to a file in file system most of the time. With the keyboard there could be a protocol that you have to follow to make it work.

What I think is happening here, is that things you are trying to write that fails, they are not being attempted to be written at the right state. The keyboard for whatever reason does not expect them when you are writing them.

You are saying that you can see that they are accepted ok with the USBTrace. This means that there is a correct state where they could be written there properly.

I'd start investigation at looking at the sequence of interactions that you are doing with the keyboard and thinking what could affect the ability of the keyboard to process your input.


Try writing an even number of bytes?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜