{"id":1230,"date":"2026-07-27T07:19:41","date_gmt":"2026-07-27T14:19:41","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/ifdef-windows\/?p=1230"},"modified":"2026-07-27T11:52:38","modified_gmt":"2026-07-27T18:52:38","slug":"a-new-way-to-bring-native-windows-apis-to-javascript-introducing-dynamic-api-projections-for-node-js","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/ifdef-windows\/a-new-way-to-bring-native-windows-apis-to-javascript-introducing-dynamic-api-projections-for-node-js\/","title":{"rendered":"A new way to bring native Windows APIs to JavaScript &#8211; introducing dynamic API projections for Node.js"},"content":{"rendered":"<div>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/ifdef-windows\/wp-content\/uploads\/sites\/61\/2026\/07\/blog-banner-5.webp\"><img decoding=\"async\" class=\" wp-image-1357\" src=\"https:\/\/devblogs.microsoft.com\/ifdef-windows\/wp-content\/uploads\/sites\/61\/2026\/07\/blog-banner-5-300x158.webp\" alt=\"Dynamic Windows Runtime APIs for Node.JS\" width=\"1124\" height=\"592\" srcset=\"https:\/\/devblogs.microsoft.com\/ifdef-windows\/wp-content\/uploads\/sites\/61\/2026\/07\/blog-banner-5-300x158.webp 300w, https:\/\/devblogs.microsoft.com\/ifdef-windows\/wp-content\/uploads\/sites\/61\/2026\/07\/blog-banner-5-1024x538.webp 1024w, https:\/\/devblogs.microsoft.com\/ifdef-windows\/wp-content\/uploads\/sites\/61\/2026\/07\/blog-banner-5-768x404.webp 768w, https:\/\/devblogs.microsoft.com\/ifdef-windows\/wp-content\/uploads\/sites\/61\/2026\/07\/blog-banner-5.webp 1202w\" sizes=\"(max-width: 1124px) 100vw, 1124px\" \/><\/a><\/p>\n<p>Electron and Node.js make it straightforward to build Windows desktop apps in JavaScript. Calling Windows Runtime APIs has been less straightforward: features such as on-device AI often required a C++ or C# bridge, manual translation of WinRT types and asynchronous behavior, and wrapper code for every exposed API. That meant another language and toolchain to build, test, and keep compatible with Electron.<\/p>\n<p>We&#8217;re making\u00a0<strong>a dynamic Windows Runtime API (WinRT) projection for Node.js<\/strong>\u00a0available in public preview. It lets an Electron app or plain Node.js process call supported Windows Runtime APIs directly from JavaScript or TypeScript. Start with one npm package; the tooling generates JavaScript wrappers and TypeScript declarations for the Windows features you choose. No app-specific native addon,\u00a0<code>node-gyp<\/code>\u00a0setup, or C++ wrapper is required.<\/p>\n<\/div>\n<div>\n<div>\n<h2 id=\"what-makes-this-projection-different\" class=\"code-line\" dir=\"auto\" data-line=\"8\">What makes this projection different<\/h2>\n<\/div>\n<div>\n<div>\n<hr \/>\n<\/div>\n<div>\n<p class=\"code-line\" dir=\"auto\" data-line=\"10\">The Windows Runtime already has static language projections for\u00a0<a href=\"https:\/\/github.com\/microsoft\/cppwinrt\" data-href=\"https:\/\/github.com\/microsoft\/cppwinrt\">C++\/WinRT<\/a>,\u00a0<a href=\"https:\/\/github.com\/microsoft\/cswinrt\" data-href=\"https:\/\/github.com\/microsoft\/cswinrt\">C#\/WinRT<\/a>,\u00a0<a href=\"https:\/\/github.com\/microsoft\/windows-rs\" data-href=\"https:\/\/github.com\/microsoft\/windows-rs\"><code>windows-rs<\/code><\/a>, and\u00a0<a href=\"https:\/\/github.com\/pywinrt\/pywinrt\" data-href=\"https:\/\/github.com\/pywinrt\/pywinrt\">PyWinRT<\/a>. This projection brings the same model to the\u00a0<strong>Node.js runtime but<\/strong>\u00a0generates JavaScript instead of a native binding for each API. A shared runtime dispatches the calls, and compatible APIs can be added by rerunning generation against their metadata.<\/p>\n<ul class=\"code-line\" dir=\"auto\" data-line=\"12\">\n<li class=\"code-line\" dir=\"auto\" data-line=\"12\"><strong>Generated JavaScript wrappers, not per-class native addons.<\/strong>\u00a0Codegen produces\u00a0<code>.js<\/code>\u00a0wrappers and\u00a0<code>.d.ts<\/code>\u00a0declarations for supported Windows Runtime API patterns.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"13\"><strong>One shared prebuilt runtime.<\/strong>\u00a0<code>@microsoft\/dynwinrt<\/code>, installed from npm, dispatches all the calls at execution time.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"14\"><strong>Regenerate, don&#8217;t rebuild.<\/strong>\u00a0When compatible Windows API metadata changes, rerun codegen instead of rebuilding or waiting for a hand-authored wrapper.<\/li>\n<\/ul>\n<\/div>\n<h2 id=\"what-you-can-build-with-the-projection\" class=\"code-line\" dir=\"auto\" data-line=\"16\">What you can build with the projection<\/h2>\n<hr \/>\n<p class=\"code-line\" dir=\"auto\" data-line=\"18\">The generator reads Windows metadata (<code>.winmd<\/code>) rather than relying on a fixed API catalog. Supported non-UI APIs include:<\/p>\n<ul class=\"code-line\" dir=\"auto\" data-line=\"20\">\n<li class=\"code-line\" dir=\"auto\" data-line=\"20\"><strong><a href=\"https:\/\/github.com\/microsoft\/electron-on-windows-gallery\" data-href=\"https:\/\/github.com\/microsoft\/electron-on-windows-gallery\">On-device AI<\/a>:<\/strong>\u00a0text generation, summarization, rewriting, text-to-table, image description, text recognition, image scaling, object extraction and removal, plus\u00a0<a href=\"https:\/\/github.com\/microsoft\/winappCli\/blob\/main\/docs\/guides\/electron\/js-winml.md\" data-href=\"https:\/\/github.com\/microsoft\/winappCli\/blob\/main\/docs\/guides\/electron\/js-winml.md\">Windows ML model and execution provider catalogs<\/a><\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"21\"><strong>App and content APIs:<\/strong>\u00a0<a href=\"https:\/\/github.com\/microsoft\/winappCli\/blob\/main\/docs\/guides\/electron\/js-notification.md\" data-href=\"https:\/\/github.com\/microsoft\/winappCli\/blob\/main\/docs\/guides\/electron\/js-notification.md\">notifications<\/a>,\u00a0<a href=\"https:\/\/github.com\/microsoft\/winappCli\/blob\/main\/docs\/guides\/electron\/js-file-picker.md\" data-href=\"https:\/\/github.com\/microsoft\/winappCli\/blob\/main\/docs\/guides\/electron\/js-file-picker.md\">file and folder pickers, storage, and image decoding<\/a>, plus rich clipboard content<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"22\"><strong>System and device APIs:<\/strong>\u00a0networking, sensors, globalization, and cryptography<\/li>\n<\/ul>\n<p class=\"code-line\" dir=\"auto\" data-line=\"24\">The same metadata-driven workflow can project other compatible Windows Runtime APIs, including APIs from custom WinRT components.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"26\">The open-source\u00a0<a href=\"https:\/\/github.com\/microsoft\/electron-on-windows-gallery\" data-href=\"https:\/\/github.com\/microsoft\/electron-on-windows-gallery\"><strong>Electron on Windows Gallery<\/strong><\/a>\u00a0uses these JavaScript projections for its AI scenarios. Each interactive sample includes its JavaScript source, API documentation, and setup guidance.<\/p>\n<div><\/div>\n<p><img decoding=\"async\" class=\"aligncenter wp-image-1234 size-full\" src=\"https:\/\/devblogs.microsoft.com\/ifdef-windows\/wp-content\/uploads\/sites\/61\/2026\/07\/electron-gallery-samples.gif\" alt=\"electron gallery samples image\" width=\"2037\" height=\"1450\" \/><\/p>\n<\/div>\n<\/div>\n<div>\n<div>\n<div>\n<h2 id=\"how-the-pieces-fit-together\" class=\"code-line\" dir=\"auto\" data-line=\"32\">How the pieces fit together<\/h2>\n<hr \/>\n<\/div>\n<div>\n<p class=\"code-line\" dir=\"auto\" data-line=\"34\">The projection is delivered through three npm packages. You install only\u00a0<code>@microsoft\/winappcli<\/code>; it coordinates the other two and keeps their versions aligned:<\/p>\n<ul class=\"code-line\" dir=\"auto\" data-line=\"36\">\n<li class=\"code-line\" dir=\"auto\" data-line=\"36\"><strong><a href=\"https:\/\/www.npmjs.com\/package\/@microsoft\/winappcli\" data-href=\"https:\/\/www.npmjs.com\/package\/@microsoft\/winappcli\"><code>@microsoft\/winappcli<\/code><\/a><\/strong>\u00a0sets up the manifest and SDK metadata, runs projection generation, and handles debug package identity.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"37\"><strong><a href=\"https:\/\/www.npmjs.com\/package\/@microsoft\/dynwinrt-codegen\" data-href=\"https:\/\/www.npmjs.com\/package\/@microsoft\/dynwinrt-codegen\"><code>@microsoft\/dynwinrt-codegen<\/code><\/a><\/strong>\u00a0reads that\u00a0<code>.winmd<\/code>\u00a0metadata and emits JavaScript wrappers with matching TypeScript declarations (<code>.js<\/code>\u00a0+\u00a0<code>.d.ts<\/code>).<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"38\"><strong><a href=\"https:\/\/www.npmjs.com\/package\/@microsoft\/dynwinrt\" data-href=\"https:\/\/www.npmjs.com\/package\/@microsoft\/dynwinrt\"><code>@microsoft\/dynwinrt<\/code><\/a><\/strong>\u00a0is the shared, prebuilt x64 and arm64 runtime that dispatches those Windows API calls when your app runs.<\/li>\n<\/ul>\n<p class=\"code-line\" dir=\"auto\" data-line=\"40\">Together, these packages turn Windows metadata into JavaScript APIs that an app can import and call.<\/p>\n<h2 id=\"two-examples-in-electron\" class=\"code-line\" dir=\"auto\" data-line=\"42\">Two examples in Electron<\/h2>\n<\/div>\n<hr \/>\n<p class=\"code-line\" dir=\"auto\" data-line=\"44\">Both examples use JavaScript only:<\/p>\n<ul class=\"code-line\" dir=\"auto\" data-line=\"46\">\n<li class=\"code-line\" dir=\"auto\" data-line=\"46\"><strong>Native notifications<\/strong>\u00a0with\u00a0<code>AppNotificationBuilder<\/code>\u00a0\/\u00a0<code>AppNotificationManager<\/code><\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"47\"><strong>Phi Silica on-device AI<\/strong>\u00a0with\u00a0<code>LanguageModel<\/code>\u00a0\/\u00a0<code>TextSummarizer<\/code>\u00a0(Copilot+ PCs)<\/li>\n<\/ul>\n<\/div>\n<h4>Project setup<\/h4>\n<div>\n<p class=\"code-line\" dir=\"auto\" data-line=\"51\">If you&#8217;re creating a new Electron app, start with the\u00a0<a href=\"https:\/\/github.com\/microsoft\/winappCli\/blob\/main\/docs\/guides\/electron\/setup.md\" data-href=\"https:\/\/github.com\/microsoft\/winappCli\/blob\/main\/docs\/guides\/electron\/setup.md\">WinApp CLI Electron setup guide<\/a>. It covers project creation, prerequisites, and the full WinApp CLI workflow.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"53\">For an existing Electron app, install the CLI and initialize the project:<\/p>\n<pre><code class=\"code-line language-bash\" dir=\"auto\" data-line=\"53\">npm install --save-dev @microsoft\/winappcli\r\nnpx winapp init . --use-defaults --add-js-bindings\r\n<\/code><\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"60\"><code>winapp init<\/code>\u00a0creates the manifest, sets up the SDKs, adds\u00a0<code>@microsoft\/dynwinrt<\/code>\u00a0and\u00a0<code>@microsoft\/dynwinrt-codegen<\/code>\u00a0to\u00a0<code>package.json<\/code>, and generates JavaScript wrappers and TypeScript declarations under\u00a0<code>.winapp\/bindings\/<\/code>. It also writes a\u00a0<code>winapp.jsBindings<\/code>\u00a0configuration block for adding namespaces or\u00a0<code>.winmd<\/code>\u00a0files, including metadata from custom WinRT components.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"62\">Setup adds\u00a0<code>#winapp\/bindings<\/code>\u00a0and\u00a0<code>#winapp\/bindings\/*<\/code>\u00a0to the\u00a0<code>package.json#imports<\/code>\u00a0map for the generated CommonJS, ES module, and TypeScript declaration entry points. This keeps imports independent of the source file&#8217;s location. See the\u00a0<a href=\"https:\/\/github.com\/microsoft\/winappCli\/blob\/main\/docs\/guides\/electron\/js-file-picker.md\" data-href=\"https:\/\/github.com\/microsoft\/winappCli\/blob\/main\/docs\/guides\/electron\/js-file-picker.md\">file picker guide<\/a>\u00a0for a detailed configuration example.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"64\">Both examples require package identity. To use them during development, give the Electron executable a temporary identity:<\/p>\n<pre><code class=\"code-line language-bash\" dir=\"auto\" data-line=\"62\">npx winapp node add-electron-debug-identity\r\n<\/code><\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"66\">Run this command again whenever the manifest, Electron executable path, or identity fields change. For APIs that don&#8217;t require package identity, skip this command and start Electron normally with\u00a0<code>npm start<\/code>. See the\u00a0<a href=\"https:\/\/github.com\/microsoft\/winappCli\/blob\/main\/docs\/guides\/electron\/setup.md#step-5-understanding-debug-identity\" data-href=\"https:\/\/github.com\/microsoft\/winappCli\/blob\/main\/docs\/guides\/electron\/setup.md#step-5-understanding-debug-identity\">debug identity guide<\/a>\u00a0for more detail.<\/p>\n<\/div>\n<div>\n<h4>Show a rich Windows notification<\/h4>\n<p class=\"code-line\" dir=\"auto\" data-line=\"74\">Electron&#8217;s built-in notification API covers basic toasts. Windows App SDK notifications add progress bars, actions, inputs, and scenarios. This main-process example shows a progress notification:<\/p>\n<\/div>\n<div>\n<pre><code class=\"code-line language-js code-active-line\" dir=\"auto\" data-line=\"74\"><span class=\"hljs-keyword\">const<\/span> {\r\n  <span class=\"hljs-title class_\">AppNotificationBuilder<\/span>,\r\n  <span class=\"hljs-title class_\">AppNotificationManager<\/span>,\r\n  <span class=\"hljs-title class_\">AppNotificationProgressBar<\/span>,\r\n} = <span class=\"hljs-built_in\">require<\/span>(<span class=\"hljs-string\">'#winapp\/bindings'<\/span>);\r\n\r\n<span class=\"hljs-keyword\">const<\/span> progress = <span class=\"hljs-title class_\">AppNotificationProgressBar<\/span>\r\n  .<span class=\"hljs-title function_\">create<\/span>()\r\n  .<span class=\"hljs-title function_\">setTitle<\/span>(<span class=\"hljs-string\">'Processing with Windows AI'<\/span>)\r\n  .<span class=\"hljs-title function_\">setStatus<\/span>(<span class=\"hljs-string\">'Running locally'<\/span>)\r\n  .<span class=\"hljs-title function_\">setValue<\/span>(<span class=\"hljs-number\">0.65<\/span>)\r\n  .<span class=\"hljs-title function_\">setValueStringOverride<\/span>(<span class=\"hljs-string\">'65%'<\/span>);\r\n\r\n<span class=\"hljs-title class_\">AppNotificationManager<\/span>.<span class=\"hljs-property\">default_<\/span>.<span class=\"hljs-title function_\">show<\/span>(\r\n  <span class=\"hljs-title class_\">AppNotificationBuilder<\/span>\r\n    .<span class=\"hljs-title function_\">create<\/span>()\r\n    .<span class=\"hljs-title function_\">addText<\/span>(<span class=\"hljs-string\">'Windows AI task running'<\/span>)\r\n    .<span class=\"hljs-title function_\">addText<\/span>(<span class=\"hljs-string\">'This notification uses a native Windows progress bar.'<\/span>)\r\n    .<span class=\"hljs-title function_\">addProgressBar<\/span>(progress)\r\n    .<span class=\"hljs-title function_\">buildNotification<\/span>()\r\n);<\/code><\/pre>\n<\/div>\n<div>\n<div>\n<p class=\"code-line\" dir=\"auto\" data-line=\"99\">Run the app, and Windows shows the same native toast a C# or C++ app would produce, including the progress bar:<\/p>\n<\/div>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/ifdef-windows\/wp-content\/uploads\/sites\/61\/2026\/07\/electron-toast-hello-from-electron.webp\"><img decoding=\"async\" class=\"aligncenter wp-image-1226 size-full\" src=\"https:\/\/devblogs.microsoft.com\/ifdef-windows\/wp-content\/uploads\/sites\/61\/2026\/07\/electron-toast-hello-from-electron.webp\" alt=\"electron toast hello from electron image\" width=\"563\" height=\"287\" srcset=\"https:\/\/devblogs.microsoft.com\/ifdef-windows\/wp-content\/uploads\/sites\/61\/2026\/07\/electron-toast-hello-from-electron.webp 563w, https:\/\/devblogs.microsoft.com\/ifdef-windows\/wp-content\/uploads\/sites\/61\/2026\/07\/electron-toast-hello-from-electron-300x153.webp 300w\" sizes=\"(max-width: 563px) 100vw, 563px\" \/><\/a><\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"99\">See the\u00a0<a href=\"https:\/\/github.com\/microsoft\/winappCli\/blob\/main\/docs\/guides\/electron\/js-notification.md\" data-href=\"https:\/\/github.com\/microsoft\/winappCli\/blob\/main\/docs\/guides\/electron\/js-notification.md\">Show a notification from JavaScript<\/a>\u00a0guide for a full walkthrough.<\/p>\n<h4>Run Phi Silica on-device AI<\/h4>\n<div>\n<p class=\"code-line\" dir=\"auto\" data-line=\"107\">The same bindings can call\u00a0<strong>Phi Silica<\/strong>, a local language model available on supported Windows devices.\u00a0<strong>This example requires a\u00a0<a href=\"https:\/\/learn.microsoft.com\/en-us\/windows\/ai\/npu-devices\/\" data-href=\"https:\/\/learn.microsoft.com\/en-us\/windows\/ai\/npu-devices\/\">Copilot+ PC<\/a>.<\/strong><\/p>\n<\/div>\n<pre><code class=\"code-line language-js\" dir=\"auto\" data-line=\"107\"><span class=\"hljs-keyword\">const<\/span> {\r\n  <span class=\"hljs-title class_\">AIFeatureReadyState<\/span>, <span class=\"hljs-title class_\">LanguageModel<\/span>, <span class=\"hljs-title class_\">TextSummarizer<\/span>,\r\n} = <span class=\"hljs-built_in\">require<\/span>(<span class=\"hljs-string\">'#winapp\/bindings'<\/span>);\r\n\r\n<span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title function_\">summarize<\/span>() {\r\n  <span class=\"hljs-keyword\">const<\/span> readyState = <span class=\"hljs-title class_\">LanguageModel<\/span>.<span class=\"hljs-title function_\">getReadyState<\/span>();\r\n  <span class=\"hljs-keyword\">if<\/span> (readyState !== <span class=\"hljs-title class_\">AIFeatureReadyState<\/span>.<span class=\"hljs-property\">Ready<\/span> &amp;&amp;\r\n      readyState !== <span class=\"hljs-title class_\">AIFeatureReadyState<\/span>.<span class=\"hljs-property\">NotReady<\/span>) {\r\n    <span class=\"hljs-variable language_\">console<\/span>.<span class=\"hljs-title function_\">log<\/span>(<span class=\"hljs-string\">'Phi Silica is not available on this device.'<\/span>);\r\n    <span class=\"hljs-keyword\">return<\/span>;\r\n  }\r\n  <span class=\"hljs-keyword\">if<\/span> (readyState === <span class=\"hljs-title class_\">AIFeatureReadyState<\/span>.<span class=\"hljs-property\">NotReady<\/span>) {\r\n    <span class=\"hljs-keyword\">await<\/span> <span class=\"hljs-title class_\">LanguageModel<\/span>.<span class=\"hljs-title function_\">ensureReadyAsync<\/span>();\r\n  }\r\n\r\n  <span class=\"hljs-keyword\">const<\/span> model = <span class=\"hljs-keyword\">await<\/span> <span class=\"hljs-title class_\">LanguageModel<\/span>.<span class=\"hljs-title function_\">createAsync<\/span>();\r\n  <span class=\"hljs-keyword\">try<\/span> {\r\n    <span class=\"hljs-keyword\">const<\/span> op = <span class=\"hljs-title class_\">TextSummarizer<\/span>\r\n      .<span class=\"hljs-title function_\">createInstance<\/span>(model)\r\n      .<span class=\"hljs-title function_\">summarizeParagraphAsync<\/span>(<span class=\"hljs-string\">'Some long paragraph...'<\/span>);\r\n\r\n    <span class=\"hljs-comment\">\/\/ Stream partial output as the model generates it<\/span>\r\n    op.<span class=\"hljs-title function_\">progress<\/span>(<span class=\"hljs-function\">(<span class=\"hljs-params\">partial<\/span>) =&gt;<\/span> {\r\n      process.<span class=\"hljs-property\">stdout<\/span>.<span class=\"hljs-title function_\">write<\/span>(partial);\r\n    });\r\n\r\n    <span class=\"hljs-keyword\">const<\/span> result = <span class=\"hljs-keyword\">await<\/span> op;\r\n    <span class=\"hljs-variable language_\">console<\/span>.<span class=\"hljs-title function_\">log<\/span>(<span class=\"hljs-string\">'\\nDone:'<\/span>, result.<span class=\"hljs-property\">text<\/span>);\r\n  } <span class=\"hljs-keyword\">finally<\/span> {\r\n    model.<span class=\"hljs-title function_\">close<\/span>();\r\n  }\r\n}\r\n\r\n<span class=\"hljs-title function_\">summarize<\/span>().<span class=\"hljs-title function_\">catch<\/span>(<span class=\"hljs-variable language_\">console<\/span>.<span class=\"hljs-property\">error<\/span>);<\/code><\/pre>\n<div>\n<p class=\"code-line\" dir=\"auto\" data-line=\"146\">Phi Silica requires the following restricted capability inside the existing\u00a0<code>&lt;Capabilities&gt;<\/code>\u00a0element in\u00a0<code>Package.appxmanifest<\/code>:<\/p>\n<pre><code class=\"code-line language-xml\" dir=\"auto\" data-line=\"134\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">rescap:Capability<\/span> <span class=\"hljs-attr\">Name<\/span>=<span class=\"hljs-string\">\"systemAIModels\"<\/span> \/&gt;<\/span><\/code><\/pre>\n<\/div>\n<\/div>\n<div>\n<div>\n<div>\n<p class=\"code-line\" dir=\"auto\" data-line=\"152\">After changing the manifest, refresh debug identity:<\/p>\n<\/div>\n<div>\n<pre class=\"prettyprint language-default\"><code class=\"language-default\">npx winapp node add-electron-debug-identity<\/code><\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"158\">When this code runs in the Electron main process, progress callbacks write partial output to the terminal before the final\u00a0<code>Done:<\/code>\u00a0line:<\/p>\n<\/div>\n<\/div>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/ifdef-windows\/wp-content\/uploads\/sites\/61\/2026\/07\/phi-silica-console.gif\"><img decoding=\"async\" class=\"alignnone size-full wp-image-1232\" src=\"https:\/\/devblogs.microsoft.com\/ifdef-windows\/wp-content\/uploads\/sites\/61\/2026\/07\/phi-silica-console.gif\" alt=\"phi silica console image\" width=\"1975\" height=\"568\" \/><\/a><\/p>\n<p>See the\u00a0<a href=\"https:\/\/github.com\/microsoft\/winappCli\/blob\/main\/docs\/guides\/electron\/js-phi-silica.md\" data-href=\"https:\/\/github.com\/microsoft\/winappCli\/blob\/main\/docs\/guides\/electron\/js-phi-silica.md\">Call Phi Silica from JavaScript<\/a>\u00a0guide for a full walkthrough.<\/p>\n<h2 id=\"add-windows-sdk-and-custom-apis\" class=\"code-line\" dir=\"auto\" data-line=\"164\">Add Windows SDK and custom APIs<\/h2>\n<p>By default, the WinApp CLI generates the supported Windows App SDK API surface; UI-only packages such as\u00a0<code>Microsoft.WindowsAppSDK.WinUI<\/code>\u00a0and\u00a0<code>Microsoft.Web.WebView2<\/code>\u00a0are excluded. To include Windows SDK APIs, list the entry-point classes in\u00a0<code>package.json<\/code>. For example, add the Windows Clipboard API:<\/p>\n<pre class=\"prettyprint language-json\"><code class=\"language-json\">{\r\n\u00a0 \"winapp\": {\r\n\u00a0 \u00a0 \"jsBindings\": {\r\n\u00a0 \u00a0 \u00a0 \"additionalWinmds\": [\r\n\u00a0 \u00a0 \u00a0 \u00a0 {\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \"namespace\": \"Windows.ApplicationModel.DataTransfer\",\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \"classes\": [\"Clipboard\", \"HtmlFormatHelper\"]\r\n\u00a0 \u00a0 \u00a0 \u00a0 }\r\n\u00a0 \u00a0 \u00a0 ]\r\n\u00a0 \u00a0 }\r\n\u00a0 }\r\n}<\/code><\/pre>\n<div>\n<p class=\"code-line\" dir=\"auto\" data-line=\"183\">Regenerate the bindings:<\/p>\n<div>\n<pre class=\"prettyprint language-default\"><code class=\"language-default\">npx winapp node generate-bindings<\/code><\/pre>\n<\/div>\n<\/div>\n<div>\n<p class=\"code-line\" dir=\"auto\" data-line=\"189\">Codegen resolves dependent types transitively, so only the entry-point classes need to be listed.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"191\">The generated bindings can now place rich HTML on the Windows clipboard for apps such as Word, Outlook, or Teams:<\/p>\n<\/div>\n<pre><code class=\"code-line language-js\" dir=\"auto\" data-line=\"191\"><span class=\"hljs-keyword\">const<\/span> {\r\n  <span class=\"hljs-title class_\">Clipboard<\/span>,\r\n  <span class=\"hljs-title class_\">DataPackage<\/span>,\r\n  <span class=\"hljs-title class_\">HtmlFormatHelper<\/span>,\r\n} = <span class=\"hljs-built_in\">require<\/span>(<span class=\"hljs-string\">'#winapp\/bindings'<\/span>);\r\n\r\n<span class=\"hljs-keyword\">const<\/span> html = <span class=\"hljs-title class_\">HtmlFormatHelper<\/span>.<span class=\"hljs-title function_\">createHtmlFormat<\/span>(<span class=\"hljs-string\">`\r\n  &lt;h2&gt;Hello from Electron&lt;\/h2&gt;\r\n  &lt;p&gt;This was copied as &lt;strong&gt;HTML&lt;\/strong&gt; via Windows Clipboard APIs.&lt;\/p&gt;\r\n  &lt;p&gt;&lt;a href=\"https:\/\/github.com\/microsoft\/winappCli\"&gt;Open WinApp CLI on GitHub&lt;\/a&gt;&lt;\/p&gt;\r\n`<\/span>);\r\n\r\n<span class=\"hljs-keyword\">const<\/span> data = <span class=\"hljs-title class_\">DataPackage<\/span>.<span class=\"hljs-title function_\">create<\/span>();\r\ndata.<span class=\"hljs-title function_\">setHtmlFormat<\/span>(html);\r\n\r\n<span class=\"hljs-title class_\">Clipboard<\/span>.<span class=\"hljs-title function_\">setContent<\/span>(data);\r\n<span class=\"hljs-title class_\">Clipboard<\/span>.<span class=\"hljs-title function_\">flush<\/span>();<\/code><\/pre>\n<p><code>HtmlFormatHelper.createHtmlFormat<\/code> wraps your markup with the CF_HTML header Windows expects, so any HTML-aware target renders it as rich text.<\/p>\n<div><a href=\"https:\/\/devblogs.microsoft.com\/ifdef-windows\/wp-content\/uploads\/sites\/61\/2026\/07\/clipboard-html-demo.gif\"><img decoding=\"async\" class=\"alignnone size-full wp-image-1235\" src=\"https:\/\/devblogs.microsoft.com\/ifdef-windows\/wp-content\/uploads\/sites\/61\/2026\/07\/clipboard-html-demo.gif\" alt=\"clipboard html demo image\" width=\"2037\" height=\"1449\" \/><\/a><\/div>\n<div>\n<p class=\"code-line\" dir=\"auto\" data-line=\"219\">For a third-party WinRT component, or a package not included by default, add a\u00a0<code>winmdPath<\/code> entry to <code>winapp.jsBindings.additionalWinmds<\/code>:<\/p>\n<pre><code class=\"code-line language-json\" dir=\"auto\" data-line=\"207\"><span class=\"hljs-punctuation\">{<\/span>\r\n  <span class=\"hljs-attr\">\"winapp\"<\/span><span class=\"hljs-punctuation\">:<\/span> <span class=\"hljs-punctuation\">{<\/span>\r\n    <span class=\"hljs-attr\">\"jsBindings\"<\/span><span class=\"hljs-punctuation\">:<\/span> <span class=\"hljs-punctuation\">{<\/span>\r\n      <span class=\"hljs-attr\">\"additionalWinmds\"<\/span><span class=\"hljs-punctuation\">:<\/span> <span class=\"hljs-punctuation\">[<\/span>\r\n        <span class=\"hljs-punctuation\">{<\/span>\r\n          <span class=\"hljs-attr\">\"winmdPath\"<\/span><span class=\"hljs-punctuation\">:<\/span> <span class=\"hljs-string\">\"path\/to\/Foo.winmd\"<\/span><span class=\"hljs-punctuation\">,<\/span>\r\n          <span class=\"hljs-attr\">\"namespace\"<\/span><span class=\"hljs-punctuation\">:<\/span> <span class=\"hljs-string\">\"Foo.Bar\"<\/span><span class=\"hljs-punctuation\">,<\/span>\r\n          <span class=\"hljs-attr\">\"classes\"<\/span><span class=\"hljs-punctuation\">:<\/span> <span class=\"hljs-punctuation\">[<\/span><span class=\"hljs-string\">\"Baz\"<\/span><span class=\"hljs-punctuation\">]<\/span>\r\n        <span class=\"hljs-punctuation\">}<\/span>\r\n      <span class=\"hljs-punctuation\">]<\/span>\r\n    <span class=\"hljs-punctuation\">}<\/span>\r\n  <span class=\"hljs-punctuation\">}<\/span>\r\n<span class=\"hljs-punctuation\">}<\/span>\r\n<\/code><\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"237\">This step generates only the JavaScript wrappers and TypeScript declarations. At runtime, the component binaries must also be deployed and any required activation configured, often in\u00a0<code>Package.appxmanifest<\/code>.<\/p>\n<\/div>\n<h2 id=\"use-the-projection-with-plain-nodejs\" class=\"code-line\" dir=\"auto\" data-line=\"225\">Use the projection with plain Node.js<\/h2>\n<hr \/>\n<p class=\"code-line\" dir=\"auto\" data-line=\"241\">The projection also works in a plain Node.js process. To try a Windows API without packaging an MSIX, create a project and point the WinApp CLI at the existing\u00a0<code>node.exe<\/code>:<\/p>\n<pre class=\"prettyprint language-default\"><code class=\"language-default\">mkdir my-winrt-experiment; cd my-winrt-experiment\r\nnpm init -y\r\nnpm install --save-dev @microsoft\/winappcli\r\nnpx winapp init . --use-defaults --add-js-bindings\r\n\r\n# winapp run needs an .exe inside the project. Alias .local-node to your Node install.\r\nNew-Item -ItemType Junction -Path .\\.local-node -Target (Split-Path (Get-Command node).Source)<\/code><\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"256\">This example also uses Phi Silica, so add the same\u00a0<code>systemAIModels<\/code>\u00a0capability to\u00a0<code>Package.appxmanifest<\/code>. Then create\u00a0<code>app.js<\/code>\u00a0with a short\u00a0<code>TextRewriter<\/code>\u00a0call:<\/p>\n<pre><code class=\"code-line language-js\" dir=\"auto\" data-line=\"256\"><span class=\"hljs-keyword\">const<\/span> { roInitialize } = <span class=\"hljs-built_in\">require<\/span>(<span class=\"hljs-string\">'@microsoft\/dynwinrt'<\/span>);\r\n<span class=\"hljs-title function_\">roInitialize<\/span>(<span class=\"hljs-number\">1<\/span>); <span class=\"hljs-comment\">\/\/ MTA<\/span>\r\n\r\n<span class=\"hljs-keyword\">const<\/span> {\r\n  <span class=\"hljs-title class_\">AIFeatureReadyState<\/span>,\r\n  <span class=\"hljs-title class_\">LanguageModel<\/span>,\r\n  <span class=\"hljs-title class_\">TextRewriter<\/span>,\r\n  <span class=\"hljs-title class_\">TextRewriteTone<\/span>,\r\n} = <span class=\"hljs-built_in\">require<\/span>(<span class=\"hljs-string\">'#winapp\/bindings'<\/span>);\r\n\r\n<span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title function_\">main<\/span>() {\r\n  <span class=\"hljs-keyword\">const<\/span> readyState = <span class=\"hljs-title class_\">LanguageModel<\/span>.<span class=\"hljs-title function_\">getReadyState<\/span>();\r\n  <span class=\"hljs-keyword\">if<\/span> (readyState !== <span class=\"hljs-title class_\">AIFeatureReadyState<\/span>.<span class=\"hljs-property\">Ready<\/span> &amp;&amp;\r\n      readyState !== <span class=\"hljs-title class_\">AIFeatureReadyState<\/span>.<span class=\"hljs-property\">NotReady<\/span>) {\r\n    <span class=\"hljs-variable language_\">console<\/span>.<span class=\"hljs-title function_\">log<\/span>(<span class=\"hljs-string\">'Phi Silica is not available on this device.'<\/span>);\r\n    <span class=\"hljs-keyword\">return<\/span>;\r\n  }\r\n  <span class=\"hljs-keyword\">if<\/span> (readyState === <span class=\"hljs-title class_\">AIFeatureReadyState<\/span>.<span class=\"hljs-property\">NotReady<\/span>) {\r\n    <span class=\"hljs-keyword\">await<\/span> <span class=\"hljs-title class_\">LanguageModel<\/span>.<span class=\"hljs-title function_\">ensureReadyAsync<\/span>();\r\n  }\r\n\r\n  <span class=\"hljs-keyword\">const<\/span> model = <span class=\"hljs-keyword\">await<\/span> <span class=\"hljs-title class_\">LanguageModel<\/span>.<span class=\"hljs-title function_\">createAsync<\/span>();\r\n  <span class=\"hljs-keyword\">try<\/span> {\r\n    <span class=\"hljs-keyword\">const<\/span> rewriter = <span class=\"hljs-title class_\">TextRewriter<\/span>.<span class=\"hljs-title function_\">createInstance<\/span>(model);\r\n    <span class=\"hljs-keyword\">const<\/span> result = <span class=\"hljs-keyword\">await<\/span> rewriter.<span class=\"hljs-title function_\">rewriteAsync<\/span>(\r\n      <span class=\"hljs-string\">'WinApp CLI makes it easier to use Windows APIs from JavaScript.'<\/span>,\r\n      <span class=\"hljs-title class_\">TextRewriteTone<\/span>.<span class=\"hljs-property\">Formal<\/span>\r\n    );\r\n    <span class=\"hljs-variable language_\">console<\/span>.<span class=\"hljs-title function_\">log<\/span>(result.<span class=\"hljs-property\">text<\/span>);\r\n  } <span class=\"hljs-keyword\">finally<\/span> {\r\n    model.<span class=\"hljs-title function_\">close<\/span>();\r\n  }\r\n}\r\n\r\n<span class=\"hljs-title function_\">main<\/span>().<span class=\"hljs-title function_\">catch<\/span>(<span class=\"hljs-function\">(<span class=\"hljs-params\">error<\/span>) =&gt;<\/span> {\r\n  <span class=\"hljs-variable language_\">console<\/span>.<span class=\"hljs-title function_\">error<\/span>(error);\r\n  process.<span class=\"hljs-property\">exitCode<\/span> = <span class=\"hljs-number\">1<\/span>;\r\n});<\/code><\/pre>\n<div>\n<p class=\"code-line\" dir=\"auto\" data-line=\"299\">Run the script once under package identity:<\/p>\n<\/div>\n<div>\n<pre class=\"prettyprint language-default\"><code class=\"language-default\">npx winapp run . --exe .local-node\\node.exe --with-alias --args \"app.js\" --unregister-on-exit<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<div>\n<div>\n<p class=\"code-line\" dir=\"auto\" data-line=\"305\"><code>winapp run<\/code>\u00a0registers the loose-layout package, launches\u00a0<code>.local-node\\node.exe app.js<\/code>\u00a0with package identity and the Windows App SDK runtime graph, and unregisters it on exit.\u00a0<code>--with-alias<\/code>\u00a0routes the launch through the execution alias so stdout and stderr remain attached to the terminal.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"307\">For repeated runs with a persistent execution alias (<code>mynode.exe app.js<\/code>\u00a0from any terminal), see the\u00a0<a href=\"https:\/\/github.com\/microsoft\/dynwinrt\/blob\/main\/docs\/guides\/node\/dev-mode.md\" data-href=\"https:\/\/github.com\/microsoft\/dynwinrt\/blob\/main\/docs\/guides\/node\/dev-mode.md\">Plain Node.js dev-mode guide<\/a>.<\/p>\n<\/div>\n<div>\n<h2 id=\"how-the-projection-works\" class=\"code-line\" dir=\"auto\" data-line=\"309\">How the projection works<\/h2>\n<\/div>\n<hr \/>\n<p class=\"code-line\" dir=\"auto\" data-line=\"311\"><code>dynwinrt-codegen<\/code>\u00a0runs as part of\u00a0<code>winapp init<\/code>,\u00a0<code>restore<\/code>, and\u00a0<code>generate-bindings<\/code>, converting\u00a0<code>.winmd<\/code>\u00a0metadata into JavaScript wrappers and TypeScript declarations. It does not generate native code per class. At runtime,\u00a0<code>@microsoft\/dynwinrt<\/code>\u00a0invokes the underlying COM vtables and adapts WinRT conventions to JavaScript: strings and HRESULT failures become JavaScript values and errors, asynchronous operations are awaitable with cancellation and progress support, and collections, structs, enums, and event delegates are projected into JavaScript shapes.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"313\">The projection primarily targets data-style Windows Runtime APIs such as AI, storage, notifications, networking, and similar system capabilities. WebView2 is not part of the generated projection surface.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"315\">For the full design, see\u00a0<a href=\"https:\/\/github.com\/microsoft\/dynwinrt\/blob\/main\/design.md\" data-href=\"https:\/\/github.com\/microsoft\/dynwinrt\/blob\/main\/design.md\"><code>dynwinrt\/design.md<\/code><\/a>.<\/p>\n<h2 id=\"feedback-and-resources\" class=\"code-line\" dir=\"auto\" data-line=\"317\">Feedback and resources<\/h2>\n<hr \/>\n<div>\n<p class=\"code-line\" dir=\"auto\" data-line=\"319\">This is a public preview. If an API maps awkwardly into JavaScript, a TypeScript declaration looks wrong, or a scenario is missing, please file an issue. That feedback will help set priorities.<\/p>\n<h3 id=\"where-to-file-issues\" class=\"code-line\" dir=\"auto\" data-line=\"321\">Where to file issues<\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"296\">The WinApp CLI and the underlying projection live in\u00a0<strong>two different repos<\/strong>. File feedback in whichever fits your issue:<\/p>\n<\/div>\n<div>\n<ul>\n<li class=\"code-line\" dir=\"auto\" data-line=\"298\"><strong>CLI setup, configuration, identity, docs, and samples:<\/strong>\u00a0<a href=\"https:\/\/github.com\/microsoft\/winappCli\/issues\" data-href=\"https:\/\/github.com\/microsoft\/winappCli\/issues\"><code>microsoft\/winappCli<\/code><\/a><\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"299\"><strong>Runtime, code generator, type mapping, and generated TypeScript declarations:<\/strong>\u00a0<a href=\"https:\/\/github.com\/microsoft\/dynwinrt\/issues\" data-href=\"https:\/\/github.com\/microsoft\/dynwinrt\/issues\"><code>microsoft\/dynwinrt<\/code><\/a><\/li>\n<\/ul>\n<\/div>\n<h3>WinApp CLI<\/h3>\n<ul>\n<li>Repo and full command reference: <a href=\"https:\/\/github.com\/microsoft\/winappCli\">microsoft\/winappCli<\/a><\/li>\n<li>Install: <a href=\"https:\/\/www.npmjs.com\/package\/@microsoft\/winappcli\">@microsoft\/winappcli<\/a>\u00a0on npm<\/li>\n<li>Electron getting-started guides: <a href=\"https:\/\/github.com\/microsoft\/winappCli\/blob\/main\/docs\/guides\/electron\/setup.md\">setup<\/a>\u00a0\u00b7 <a href=\"https:\/\/github.com\/microsoft\/winappCli\/blob\/main\/docs\/guides\/electron\/js-file-picker.md\">file picker<\/a> \u00b7 <a href=\"https:\/\/github.com\/microsoft\/winappCli\/blob\/main\/docs\/guides\/electron\/js-notification.md\">notification<\/a><a href=\"https:\/\/github.com\/microsoft\/winappCli\/blob\/main\/docs\/guides\/electron\/js-phi-silica.md\">Phi Silica<\/a>\u00a0\u00b7 <a href=\"https:\/\/github.com\/microsoft\/winappCli\/blob\/main\/docs\/guides\/electron\/js-winml.md\">WinML<\/a><\/li>\n<li>Debug identity for Electron: <a href=\"https:\/\/github.com\/microsoft\/winappCli\/blob\/main\/docs\/guides\/electron\/setup.md#step-5-understanding-debug-identity\">Setup guide \u2192 Understanding Debug Identity<\/a><\/li>\n<\/ul>\n<h3>dynwinrt (the projection itself)<\/h3>\n<ul>\n<li>Repo, design notes, and benchmarks: <a href=\"https:\/\/github.com\/microsoft\/dynwinrt\">microsoft\/dynwinrt<\/a><\/li>\n<\/ul>\n<div><\/div>\n<div>We&#8217;re excited to see what you build using the projection. Happy coding! \ud83c\udf89<\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Electron and Node.js make it straightforward to build Windows desktop apps in JavaScript. Calling Windows Runtime APIs has been less straightforward: features such as on-device AI often required a C++ or C# bridge, manual translation of WinRT types and asynchronous behavior, and wrapper code for every exposed API. That meant another language and toolchain to [&hellip;]<\/p>\n","protected":false},"author":213245,"featured_media":1357,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-1230","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ifdef-windows"],"acf":[],"blog_post_summary":"<p>Electron and Node.js make it straightforward to build Windows desktop apps in JavaScript. Calling Windows Runtime APIs has been less straightforward: features such as on-device AI often required a C++ or C# bridge, manual translation of WinRT types and asynchronous behavior, and wrapper code for every exposed API. That meant another language and toolchain to [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/ifdef-windows\/wp-json\/wp\/v2\/posts\/1230","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/ifdef-windows\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/ifdef-windows\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ifdef-windows\/wp-json\/wp\/v2\/users\/213245"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ifdef-windows\/wp-json\/wp\/v2\/comments?post=1230"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/ifdef-windows\/wp-json\/wp\/v2\/posts\/1230\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ifdef-windows\/wp-json\/wp\/v2\/media\/1357"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/ifdef-windows\/wp-json\/wp\/v2\/media?parent=1230"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ifdef-windows\/wp-json\/wp\/v2\/categories?post=1230"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ifdef-windows\/wp-json\/wp\/v2\/tags?post=1230"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}