[译]Dart&Flutter调用win32 API的库win32

4,949 阅读6分钟

「这是我参与11月更文挑战的第28天,活动详情查看:2021最后一次更文挑战」。

本文翻译自 win32 | Dart Package (pub.dev)
本文所有图片均来自于该链接。

上学的时候没好好学,原来 Windows API 很值得深入学习。


image.png

该包包装了对一些常用 Win32 API 的调用。通过 FFI 使其可以访问 Dart Code 而不需要引入 C 编译器或 Windows SDK。

除了暴露 API 本身之外,该包还提供了多种有用的示例用于更复杂的 FFI 使用场景。

该包有意地提供了一个对 Win32 API 最小的更改以支持 Dart 风格。 目标是为现在的 Win32 开发者提供一个高度熟悉的感觉。 其它的 Dart 包可能在原始 API 基础上构建以提供一个对于 Dart&Flutter 开发者友好的 API。 一个很好的例子是 filepicker_windows,提供了一个通用的项目对话框,适合融入现有的 Flutter 应用。

使用

该包可以用来编写从 Dart 中直接使用 Windows API 的应用,通过使用 Dart FFI 来包装常用的 Win32 API 、 COM 和 Windows Runtime API 。

可以使用该包来调用一个 Win32 API 如 EnumFontFamiliesEx 来列举所有本地安装的字体:

image.png

或者访问不通过 Dart 框架库暴露的系统信息:

image.png

也可以使用该包来用 Flutter 构建一个依赖 Win32 API 的 Windows 应用。

image.png

甚至可以用来构建一个传统的 Win32 应用,用纯 Dart 开发。这个是直接从经典的 Charles Petzold的《Programming Windows 应用》来的:

image.png

或者甚至是一个使用 GDI 的完全成熟的游戏:

image.png

甚至可以构建一个基于该包的包,如:dart_console,构建了一个高级的命令行控制台。

image.png

或者 filepicker_windows,为 Flutter 提供了一个现代的 Windows 文件选取器。

image.png

开始

更多的示例可以在 example\ 子目录中找到,和 test\ 子目录的测试套件(展示了一些其它 API 的调用)一起。

一个好的开始点是 hello.dart。这个示例演示了创建一个 Win32 窗口和响应通用消息。如通过 WindowProc 回调函数的 WM_PAINT 消息。

要运行它,输入:

dart example\hello.dart

这会显示一个带文本信息的窗口。

这可以编译成一个单独的 Win32 可执行文件,运行下面的命令:

dart compile exe example\hello.dart -o example\bin\hello.exe

更多的从 Dart 中使用 Win32 库的信息,查阅一下文档。 特别是 字符串操作 和 COM 对象 的部分。

示例

Dart 示例

example\ 子目录包含了许多示例。这些示例使用了 Win32 API 来显示 UI ,不需要 Flutter 。

示例说明
hello.dart基本的 Petzoldian Win32 应用 "hello world"
bluetooth.dart演示列举蓝牙设备
calendar.dart从 WinRT API 获取日历信息
console.dart展示控制台 API 的用法
credentials.dart添加一个商店的证书然后获取它
customwin.dart显示一个非矩形的窗口
devices.dart使用(磁盘)卷管理 API 列出所有的磁盘设备
dialog.dart用代码创建一个自定义对话框
dialogshow.dart使用 COM 创建一个通用项目对话框(文件选取器)
diskinfo.dart使用 DeviceIoControl() 直接进行设备操作
dump.dart使用调试库来打印 DLL 导出的函数
dynamic_load.dart演示加载一个 DLL 和在运行时调用这个 DLL
filever.dart从文件源获取文件版本信息
guid.dart创建一个全局唯一标识 (GUID)
idispatch.dart演示使用 IDispatch 调用一个方法
knownfolder.dart从当前用户资料中获取已知的文件夹
magnifier.dart使用放大 API 来提供一个放大镜窗口
manifest演示编译后程序的应用清单的使用
midi.dart演示使用 MCI 命令重放 MIDI
modules.dart列举当前系统中加载的所有模块
monitor.dart使用 DDC 和 monitor-config API 来获取显示器指标
msgbox.dart演示控制台的 MessageBox 信息
notepadWindows 记事本小程序的轻量级副本
paint.dart演示简单的 GDI 绘制和最小化/最大化 窗口
pipe.dart展示跨进程通信的命名管道
play_sound.dart使用 Windows 的Plays PlaySound API 播放一个 WAV 文件
printer_list.dart列举 Windows 系统中可用的打印机
registry.dart演示在注册表中查询值
screenshot.dart对当前桌面屏幕截图
scroll.dart带水平滚动条和垂直滚动条的文件窗口
sendinput.dart向另外一个窗口发送键盘和鼠标
serial.dart演示串口管理
shortcut.dart演示创建一个 Windows Shell 链接
snake.dart使用各种 GDI 特性的贪吃蛇游戏
sysinfo.dart使用原生 C API 获取设备信息的示例
taskdialog.dart演示使用现代的任务对话框
tetris\main.dart用于 Dart 的开源俄罗斯方块游戏 的载入口
vt.dart展示虚拟终端序列
wallpaper.dart展示设置的墙纸和背景
window.dart列举打开的窗口和基本的窗口操作
winmd.dart问询窗口运行时类型
wmi.dart使用 WMI 从 COM 获取 设备/OS 信息

Flutter 示例

example 子目录中包含一个简单的 Flutter 应用,它使用了 Win32 API 的(磁盘)卷管理来查找连接电脑的磁盘驱动,还有它们的 ID 和 绑定路径。

必要条件

该包采用 Windows 上运行的 Dart 64-位 编译器。很多命令是在32位 Windows 上测试,但是因为缺少对32位可执行文件的编译器,也缺少运行32位操作系统的机器(这个必然低优先度)。这个包也可以在 Windows-on-ARM 架构上测试,以x64的模拟模式运行。

特性和 BUG

现在的包计划是一个 Win32 API 的子集,但是新的 API 会根据用户需要添加。我对解锁 Windows 的插件特别感兴趣。请在 issue tracker 递交特性请求和 BUG。

向后兼容

库版本使用语义化版本,但是不需要采取对小版本的非破坏性改动的严格保证。 这个保证不太现实,有以下几个原因:

  • 为了 Win32 API 的精确使用,多次修复BUG已经收紧了对参数的约束(例如:Pointer 变为 Pointer<INPUT>))。这些改动在 log 中会有体现。

  • 添加新特性可能会引起破坏性的变动。例如:如果在你自己的代码中声明了一个缺失的 Windows 常量,然后添加了它,Dart 会抱怨这样完全重复的定义。

一个解决方案是锁定到一个指定的 Win32 版本,或者声明一个更窄范围的版本依赖(例如:'>=1.7.0 <1.8.0' 而不只是 ^1.7.0)。但是最好的方式是简单地用该包的最新版本进行常规测试,然后继续进行最小的改动。随着该包的成熟,这些问题会逐渐消失。

致谢

上面列出的俄罗斯方块游戏是一个更完整的示例,使用 Dart Win32 包的完成度非常高的程序。它载入 C 版本的游戏。 C 版本由 Chang-Hung Liang 开发。更多信息

贪吃蛇的 C 实现 由 David Jones,使用经过他的允许。

记事本示例的原始 C 版本由 Charles Petzold 授权,他友好地许可我们且没有任何限制。

Win32 API 汇总文档的注释 由 Microsoft 许可 基于 Creative Commons Attribution 4.0 International Public License