Как использовать WinR GetRawInputDeviceList в Go? - PullRequest
0 голосов
/ 13 марта 2020

Я пытаюсь использовать функцию GetRawInputDeviceList в Go и получаю следующее сообщение об ошибке:

The parameter is incorrect.

В соответствии с официальная документация : первый параметр должен представлять собой массив структур RAWINPUTDEVICELIST для устройств, подключенных к системе. Я не совсем понимаю, какую комбинацию unsafe.Pointer, арифметику указателя c (?) И других вещей, которые мне нужно сделать, чтобы заставить это работать правильно.

Я нашел это Средняя статья , в которой содержатся некоторые рекомендации, но она не имеет прямого отношения к моему случаю использования. У меня недостаточно опыта работы с указателями и ручным управлением памятью, чтобы применить его к моей проблеме. Я не знаю, как перевести этот пример C ++ в Go, и я настолько отчаялся, что попытался преобразовать работающее VBA-решение в Go безуспешно.

У меня есть два вопроса по этому вопросу:

  1. Как преобразовать массив структур в Go в соответствующий тип, ожидаемый для Windows Вызов API?
  2. Как преобразовать результат обратного вызова API Windows в массив структур с заполненными данными?

Среда

Вот Сведения о моей системе / языке:

  • 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
}

1 Ответ

1 голос
/ 13 марта 2020

Во-первых, ошибка 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
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...