「这是我参与11月更文挑战的第28天,活动详情查看:2021最后一次更文挑战」。
本文翻译自 win32 | Dart Package (pub.dev)。
本文所有图片均来自于该链接。
上学的时候没好好学,原来 Windows API 很值得深入学习。
该包包装了对一些常用 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 来列举所有本地安装的字体:
或者访问不通过 Dart 框架库暴露的系统信息:
也可以使用该包来用 Flutter 构建一个依赖 Win32 API 的 Windows 应用。
甚至可以用来构建一个传统的 Win32 应用,用纯 Dart 开发。这个是直接从经典的 Charles Petzold的《Programming Windows 应用》来的:
或者甚至是一个使用 GDI 的完全成熟的游戏:
甚至可以构建一个基于该包的包,如:dart_console,构建了一个高级的命令行控制台。
或者 filepicker_windows,为 Flutter 提供了一个现代的 Windows 文件选取器。
开始
更多的示例可以在 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 信息 |
notepad | Windows 记事本小程序的轻量级副本 |
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。