pointers - 如何在Go中使用Win32的GetRawInputDeviceList?

标签 pointers go winapi

我试图在Go中使用 GetRawInputDeviceList 函数,但不断出现以下错误:
The parameter is incorrect.
对于official documentation:对于连接到系统的设备,第一个参数必须是 RAWINPUTDEVICELIST 结构的数组。我不太了解unsafe.Pointer,指针算术(?)和我需要做的其他事情才能使其正常工作。

我发现this Medium article提供了一些指导,但它并不直接适用于我的用例。我没有足够的经验与指针和手动内存管理一起将其应用于我的问题。我不知道如何将this C++ example转换为Go,但我如此绝望,以至于我尝试将a working VBA solution转换为Go都没有成功。

关于此事,我有两个问题:

  • 如何将Go中的结构数组转换为Windows API调用所需的适当类型?
  • 如何将Windows API调用的结果转换回具有填充数据的结构数组?

  • 环境

    这是我的系统/语言详细信息:
  • macOS Mojave v10.14.6
  • Go v1.10.7(需要在Windows XP上运行可执行文件)

  • 我的目标是Windows XP,因此我运行以下命令进行编译:
    env GOOS=windows GOARCH=386 go1.10.7 build -o example.exe example.go
    



    这是我要开始工作的代码。我还没有对devices做任何事情,但是目标是使用句柄(DeviceHandle中的rawInputDeviceList)来获取有关输入设备的信息。

    package main
    
    import (
      "fmt"
      "syscall"
      "unsafe"
    )
    
    // RAWINPUTDEVICELIST structure
    type rawInputDeviceList struct {
      DeviceHandle uintptr
      Type         uint32
    }
    
    var (
      user32 = syscall.NewLazyDLL("user32.dll")
      getRawInputDeviceListProc = user32.NewProc("GetRawInputDeviceList")
    )
    
    func main() {
      dl := rawInputDeviceList{}
      size := uint32(unsafe.Sizeof(dl))
    
      // First I determine how many input devices are on the system, which
      // gets assigned to `devCount`
      var devCount uint32
      _ = getRawInputDeviceList(nil, &devCount, size)
    
      if devCount > 0 {
        size = size * devCount
        devices := make([]rawInputDeviceList, size) // <- This is definitely wrong
    
        for i := 0; i < int(devCount); i++ {
          devices[i] = rawInputDeviceList{}
        }
    
        // Here is where I get the "The parameter is incorrect." error:
        err := getRawInputDeviceList(&devices, &devCount, size)
        if err != nil {
          fmt.Printf("Error: %v", err)
        }
      }
    }
    
    // Enumerates the raw input devices attached to the system.
    func getRawInputDeviceList(
      rawInputDeviceList *[]rawInputDeviceList, // <- This is probably wrong
      numDevices *uint32,
      size uint32,
    ) error {
      _, _, err := getRawInputDeviceListProc.Call(
        uintptr(unsafe.Pointer(rawInputDeviceList)),
        uintptr(unsafe.Pointer(numDevices)),
        uintptr(size))
      if err != syscall.Errno(0) {
        return err
      }
    
      return nil
    }
    

    最佳答案

    首先,ERROR_INVALID_PARAMETER错误是由最后一个参数引起的:cbSize,根据文档,应始终将其设置为RAWINPUTDEVICELIST的大小。

    然后,您将通过编译器,但仍会收到运行时错误。因为您已经传递了数组的指针。

    以下代码对我有用:

    package main
    
    import (
      "fmt"
      "syscall"
      "unsafe"
    )
    
    // RAWINPUTDEVICELIST structure
    type rawInputDeviceList struct {
      DeviceHandle uintptr
      Type         uint32
    }
    
    var (
      user32 = syscall.NewLazyDLL("user32.dll")
      getRawInputDeviceListProc = user32.NewProc("GetRawInputDeviceList")
    )
    
    func main() {
      dl := rawInputDeviceList{}
      size := uint32(unsafe.Sizeof(dl))
    
      // First I determine how many input devices are on the system, which
      // gets assigned to `devCount`
      var devCount uint32
      _ = getRawInputDeviceList(nil, &devCount, size)
    
      if devCount > 0 {
        devices := make([]rawInputDeviceList, size * devCount) // <- This is definitely wrong
    
        for i := 0; i < int(devCount); i++ {
          devices[i] = rawInputDeviceList{}
        }
    
        // Here is where I get the "The parameter is incorrect." error:
        err := getRawInputDeviceList(&devices[0], &devCount, size)
        if err != nil {
          fmt.Printf("Error: %v", err)
        }
        for i := 0; i < int(devCount); i++ {
          fmt.Printf("Type: %v", devices[i].Type)
        }
    
      }
    }
    
    // Enumerates the raw input devices attached to the system.
    func getRawInputDeviceList(
      rawInputDeviceList *rawInputDeviceList, // <- This is probably wrong
      numDevices *uint32,
      size uint32,
    ) error {
      _, _, err := getRawInputDeviceListProc.Call(
        uintptr(unsafe.Pointer(rawInputDeviceList)),
        uintptr(unsafe.Pointer(numDevices)),
        uintptr(size))
      if err != syscall.Errno(0) {
        return err
      }
    
      return nil
    }
    

    关于pointers - 如何在Go中使用Win32的GetRawInputDeviceList?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60662743/

    相关文章:

    windows - 使用 Go 1.7 构建 dll

    .net - 将窗口置于无焦点的前面

    c++ - ExtractIcon和ExtractAssociatedIcon之间的区别?需要提取特定大小的图标

    c++ - 如何解决将未知大小的二维数组传递给函数的问题?

    c - 结构体中的指针值发生变化而不重新分配

    go - HTTP批量从多个API获取并保存到结构

    json - http: panic serving [::1]:57685: 分配给 nil 映射中的条目

    C++如何删除垂直滚动条?

    c - 为什么下面代码的答案是1000?

    C 在 void 函数之后由指针发送的数组的值被修改