Using Windows Runtime from Swift

I thought that people here might care about this little demo:
compnerd/SwiftWinRT: WinRT Bridging for Swift (github.com)

It shows how we could possibly bridge the Windows Runtime into Swift. Having a quick peek at the generated assembly shows that in release mode, it should be largely what we want:

if (this)
  if (SUCCEEDED(<virtual dispatch>))
    return;
return Error;

With this work, the entire modern Windows aspects (UWP, WinUI, WinRT, Xaml) can now be exposed to Swift, and done so largely with performance close to C++. There definitely is a fair amount of work left here, but there is now some light on the path that will provide the foundations for access to the full Windows API surface, with the ability to immediately gain access to future APIs as well.

Saleem

There is some additional follow up work that I intend to put up soon that will show how this actually provides truly first class Windows development

47 Likes

Cool!

It can't be understated how important this is to continue to expand swift's adoption as a general purpose language. Thank you so much for your efforts :pray:

6 Likes

Awesome, that’s great news!

I’d love to see a Swift DSL for WinUI. This is getting really exciting!

3 Likes

I've been working on a way to generate Swift/WinRT bindings from WinMD files, building on the (really cool) work @compnerd did in the demo repo posted above.

To have a look, see my fork of his repo:

In general, except for the now-automatically-generated parts, I've tried to keep the original repo unchanged.

Overall, I've made some decent progress. I can generate much of the WinRT API surface (but I currently don't, because swift build cannot cope with the size, grumble). No support for parameterized interfaces yet, so that's a big missing piece yet to be done. The original two samples work, and I added another sample that displays a toast notification.

A bit more detail is explained in the README file of the fork.

2 Likes

Have you looked at GitHub - compnerd/swift-winmd: Windows Metadata Parser in Swift? That is likely meant to go in the same direction (in the sense, that it is meant to autogenerate the interfaces and eventually become a swift-package-manager plugin to generate the bindings as appropriate for the project).

The idea of generating the interfaces is really the desired thing, and that is pretty cool that you have managed to accomplish that. I will have to take a look at that :slight_smile:

1 Like

Yes, I had seen your winmd parser project, but I already had the parsing code, so I just used what was already working for me. My generator is just a different form of output from the same project where I generate Swift bindings for dotnet assemblies.

I haven't explored the idea of a swift-package-manager plugin, but that would be an interesting approach. I need to investigate what kind of info is available to the plugin.

Thanks for the reply, and thanks also for blazing the trail toward Swift development on Windows. Any feedback to have on the generator output in my fork would be welcomed.

1 Like

Update: I've been making steady progress on bridging WinRT things to Swift. There are several working samples in my repo (mentioned in a comment above), including a port of a Win2D game, and a simple RPN-style calculator using WinUI.

Highlights described in a blog entry I just posted:

https://ericsink.com/entries/swift_winrt_preview.html

9 Likes

Your works are really amazing and inspiring!

One thing I’m wondering is if we can create a plugin to automatically generate the binding. That’s a natural way many projects are now adopting to unlock more power.

Thanks for your kind words.

I do like the idea of generating the bindings in a SwiftPM plugin, but aside from some basic investigation, I haven't really started pursuing that approach yet. So far I've just been focused on basic functionality.

I've encountered quite a few tricky issues around the generation of the bindings. One of the biggest one, which I mentioned in my blog entry, is that it is easy to end up with DLLs that fail to link because they have too many symbols.

A primary appeal of a SwiftPM plugin is the possibility of generating only those bindings which are needed by the project. Of course, there is the question of how we determine which bindings are needed. We could have a config file for the user to specify them, which sounds tedious and unfriendly. Or we could somehow scan the project code and figure it out, which sounds potentially inaccurate. Maybe we need a combination of both -- scan and guess, plus a config file as a fallback plan for edge cases.

1 Like

I've been investigating this. I refactored some things to be more compatible with the plugin approach, and in general, I like where that path seems to be going. However, I've run into two classes of problems:

  1. build tool plugins don't work on Windows yet. I've been logging bugs, and those bugs are getting fixed (thanks @compnerd), so this is a temporary problem.
  2. The bigger issue is that build tool plugins apparently don't work with C, and I am currently generating the vtables and structure definitions as a C header file. I will either need swiftpm to support this case, or I need to redo this bit to generate all that stuff in Swift. :slightly_frowning_face:
1 Like

AFAICT, the only supported way to define a C function pointer with a parameter that is a pointer to a struct is to define it in C and import it. Given a struct called Foo, something like @convention(c) (UnsafeMutablePointer<Foo>) -> Int is not allowed unless the C import code produced it.

That probably means generated bindings with a build tool plugin are blocked until swiftpm supports build tool plugins with C.

1 Like