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.
- 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, andARRAY - Method filtering — generate only the methods you need with include/exclude patterns
go generatefriendly — designed to run as a//go:generatedirective- Pure Go — uses
syscall.SyscallNwith a built-inwinrtpackage, 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
goimportsandgo/format
go install github.com/zandercodes/gowinrt/cmd/gowinrt@latestGenerate bindings for a WinRT class:
gowinrt -c Windows.Foundation.DeferralWith inheritance (adds wrapper methods for parent interfaces):
gowinrt -c "Windows.Foundation.IAsyncOperation`1" --inheritanceWith method filtering:
gowinrt -c Windows.Storage.Streams.DataReader \
-f FromBuffer -f ReadBytes -f '!*'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`1Then run:
go generate ./...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
| 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.
| 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 |
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
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}"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 tounsafe.PointerSZARRAY— Single-dimensional arraysBYREF— Pass-by-reference parametersARRAY— Multi-dimensional arrays
Templates use Go's text/template with custom functions:
| Function | Description |
|---|---|
funcName |
Converts WinRT method names (get_X → GetX, put_X → SetX) |
concat |
Merges parameter slices for iteration |
dict |
Creates a map from key-value pairs for template data passing |
toLower |
Lowercases first character |
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
}- Receive-array out-parameters — WinRT methods that use the "receive array" pattern (
BYREF SZARRAYwithOutflag, 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.
| 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) |
This project based on the excellent work of winrt-go by Salto Systems, reimplemented with Microsoft's official go-winmd metadata library.
This project is licensed under the GNU General Public License v3.0.
Portions derived from winrt-go by Salto Systems (MIT License).