首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用dart:ffi实现winapi(SendInput)

使用dart:ffi实现winapi(SendInput)
EN

Stack Overflow用户
提问于 2019-12-16 22:42:47
回答 1查看 301关注 0票数 0

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

代码语言:javascript
复制
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,例如,此代码不发送鼠标输入。

代码语言:javascript
复制
  var mi = MouseInput.allocate(dx: 505, dy: 175, dwFlags: 0x0002);
  var r = SendInput(0, mi: mi);

下面是函数在C++中的外观

代码语言:javascript
复制
    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 ),但我想知道在联合得到支持之前是否有解决方法。

EN

回答 1

Stack Overflow用户

发布于 2020-01-01 16:54:34

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

代码语言:javascript
复制
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语言中它可以很好地工作)。这可能是dart FFI本身的一个bug,但也可以是很多其他东西。我正在尝试破解它,因为我也需要它来工作。

现在,您可以使用刚刚生效的弃用函数:

代码语言:javascript
复制
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);
}

另外,如果你需要来自WinAPI的更多函数,你可以使用我的quickly stitched together dart binding generator来实现WinAPI函数。您只需运行它并将WinAPI函数粘贴到上面的文本区,底部区域应该会显示dart绑定。有时它缺少一些类型定义(只需添加另一个类型Mapping),但在大多数情况下,它工作得很好:) (不适用于structs tough)

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59358895

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档