Skip to content

Repository files navigation

dynwinrt

Call any Windows Runtime (WinRT) API from JavaScript or TypeScript — without writing a native addon.

@microsoft/dynwinrt @microsoft/dynwinrt-codegen License: MIT

Why dynwinrt?

If you've ever tried to call a modern Windows API (WinAppSDK, Windows AI, notifications, file pickers, sensors, …) from an Electron, Node, or Python app, you've probably hit one of these walls:

  • Writing a C++ node-addon-api addon — needs node-gyp, MSVC, Python, the matching Windows SDK, and a CI matrix per Electron version.
  • Writing a C# addon via node-api-dotnet — needs the .NET SDK, a csproj build step, and a hand-maintained wrapper for every API surface you want to expose.
  • Waiting for an official projection — Windows ships .winmd metadata months before any JavaScript- or Python-friendly projection appears in a published package.

dynwinrt removes all of that. It reads the same .winmd metadata your Windows SDK / WinAppSDK NuGet packages already ship and calls the underlying COM vtables dynamically at runtime via libffi. The codegen emits typed .js + .d.ts wrappers; the runtime invokes them through dynwinrt's native binary. No MSBuild step in your app, no node-gyp, no per-Windows-version recompile.

import { LanguageModel } from './bindings/winrt';

const model = await LanguageModel.createAsync();
const result = await model.generateResponseAsync('Tell me a joke');
console.log(result.text);

That's the whole story: install, generate, import, call.

Scopedynwinrt primarily targets data-style WinRT APIs. WinUI Application + Window hosting is also supported on a caller-managed STA UI thread; the application remains responsible for package identity and lifecycle.

Quick start

npm install @microsoft/dynwinrt
npm install -D @microsoft/dynwinrt-codegen

# Generate a binding for one class (auto-detects the Windows SDK winmd)
npx dynwinrt-codegen generate \
  --namespace Windows.Foundation \
  --class-name Uri \
  --output ./generated
const { roInitialize } = require('@microsoft/dynwinrt');
const { Uri } = require('./generated');

roInitialize(1);                                       // MTA
const uri = new Uri('https://example.com/path?q=1');
console.log(uri.host);                                 // "example.com"

Classic COM bindings import their runtime API from the separate @microsoft/dynwinrt/com subpath. It is part of the same npm package; the package root remains the WinRT-only API. See Classic COM support for the supported ABI, common-interface test matrix, unsupported native types, and ownership rules.

Generated bindings project unambiguous public WinRT activation metadata as JavaScript constructors, including overloads such as new Uri(base, relative). Existing static factory methods remain available. Classes that can only be returned by the system, or that expose only protected composition, remain non-constructible. Bindings also include async + progress support, generic collections (IVector<T>, IMap<K,V>), structs, enums, and delegates — see tools/dynwinrt-codegen/npm/README.md for the full feature list.

WinUI Application + Window

When Microsoft.UI.Xaml.Application is selected, JavaScript codegen also emits XamlControlsXamlMetaDataProvider and XamlControlsResources. Use the generated helper to compose the application outer, register WinUI metadata, and install the default Fluent resources before creating controls:

const { initWinappsdk, roInitialize } = require('@microsoft/dynwinrt');
const { Application, Button, Window } = require('./generated');

initWinappsdk(2, 2);
roInitialize(0); // STA

async function main() {
  let app;
  await Application.startScheduled(() => {
    app = Application.create(() => {
      const window = new Window();
      window.content = new Button();
      window.activate();
    });
    app.requestedTheme = 1; // Dark
  });
}

main().catch(console.error);

Application.startScheduled() enters the WinUI dispatcher loop after the current JavaScript callback unwinds and resolves when the application exits. This keeps WinUI async completions and JavaScript Promise checkpoints working while XAML owns the thread. Application.start() remains available when the exact blocking WinRT call is required, but it pauses the Node event loop.

In an unpackaged process, set WINAPPSDK_BOOTSTRAP_DLL_PATH to the architecture-matched Microsoft.WindowsAppRuntime.Bootstrap.dll before calling initWinappsdk(). Application.create() resolves the bootstrapped framework resources and configures its UI thread for Per-Monitor V2 DPI awareness. Packaged processes can omit the bootstrap call.

Repository layout

dynwinrt/
├── crates/dynwinrt/          # Core Rust runtime (FFI, metadata, async, delegates, collections)
├── bindings/
│   ├── js/                   # @microsoft/dynwinrt — JS / TS bindings (napi-rs)
│   └── py/                   # Python bindings (PyO3, experimental — not published)
├── tools/
│   └── dynwinrt-codegen/     # @microsoft/dynwinrt-codegen — typed-binding generator
├── tests/                    # Integration tests + sample E2E projects
└── bench-electron/           # Electron benchmark app

Build from source

# Core library
cargo build -p dynwinrt
cargo test  -p dynwinrt

# JS bindings (napi-rs)
cd bindings/js && npm install && npm run build

# Python bindings (PyO3 + maturin) — experimental, not published to PyPI
cd bindings/py && maturin develop && pytest

# Codegen tool
cargo build -p dynwinrt-codegen --release
cargo run   -p dynwinrt-codegen -- generate --namespace Windows.Foundation --class-name Uri --output ./generated

Python runtime, codegen, packaging, and WinUI readiness are tracked in PYTHON_CHECKLIST.md.

Codegen CLI reference

Argument Required Description
--winmd PATH[;PATH...] No Path to .winmd file(s) (auto-detects Windows SDK if omitted)
--folder PATH No Directory containing .winmd files
--namespace NAMESPACE No WinRT namespace to generate (omit for all non-Windows.* namespaces)
--class-name CLASS No Specific class (transitively pulls in dependencies)
--ref PATH No Additional .winmd files for type resolution only (no code emitted)
--lang LANG No js (default, emits .js + .d.ts) or py (emits .py + .pyi and py.typed)
--no-pyi No With --lang py, emit implementation files without type stubs
--output DIR No Output directory (default ./generated)
--dry-run No Validate input, don't write files

For each WinRT class the codegen emits a typed wrapper, factory, interface registration, async + progress support, generic collections, structs, enums, delegates, and an index.js / index.d.ts that re-exports every emitted symbol.

Local development — fix import paths in generated files

Generated files import from '@microsoft/dynwinrt'. When iterating against a locally-built runtime, rewrite imports to the relative path:

find generated -name "*.js" -exec sed -i "s|from '@microsoft/dynwinrt'|from '../../dist/winrt.js'|g" {} +

Troubleshooting

Problem Solution
cargo build fails with libffi errors Ensure you have a C compiler (MSVC) and the Windows SDK installed
cargo test -p dynwinrt fails Windows SDK must be installed at the default path with Windows.winmd
JS bindings won't build Run npm install first; requires Node.js 18+
Python bindings won't build Requires Python 3.8+ and maturin (pip install maturin)
Codegen snapshot tests fail Line-ending differences — run cargo test -p dynwinrt-codegen -- --include-ignored to regenerate

Contributing

This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.

When you submit a pull request, a CLA bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA.

This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments.

Trademarks

This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks or logos is subject to and must follow Microsoft's Trademark & Brand Guidelines. Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos are subject to those third-party's policies.

License

This project is licensed under the MIT License.

About

Use WinRT methods dynamically

Resources

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages