【问题标题】:Implementing winapi(SendInput) with dart:ffi使用 dart:ffi 实现 winapi(SendInput)
【发布时间】:2020-04-09 01:12:52
【问题描述】:

我正在尝试使用 ffi 在 dart 中实现 SendInput 函数。 它需要一个无符号整数、一个输入数组和一个整数。 我发现很难实现 INPUT 数组结构,这是我到目前为止所做的:

import 'dart:ffi';

import 'package:ffi/ffi.dart';

import 'user32.dart'; //import dylib

typedef SendInputC = Uint32 Function(
    Uint32 cInputs, Pointer pInputs, Int32 cbSize);

typedef SendInputDart = int Function(int inputCount, Pointer inputs, int size);

int SendInput(int type, {MouseInput mi, KeyboardInput ki, HardwareInput hi}) {
  final SendInputP =
      dylib.lookupFunction<SendInputC, SendInputDart>('SendInput');

  var input = Input.allocate(
      type: type,
      mi: mi?.addressOf ?? nullptr,
      ki: ki?.addressOf ?? nullptr,
      hi: hi?.addressOf ?? nullptr);

  var result = SendInputP(1, input.addressOf, sizeOf<Input>());
  return result;
}

class Input extends Struct {
  @Uint32()
  int type;

  Pointer<MouseInput> mi;
  Pointer<KeyboardInput> ki;
  Pointer<HardwareInput> hi;

  factory Input.allocate(
          {int type,
          Pointer<MouseInput> mi,
          Pointer<KeyboardInput> ki,
          Pointer<HardwareInput> hi}) =>
      allocate<Input>().ref
        ..type = type
        ..mi = mi
        ..ki = ki
        ..hi = hi;
}

/// MouseInput struct
class MouseInput extends Struct {
  @Int32()
  int dx;

  @Int32()
  int dy;

  @Uint32()
  int mouseData;

  @Uint32()
  int dwFlags;

  @Uint32()
  int time;

  @Uint32()
  int dwExtraInfo;

  factory MouseInput.allocate(
          {int dx = 0,
          int dy = 0,
          int mouseData = 0,
          int dwFlags = 0,
          int time = 0,
          int dwExtraInfo = 0}) =>
      allocate<MouseInput>().ref
        ..dx = dx
        ..dy = dy
        ..mouseData = mouseData
        ..dwFlags = dwFlags
        ..time = time
        ..dwExtraInfo = dwExtraInfo;
}

class KeyboardInput extends Struct {
  @Uint16()
  int wVk;

  @Uint16()
  int wScan;

  @Uint32()
  int dwFlags;

  @Uint32()
  int time;

  @Uint32()
  int dwExtraInfo;

  factory KeyboardInput.allocate(
          {int wVk = 0,
          int wScan = 0,
          int dwFlags = 0,
          int time = 0,
          int dwExtraInfo = 0}) =>
      allocate<KeyboardInput>().ref
        ..wVk = wVk
        ..wScan = wScan
        ..dwFlags = dwFlags
        ..time = time
        ..dwExtraInfo = dwExtraInfo;
}

class HardwareInput extends Struct {
  @Uint32()
  int uMsg;

  @Uint16()
  int wParamL;

  @Uint16()
  int wParamH;

  factory HardwareInput.allocate(
          {int uMsg = 0, int wParamL = 0, int wParamH = 0}) =>
      allocate<HardwareInput>().ref
        ..uMsg = uMsg
        ..wParamL = wParamL
        ..wParamH = wParamH;
}

但是调用SendInput函数没有任何效果,返回0,例如这段代码没有发送鼠标输入。

  var mi = MouseInput.allocate(dx: 505, dy: 175, dwFlags: 0x0002);
  var r = SendInput(0, mi: mi);

这是函数在 C++ 中的样子

    INPUT input;
    input.type = INPUT_MOUSE;
    input.mi.dx = 505;
    input.mi.dy = 175;
    input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
    input.mi.dwExtraInfo = 0;
    input.mi.time = 0;


    SendInput(1, &input, sizeof(input));

tagInput 结构包含似乎尚不支持的联合 (https://github.com/dart-lang/sdk/issues/38491),但我想知道在支持联合之前是否有解决方法。

【问题讨论】:

    标签: c++ winapi dart ffi


    【解决方案1】:

    你的方法行不通,因为你的结构太大了。您真正想要的是分配的内存具有与常规 C 版本相同的大小(即 28 字节),因此如下所示:

    class KeyboardInput extends Struct {
      @Uint32() int type;
      @Uint16() int virtualCode;
      @Uint16() int scanCode;
      @Uint32() int flags;
      @Uint32() int time;
      Pointer dwExtraInfo;
      @Uint32() int _padding;
    }
    

    话虽如此 - 它仍然不起作用,我真的不知道为什么。我什至 experimented 只传递了在 dart 中仍然不起作用的原始字节数组指针(在 C 中它工作得很好)。这可能是飞镖 FFI 本身的一个错误,但可能是很多其他的东西。我正在尝试破解它,因为我也需要它来工作。

    现在您可以使用已弃用的功能:

    import 'dart:ffi';
    DynamicLibrary _user32 = DynamicLibrary.open("user32.dll");
    
    typedef _keybd_event_C = Void Function(Uint8 bVk, Uint8 bScan, Uint32 dwFlags, Pointer dwExtraInfo);
    typedef _keybd_event_Dart = void Function(int bVk, int bScan, int dwFlags, Pointer dwExtraInfo);
    var keybd_event = _user32.lookupFunction<_keybd_event_C, _keybd_event_Dart>("keybd_event");
    
    const MAPVK_VK_TO_VSC = 0;
    typedef _MapVirtualKeyW_C = Uint32 Function(Uint32 uCode, Uint32 uMapType);
    typedef _MapVirtualKeyW_Dart = int Function(int uCode, int uMapType);
    var MapVirtualKeyW = _user32.lookupFunction<_MapVirtualKeyW_C, _MapVirtualKeyW_Dart>("MapVirtualKeyW");
    
    
    void main() {
      keybd_event(
        0x5a, 
        MapVirtualKeyW(0x5a, MAPVK_VK_TO_VSC), 
        0, 
        nullptr);
    }
    

    PS: 此外,如果您需要 WinAPI 的更多功能,您可以使用我的quickly stitched together dart binding generator 来获取 WinAPI 功能。您只需运行它并将 WinAPI 函数粘贴到上部 textarea 中,底部区域应显示 dart 绑定。有时它缺少一些类型定义(只需添加另一种类型Mapping),但在大多数情况下它工作得很好:)(不适用于坚韧的结构)

    【讨论】:

    • 感谢您的提示,实际上我应该更新答案,我尝试使用正确的 28 字节结构,但没有奏效。我在 dart repo 中询问了help,但我不太明白我应该如何制作我的结构。最后,我使用了 mouse_event 和 keybd_event,它们工作得很好(here)。还要感谢绑定生成器,它可能会派上用场。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-28
    • 2013-02-25
    • 1970-01-01
    • 2013-03-21
    相关资源
    最近更新 更多