【问题标题】:How do I use Win32's GetRawInputDeviceList in Go?如何在 Go 中使用 Win32 的 GetRawInputDeviceList?
【发布时间】:2020-03-12 22:42:49
【问题描述】:

我正在尝试在 Go 中使用 GetRawInputDeviceList 函数,但我不断收到以下错误:

The parameter is incorrect.

根据official documentation:第一个参数必须是连接到系统的设备的RAWINPUTDEVICELIST 结构数组。我不太明白unsafe.Pointer、指针算术(?)和其他我需要做的组合才能使其正常工作。

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

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

  1. 如何将 Go 中的结构数组转换为 Windows API 调用所需的适当类型?
  2. 如何将 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 做任何事情,但目标是使用句柄(来自rawInputDeviceListDeviceHandle)来获取有关输入设备的信息。

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
}

【问题讨论】:

  • 你只要把它当成一个GetRawInputDeviceList指针,第二次传递的size已经改成size = size * devcount而不是sizeof (GetRawInputDeviceList)

标签: pointers go winapi


【解决方案1】:

首先,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
}

【讨论】:

  • 嗨,@Mike 这对您的问题有帮助吗?
  • 嗨@drake-wu-msft,对于延迟回复,我深表歉意。我刚刚尝试了你的解决方案,它奏效了。非常感谢您的帮助!
猜你喜欢
  • 2010-11-04
  • 2010-12-15
  • 1970-01-01
  • 1970-01-01
  • 2011-09-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-18
相关资源
最近更新 更多