Introducing Dart | Windows

A suite of packages providing Windows Runtime, COM, and Win32 API support for Dart

Tim Sneath
4 min readMay 12, 2023

At any point in time, I normally have a variety of small experiments and hobby projects at various stages of development. As a product manager for developer frameworks or languages, it’s important to make time to explore and use your own product. While it’s dangerous to over-index on your own experiences, it’s also tough to truly empathize with your users if you haven’t walked a fair amount in their shoes.

For several years, I’ve been having fun with one side-project in particular, which combined my experience working on Windows and related technologies at Microsoft with my current focus on Dart and Flutter. The purpose of this project is to make it easy to do Windows programming with Dart, by exposing C-based Windows APIs to Dart.

I last wrote about this project a couple of years ago, when it was still at a fairly immature status, and then last year I gave a talk at Flutter Vikings about it. But it’s finally reached a point where the project has grown out of hobby project status, so it’s a good time to rebrand and reintroduce it.

A suite of Windows packages

Today I’m therefore delighted to introduce Dart | Windows, a suite of packages that provide projections for each of the various programming models available to Windows developers: Win32, COM and the modern Windows Runtime (also known as WinRT).

The base win32 package provides a low-level, API-compatible mapping of the core Win32 APIs. With this package, you can write Dart code that calls APIs ranging from simple MessageBox calls to networking, disk management, cryptography and window management. This package also includes many COM interfaces covering things like audio, sensors, spell checkers and WMI.

It’s not likely that the average Flutter developer will need to use this package directly; instead, they’ll typically use a higher-level package that provides a more idiomatic interface to this low-level functionality, and perhaps also includes implementations for other platforms. Indeed, there are tens of packages that are already written that use win32, thanks to kind volunteers who have invested in the Dart package ecosystem, including file pickers, biometric storage, console output, and share tools. The Dart | Windows suite also includes a number of such packages, including win32_gamepad and win32_registry.

Windows Runtime support

One contributor in particular has gone further and become a deep collaborator in this project over the last year or so. Halil Durmus has been quietly laboring away to improve my own haphazard efforts. As an actual professional developer, he has kindly invested a huge amount of time to fix bugs and improve readability in my own code. I’ve learned a great deal from him.

But beyond that, he’s extended my work on automatically generating support for COM APIs to build the next layer up: Windows Runtime support. WinRT was introduced in Windows 8 as a new API model for Windows development, and extends COM with many modern capabilities including generics, events, properties and asynchronous programming. With the Windows Runtime API, Windows finally gets a programming model that is accessible to a wide variety of languages.

The breadth of Halil’s work is extraordinary: he’s created layers of abstraction that convert WinRT primitives like IMap and HSTRING to Dart equivalents; he’s built well-tested generators that take Windows metadata and create Dart wrappers; and he’s written documentation that makes it all clear. At this point, the bulk of the credit belongs to him, not me.

The first version of this WinRT work is now available, and with it, you’ll find that you can write Windows code that looks like it was designed with Dart in mind. Here’s a simple example that retrieves geolocation from Windows:

import 'package:windows_devices/windows_devices.dart';

void main() async {
await Geolocator.requestAccessAsync();

final locator = Geolocator()..allowFallbackToConsentlessPositions();
final location = await locator.getGeopositionAsync();
if (location?.coordinate case final coordinate?) {
final position = coordinate.point?.position;
if (position case BasicGeoposition(:final latitude, :final longitude)) {
print('Current location: ($latitude, $longitude)');
} else {
print('Current location: N/A');
}
print('Location accuracy: ±${coordinate.accuracy} meters');
print('Current heading: ${coordinate.heading ?? 'N/A'}');
} else {
print('No location received.');
}
}

Using Dart 3 pattern matching, this code gets coordinate information and destructures it into latitude and longitude measurements. While there are a few more nulls than you might expect if this were powered by Dart code all the way down, it doesn’t take a Windows expert to write code like this (yay!).

Over time, I expect that the original win32 package will take a backseat to this more friendly approach to Windows development. I’m so excited by the work Halil has done, because I think this opens the door for many more packages to support Windows, and for a world where serious Windows apps can be built with Flutter without requiring any C++ knowledge.

Getting started with Dart | Windows

A blog isn’t a good medium for evergreen learning materials, so instead interested readers should consult the Dart | Windows website or visit the GitHub organization where we’re collating various packages and information.

We’d love to have more folk join us on the journey: particularly those with existing Windows experience. You can contribute examples or tests; update existing packages at pub.dev to support Windows; convert packages with C++ plugin implementations to native Dart replacements; or provide feedback on gaps that need filling. Come have fun with Dart | Windows!

--

--

Tim Sneath
Tim Sneath

Written by Tim Sneath

Director for Developer Tools and Frameworks at Apple. I used to run Flutter and Dart at Google.