Skip to content

zandercodes/gowinrt

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

gowinrt

A Go code generator for Windows Runtime (WinRT) APIs. Generate type-safe Go bindings from WinRT metadata (.winmd) files and call Windows APIs directly from Go — no CGo required.

Built on go-winmd — Microsoft's official Go library for reading ECMA-335 / WinRT metadata.

Features

  • Full WinRT type support — interfaces, classes, enums, structs, and delegates
  • Interface inheritance — inherited methods are generated as convenient wrappers using QueryInterface
  • Generic types — custom ECMA-335 signature parser handles GENERICINST, VAR, MVAR, SZARRAY, BYREF, and ARRAY
  • Method filtering — generate only the methods you need with include/exclude patterns
  • go generate friendly — designed to run as a //go:generate directive
  • Pure Go — uses syscall.SyscallN with a built-in winrt package, no CGo or external COM dependencies
  • Parameterized GUIDs — runtime helper to compute GUIDs for generic WinRT types (RFC 4122 v5)
  • Formatted output — generated code is automatically processed by goimports and go/format

Installation

go install github.com/zandercodes/gowinrt/cmd/gowinrt@latest

Quick Start

Generate bindings for a WinRT class:

gowinrt -c Windows.Foundation.Deferral

With inheritance (adds wrapper methods for parent interfaces):

gowinrt -c "Windows.Foundation.IAsyncOperation`1" --inheritance

With method filtering:

gowinrt -c Windows.Storage.Streams.DataReader \
  -f FromBuffer -f ReadBytes -f '!*'

Using go generate

Add directives to any Go file:

//go:generate gowinrt -c Windows.Foundation.IClosable
//go:generate gowinrt -c "Windows.Foundation.IAsyncOperation`1" --inheritance
//go:generate gowinrt -c Windows.Foundation.Deferral
//go:generate gowinrt -c Windows.Foundation.Collections.IVector`1

Then run:

go generate ./...

CLI Reference

Usage:
  gowinrt [flags]

Flags:
  -c, --class string             WinRT class to generate (e.g. Windows.Foundation.Uri)
  -f, --method-filter strings    Filter methods (e.g. -f GetResults -f '!*')
  -i, --inheritance              Include inherited interface methods as wrappers
  -V, --validate                 Validate generated files match without writing
  -v, --verbose                  Enable debug output
  -h, --help                     Show help

Method Filter Syntax

Pattern Meaning
MethodName Include this method
!MethodName Exclude this method
!* Exclude all remaining (use after includes)

Methods are evaluated in order. Use -f GetResults -f Close -f '!*' to generate only GetResults and Close.

Supported WinRT Types

Type Template Description
Interface interface.tmpl VTable struct, method implementations, inherited wrappers
Class class.tmpl Runtime class with constructor, implemented + exclusive interfaces
Enum enum.tmpl Typed integer constants
Struct struct.tmpl Value types with fields
Delegate delegate.tmpl Callback types with VTable and ref counting

Architecture

cmd/gowinrt/          CLI entry point
winrt/                WinRT runtime types (IUnknown, IInspectable, GUID, HString, 
│                       parameterized GUID computation, type signature constants)
tests/                All tests (generation, runtime, GUID)
internal/
├─ cli/              Cobra command setup
├─ delegate/         Delegate callback registration
├─ emit/             Template rendering & file output
├─ gen/              Template engine & template files
├─ ir/               Intermediate representation types
├─ kernel32/         Heap allocation for delegate VTables
├─ logger/           Logging setup
├─ mapgo/            Go import path computation
├─ metadata/         WinRT metadata store (wraps go-winmd)
└─ resolve/          Type resolution, naming, filtering, signature parsing
windows/              Generated WinRT bindings

Parameterized GUIDs

Generic WinRT types (e.g. IAsyncOperation<T>) don't have a fixed GUID — it must be computed at runtime from the base GUID and the type arguments' signatures. The winrt package implements this per the WinRT type system spec:

import "github.com/zandercodes/gowinrt/winrt"

// TypedEventHandler<Watcher, ReceivedEventArgs>
guid := winrt.ParameterizedInstanceGUID(
    "9de1c534-6ae1-11e0-84e1-18a905bcc53f",
    "rc(Windows.Devices.Bluetooth.Advertisement.BluetoothLEAdvertisementWatcher;{a6ac336f-f3d3-4297-8d6c-c81ea6623f40})",
    "rc(Windows.Devices.Bluetooth.Advertisement.BluetoothLEAdvertisementReceivedEventArgs;{27987ddf-e596-41be-8d43-9e6731d4a913})",
)
// guid == "{90EB4ECA-D465-5EA0-A61C-033C8C5ECEF2}"

Signature Parser

WinRT metadata encodes method signatures as ECMA-335 blobs. The built-in go-winmd parser does not yet support generic instantiations (GENERICINST). gowinrt includes a custom signature parser (sigparse.go) that handles:

  • GENERICINST — Generic type instantiations (e.g. IAsyncOperation<T>)
  • VAR / MVAR — Generic type/method parameters → mapped to unsafe.Pointer
  • SZARRAY — Single-dimensional arrays
  • BYREF — Pass-by-reference parameters
  • ARRAY — Multi-dimensional arrays

Template System

Templates use Go's text/template with custom functions:

Function Description
funcName Converts WinRT method names (get_XGetX, put_XSetX)
concat Merges parameter slices for iteration
dict Creates a map from key-value pairs for template data passing
toLower Lowercases first character

Example Output

Running gowinrt -c Windows.Foundation.IClosable generates:

// Code generated by gowinrt. DO NOT EDIT.

//go:build windows

package foundation

import (
    "syscall"
    "unsafe"

    "github.com/zandercodes/gowinrt/winrt"
)

const GUIDIClosable string = "30d5a829-7fa4-4026-83bb-d75bae4ea99c"
const SignatureIClosable string = "{30d5a829-7fa4-4026-83bb-d75bae4ea99c}"

type IClosable struct {
    winrt.IInspectable
}

type IClosableVtbl struct {
    winrt.IInspectableVtbl
    Close uintptr
}

func (v *IClosable) VTable() *IClosableVtbl {
    return (*IClosableVtbl)(unsafe.Pointer(v.RawVTable))
}

func (v *IClosable) Close() error {
    hr, _, _ := syscall.SyscallN(
        v.VTable().Close,
        uintptr(unsafe.Pointer(v)),
    )
    if hr != 0 {
        return winrt.NewError(hr)
    }
    return nil
}

Known Limitations

  • Receive-array out-parameters — WinRT methods that use the "receive array" pattern (BYREF SZARRAY with Out flag, e.g. IPropertyValue.GetUInt8Array) are not yet implemented. The VTable entries are generated to preserve correct interface layout, but no Go wrapper is emitted. The generator logs a warning for each skipped method.

Dependencies

Package Purpose
go-winmd ECMA-335 metadata reader
cobra CLI framework
zerolog Structured logging
x/tools goimports for import cleanup
x/sys Windows DLL loading (combase.dll)

Credits

This project based on the excellent work of winrt-go by Salto Systems, reimplemented with Microsoft's official go-winmd metadata library.

License

This project is licensed under the GNU General Public License v3.0.

Portions derived from winrt-go by Salto Systems (MIT License).

About

A Go code generator for Windows Runtime (WinRT) APIs.

Resources

License

Stars

Watchers

Forks

Contributors