c++ - 使用 dart:ffi 实现 winapi(SendInput)
问题描述
我正在尝试使用 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 版本相同的大小(即 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;
}
话虽如此 - 它仍然不起作用,我真的不知道为什么。我什至尝试过只传递原始字节数组指针,它在 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 的更多功能,您可以使用我的快速拼接飞镖绑定生成器来获取 WinAPI 功能。您只需运行它并将 WinAPI 函数粘贴到上部 textarea 中,底部区域应显示 dart 绑定。有时它缺少一些类型定义(只需添加另一种类型Mapping
),但在大多数情况下它工作得很好:)(不适用于结构强硬)
推荐阅读
- chilkat-email - Chilkat:如何检查给定电子邮件的回复 - Original-Envelope-Id
- java - 方法 org/hibernate/cache/ehcache/EhCacheRegionFactory.start(Lorg/hibernate/boot/spi/SessionFactoryOptions;Ljava/util/Map;)V 是抽象的
- c# - VAL和Transform的结合与visual fox pro到c#的转换
- oracle - 使用 oracle Web 服务测试客户端时 SOAP 请求失败
- javascript - 将坐标数组转换为多边形 react-leaflet 并获取它的边界
- python - 如何从保存的 xgboost 模型中替换参数?
- apache-kafka - 如何收听通用 Kafka 消费者
- reactjs - 将类组件转换为功能组件
- c++ - 如何修复“架构 x86_64 的未定义符号:”C++ 编译器错误?
- python - 所有可能对的整数 RDD(有序)