diff --git a/NativeScriptWindowsDemo/App/core/ui.js b/NativeScriptWindowsDemo/App/core/ui.js
new file mode 100644
index 0000000..448bbce
--- /dev/null
+++ b/NativeScriptWindowsDemo/App/core/ui.js
@@ -0,0 +1,184 @@
+const delegateKeepAlive = [];
+
+export function resolveType(typeName) {
+ const parts = String(typeName).split(".");
+ let current = globalThis;
+ for (let i = 0; i < parts.length; i += 1) {
+ current = current && current[parts[i]];
+ }
+ return current;
+}
+
+export function text(value, size) {
+ const control = new Windows.UI.Xaml.Controls.TextBlock();
+ control.Text = String(value);
+ if (size) {
+ control.FontSize = size;
+ }
+ return control;
+}
+
+export function createTypedDelegate(typeName, callback) {
+ const TypeCtor = resolveType(typeName);
+ if (typeof TypeCtor !== "function") {
+ return null;
+ }
+
+ try {
+ const delegate = new TypeCtor({
+ Invoke: function () {
+ return callback.apply(null, arguments);
+ },
+ });
+ delegateKeepAlive.push(delegate);
+ return delegate;
+ } catch (_error) {
+ return null;
+ }
+}
+
+export function bindClick(button, onClick) {
+ const callback = typeof onClick === "function" ? onClick : function () {};
+ const delegate = createTypedDelegate("Windows.UI.Xaml.RoutedEventHandler", callback);
+
+ if (delegate && typeof button.add_Click === "function") {
+ button.add_Click(delegate);
+ return;
+ }
+
+ button.Click = delegate || callback;
+}
+
+export function createButton(label, onClick) {
+ const button = new Windows.UI.Xaml.Controls.Button();
+ button.Height = 42;
+ button.Content = String(label);
+ bindClick(button, onClick);
+ return button;
+}
+
+export function createCard(titleValue, bodyValue) {
+ const border = new Windows.UI.Xaml.Controls.Border();
+
+ const stack = new Windows.UI.Xaml.Controls.StackPanel();
+ stack.Spacing = 8;
+
+ const titleText = text(titleValue, 19);
+ const bodyText = text(bodyValue, 14);
+ bodyText.TextWrapping = Windows.UI.Xaml.TextWrapping.Wrap;
+
+ stack.Children.Append(titleText);
+ stack.Children.Append(bodyText);
+
+ border.Child = stack;
+ return border;
+}
+
+export function withContentPadding(content) {
+ const outer = new Windows.UI.Xaml.Controls.StackPanel();
+
+ const topSpacer = new Windows.UI.Xaml.Controls.Border();
+ topSpacer.Height = 18;
+ outer.Children.Append(topSpacer);
+
+ const row = new Windows.UI.Xaml.Controls.StackPanel();
+ row.Orientation = Windows.UI.Xaml.Controls.Orientation.Horizontal;
+
+ const leftSpacer = new Windows.UI.Xaml.Controls.Border();
+ leftSpacer.Width = 24;
+
+ row.Children.Append(leftSpacer);
+ row.Children.Append(content);
+ outer.Children.Append(row);
+
+ return outer;
+}
+
+export function safeGetChildrenSize(element) {
+ try {
+ const children = element && element.Children;
+ if (children && typeof children.Size === "number") {
+ return children.Size;
+ }
+ } catch (_error) {
+ }
+
+ return -1;
+}
+
+export function createBrandImage(width, height) {
+ const host = new Windows.UI.Xaml.Controls.StackPanel();
+ host.Spacing = 0;
+
+ const image = new Windows.UI.Xaml.Controls.Image();
+ image.Width = width || 280;
+ image.Height = height || 120;
+ image.Stretch = Windows.UI.Xaml.Media.Stretch.Uniform;
+
+ const fallback = text("NativeScript", 44);
+ fallback.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
+
+ host.Children.Append(image);
+ host.Children.Append(fallback);
+
+ const candidateUris = [
+ "ms-appx:///Assets/Wide310x150Logo.scale-200.png",
+ "ms-appx:///Assets/Square150x150Logo.scale-200.png",
+ "ms-appx:///Assets/StoreLogo.png",
+ "ms-appx:///Assets/cover.png",
+ "https://raw.githubusercontent.com/NativeScript/NativeScript/main/tools/graphics/cover.png",
+ ].filter(function (value) {
+ return typeof value === "string" && value.length > 0;
+ });
+
+ let assigned = false;
+
+ const tryAssignImageSource = function () {
+ for (let i = 0; i < candidateUris.length; i += 1) {
+ const uriValue = candidateUris[i];
+ console.log("NativeScriptWindowsDemo: trying image URI", uriValue);
+
+ try {
+ const uri = new Windows.Foundation.Uri(uriValue);
+ const bitmap = new Windows.UI.Xaml.Media.Imaging.BitmapImage();
+ bitmap.UriSource = uri;
+ image.Source = bitmap;
+ console.log("NativeScriptWindowsDemo: image source assigned", uriValue);
+ assigned = true;
+ return true;
+ } catch (error) {
+ console.log("NativeScriptWindowsDemo: invalid image URI", uriValue, error && error.message ? error.message : error);
+ }
+ }
+
+ return false;
+ };
+
+ const showTextFallback = function () {
+ image.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
+ fallback.Visibility = Windows.UI.Xaml.Visibility.Visible;
+ };
+
+ if (!tryAssignImageSource()) {
+ showTextFallback();
+ }
+
+ if (!assigned) {
+ showTextFallback();
+ }
+
+ return host;
+}
+
+export function openExternalUrl(url) {
+ try {
+ const launchOp = Windows.System.Launcher.LaunchUriAsync(new Windows.Foundation.Uri(String(url)));
+ if (launchOp && typeof NSWinRT !== "undefined" && typeof NSWinRT.onCompleted === "function") {
+ NSWinRT.onCompleted(launchOp, function (_asyncInfo, status) {
+ console.log("NativeScriptWindowsDemo: launch status", status, url);
+ }, { timeoutMs: 12000 });
+ }
+ } catch (error) {
+ console.log("NativeScriptWindowsDemo: failed to open URL", url, error && error.message ? error.message : error);
+ }
+}
diff --git a/NativeScriptWindowsDemo/App/features/components.js b/NativeScriptWindowsDemo/App/features/components.js
new file mode 100644
index 0000000..7e87aa5
--- /dev/null
+++ b/NativeScriptWindowsDemo/App/features/components.js
@@ -0,0 +1,59 @@
+import {
+ createButton,
+ createCard,
+ safeGetChildrenSize,
+ text,
+} from "../core/ui.js";
+
+export function createComponentsPage() {
+ const root = new Windows.UI.Xaml.Controls.StackPanel();
+ root.Spacing = 12;
+
+ root.Children.Append(text("Components Lab", 34));
+
+ const description = text(
+ "This tab demonstrates real WinRT controls manipulated from JavaScript event handlers.",
+ 14,
+ );
+ description.TextWrapping = Windows.UI.Xaml.TextWrapping.Wrap;
+ root.Children.Append(description);
+
+ const toggle = new Windows.UI.Xaml.Controls.ToggleSwitch();
+ toggle.Header = "Enable runtime polish";
+ toggle.IsOn = true;
+
+ const slider = new Windows.UI.Xaml.Controls.Slider();
+ slider.Minimum = 0;
+ slider.Maximum = 100;
+ slider.Value = 40;
+ slider.Width = 360;
+
+ const progress = new Windows.UI.Xaml.Controls.ProgressBar();
+ progress.Minimum = 0;
+ progress.Maximum = 100;
+ progress.Value = 40;
+ progress.Width = 360;
+
+ const status = text("State: polish enabled at 40%", 13);
+
+ const applyButton = createButton("Apply Slider To Progress", function () {
+ progress.Value = slider.Value;
+ status.Text = "State: " + (toggle.IsOn ? "polish enabled" : "polish disabled") + " at " + Math.round(slider.Value) + "%";
+ });
+
+ root.Children.Append(toggle);
+ root.Children.Append(slider);
+ root.Children.Append(progress);
+ root.Children.Append(applyButton);
+ root.Children.Append(status);
+
+ root.Children.Append(
+ createCard(
+ "Copyable Pattern",
+ "Instantiate controls, keep references, and update state on click handlers.",
+ ),
+ );
+
+ console.log("NativeScriptWindowsDemo: components children", safeGetChildrenSize(root));
+ return root;
+}
diff --git a/NativeScriptWindowsDemo/App/features/dashboard.js b/NativeScriptWindowsDemo/App/features/dashboard.js
new file mode 100644
index 0000000..f095072
--- /dev/null
+++ b/NativeScriptWindowsDemo/App/features/dashboard.js
@@ -0,0 +1,70 @@
+import {
+ createBrandImage,
+ createButton,
+ createCard,
+ openExternalUrl,
+ safeGetChildrenSize,
+ text,
+} from "../core/ui.js";
+
+export function createDashboardPage(onNavigate) {
+ const root = new Windows.UI.Xaml.Controls.StackPanel();
+ root.Spacing = 14;
+
+ root.Children.Append(text("NativeScript for Windows", 42));
+
+ const subtitle = text(
+ "Build native desktop apps with JavaScript, first-class WinRT interop, and a runtime that feels fast and direct.",
+ 16,
+ );
+ subtitle.TextWrapping = Windows.UI.Xaml.TextWrapping.Wrap;
+ root.Children.Append(subtitle);
+
+ root.Children.Append(createBrandImage(380, 200));
+
+ root.Children.Append(
+ createCard(
+ "Single JavaScript Runtime",
+ "Use one language across startup, UI composition, interop calls, and event binding.",
+ ),
+ );
+ root.Children.Append(
+ createCard(
+ "Real Native Controls",
+ "NavigationView, ToggleSwitch, SplitView, and every WinRT type are available directly from JavaScript.",
+ ),
+ );
+ root.Children.Append(
+ createCard(
+ "Production-minded Tooling",
+ "Build from Rust crates, test with sample apps, and iterate quickly without leaving native APIs behind.",
+ ),
+ );
+
+ const ctaRow = new Windows.UI.Xaml.Controls.StackPanel();
+ ctaRow.Orientation = Windows.UI.Xaml.Controls.Orientation.Horizontal;
+ ctaRow.Spacing = 8;
+
+ ctaRow.Children.Append(
+ createButton("Explore Components Demo", function () {
+ if (typeof onNavigate === "function") {
+ onNavigate("components");
+ }
+ }),
+ );
+
+ ctaRow.Children.Append(
+ createButton("Visit NativeScript.org", function () {
+ openExternalUrl("https://nativescript.org");
+ }),
+ );
+
+ root.Children.Append(ctaRow);
+
+ root.Children.Append(
+ text("Copy the patterns from each tab to build your own native app shell.", 13),
+ );
+
+ console.log("NativeScriptWindowsDemo: dashboard children", safeGetChildrenSize(root));
+ return root;
+}
diff --git a/NativeScriptWindowsDemo/App/features/examples.js b/NativeScriptWindowsDemo/App/features/examples.js
new file mode 100644
index 0000000..dca9c28
--- /dev/null
+++ b/NativeScriptWindowsDemo/App/features/examples.js
@@ -0,0 +1,84 @@
+import {
+ createButton,
+ createCard,
+ safeGetChildrenSize,
+ text,
+} from "../core/ui.js";
+
+export function createExamplesPage() {
+ const root = new Windows.UI.Xaml.Controls.StackPanel();
+ root.Spacing = 12;
+
+ root.Children.Append(text("Examples", 34));
+
+ const intro = text("Interactive examples implemented in plain JavaScript.", 14);
+ intro.TextWrapping = Windows.UI.Xaml.TextWrapping.Wrap;
+ root.Children.Append(intro);
+
+ const counterTitle = text("Counter Demo", 20);
+ root.Children.Append(counterTitle);
+
+ const counterRow = new Windows.UI.Xaml.Controls.StackPanel();
+ counterRow.Orientation = Windows.UI.Xaml.Controls.Orientation.Horizontal;
+ counterRow.Spacing = 10;
+
+ const valueText = text("0", 24);
+ let value = 0;
+
+ counterRow.Children.Append(
+ createButton("-", function () {
+ value = Math.max(value - 1, 0);
+ valueText.Text = String(value);
+ }),
+ );
+ counterRow.Children.Append(valueText);
+ counterRow.Children.Append(
+ createButton("+", function () {
+ value += 1;
+ valueText.Text = String(value);
+ }),
+ );
+
+ root.Children.Append(counterRow);
+
+ root.Children.Append(text("Action Feed", 20));
+
+ const feed = new Windows.UI.Xaml.Controls.StackPanel();
+ feed.Spacing = 4;
+
+ const addFeedEntry = function (entry) {
+ if (feed.Children.Size > 6) {
+ feed.Children.RemoveAt(0);
+ }
+ feed.Children.Append(text("- " + entry, 13));
+ };
+
+ const examplesRow = new Windows.UI.Xaml.Controls.StackPanel();
+ examplesRow.Orientation = Windows.UI.Xaml.Controls.Orientation.Horizontal;
+ examplesRow.Spacing = 8;
+
+ examplesRow.Children.Append(
+ createButton("Track Counter", function () {
+ addFeedEntry("Counter currently at " + value);
+ }),
+ );
+
+ examplesRow.Children.Append(
+ createButton("Simulate Save", function () {
+ addFeedEntry("Persisted runtime demo state");
+ }),
+ );
+
+ root.Children.Append(examplesRow);
+ root.Children.Append(feed);
+
+ root.Children.Append(
+ createCard(
+ "Why this matters",
+ "You can compose useful behavior with plain JS functions and native controls, then scale into larger modules.",
+ ),
+ );
+
+ console.log("NativeScriptWindowsDemo: examples children", safeGetChildrenSize(root));
+ return root;
+}
diff --git a/NativeScriptWindowsDemo/App/features/getting-started.js b/NativeScriptWindowsDemo/App/features/getting-started.js
new file mode 100644
index 0000000..278b54b
--- /dev/null
+++ b/NativeScriptWindowsDemo/App/features/getting-started.js
@@ -0,0 +1,43 @@
+import {
+ createBrandImage,
+ createCard,
+ safeGetChildrenSize,
+ text,
+} from "../core/ui.js";
+
+export function createGettingStartedPage() {
+ const root = new Windows.UI.Xaml.Controls.StackPanel();
+ root.Spacing = 12;
+
+ root.Children.Append(text("Getting Started", 34));
+ root.Children.Append(createBrandImage(220, 120));
+
+ const intro = text("Hello NativeScript Windows", 22);
+ root.Children.Append(intro);
+
+ const sub = text("Let us build something native together.", 16);
+ sub.TextWrapping = Windows.UI.Xaml.TextWrapping.Wrap;
+ root.Children.Append(sub);
+
+ root.Children.Append(
+ createCard(
+ "1. Explore Native Controls",
+ "Use the Components tab to try ToggleSwitch, Slider, ProgressRing, and native event wiring.",
+ ),
+ );
+ root.Children.Append(
+ createCard(
+ "2. Explore Full Examples",
+ "Use the Examples tab for interactive counter and list patterns in plain JavaScript.",
+ ),
+ );
+ root.Children.Append(
+ createCard(
+ "3. Ship and Share",
+ "Use this shell as your launchpad for real desktop experiences backed by Rust runtime speed.",
+ ),
+ );
+
+ console.log("NativeScriptWindowsDemo: getting-started children", safeGetChildrenSize(root));
+ return root;
+}
diff --git a/NativeScriptWindowsDemo/App/features/setup.js b/NativeScriptWindowsDemo/App/features/setup.js
new file mode 100644
index 0000000..50f50b1
--- /dev/null
+++ b/NativeScriptWindowsDemo/App/features/setup.js
@@ -0,0 +1,43 @@
+import {
+ createButton,
+ createCard,
+ openExternalUrl,
+ safeGetChildrenSize,
+ text,
+} from "../core/ui.js";
+
+export function createSetupPage() {
+ const root = new Windows.UI.Xaml.Controls.StackPanel();
+ root.Spacing = 12;
+
+ root.Children.Append(text("Setup", 34));
+
+ const body = text(
+ "Bootstrap your own app from the NativeScript template and map these demo tabs to your production flows.",
+ 14,
+ );
+ body.TextWrapping = Windows.UI.Xaml.TextWrapping.Wrap;
+ root.Children.Append(body);
+
+ root.Children.Append(
+ createButton("Open NativeScript Starter Templates", function () {
+ openExternalUrl("https://github.com/NativeScript");
+ }),
+ );
+
+ root.Children.Append(
+ createCard(
+ "Runtime + UI",
+ "This sample runs pure JavaScript while driving native WinRT controls with no JSX/TSX layer.",
+ ),
+ );
+ root.Children.Append(
+ createCard(
+ "Modular Features",
+ "Each tab lives in its own file so teams can evolve pages independently.",
+ ),
+ );
+
+ console.log("NativeScriptWindowsDemo: setup children", safeGetChildrenSize(root));
+ return root;
+}
diff --git a/NativeScriptWindowsDemo/App/main.js b/NativeScriptWindowsDemo/App/main.js
index 478b712..c4dee64 100644
--- a/NativeScriptWindowsDemo/App/main.js
+++ b/NativeScriptWindowsDemo/App/main.js
@@ -1,159 +1,169 @@
-console.log("NativeScriptWindowsDemo: booting JS UI demo");
-
-function createSectionTitle(text) {
- const title = new Windows.UI.Xaml.Controls.TextBlock();
- title.Text = text;
- title.FontSize = 18;
- title.Margin = new Windows.UI.Xaml.Thickness(0, 16, 0, 8);
- return title;
+import { createButton, text, withContentPadding } from "./core/ui.js";
+import { createDashboardPage } from "./features/dashboard.js";
+import { createGettingStartedPage } from "./features/getting-started.js";
+import { createSetupPage } from "./features/setup.js";
+import { createComponentsPage } from "./features/components.js";
+import { createExamplesPage } from "./features/examples.js";
+
+console.log("NativeScriptWindowsDemo: booting");
+
+function createShell() {
+ console.log("NativeScriptWindowsDemo: createShell start");
+ try {
+ const navigation = new Windows.UI.Xaml.Controls.NavigationView();
+ navigation.PaneTitle = "NativeScript Studio";
+ navigation.IsSettingsVisible = false;
+ navigation.PaneDisplayMode = Windows.UI.Xaml.Controls.NavigationViewPaneDisplayMode.Left;
+ navigation.IsBackButtonVisible = Windows.UI.Xaml.Controls.NavigationViewBackButtonVisible.Collapsed;
+ navigation.IsPaneToggleButtonVisible = true;
+
+ console.log("NativeScriptWindowsDemo: createShell done (NavigationView)");
+ return { kind: "navigation", navigation };
+ } catch (error) {
+ console.log(
+ "NativeScriptWindowsDemo: NavigationView unavailable, falling back to SplitView",
+ error && error.message ? error.message : error,
+ );
+ }
+
+ const split = new Windows.UI.Xaml.Controls.SplitView();
+ split.DisplayMode = Windows.UI.Xaml.Controls.SplitViewDisplayMode.Inline;
+ split.IsPaneOpen = true;
+ split.OpenPaneLength = 260;
+
+ const pane = new Windows.UI.Xaml.Controls.StackPanel();
+ pane.Spacing = 6;
+ pane.Children.Append(text("NativeScript Studio", 22));
+ pane.Children.Append(text("Windows runtime demo tabs", 12));
+
+ split.Pane = pane;
+
+ console.log("NativeScriptWindowsDemo: createShell done (SplitView fallback)");
+ return { kind: "split", split, pane };
}
-function createControlCard() {
- const border = new Windows.UI.Xaml.Controls.Border();
- border.BorderBrush = new Windows.UI.Xaml.Media.SolidColorBrush(Windows.UI.Colors.LightGray);
- border.BorderThickness = new Windows.UI.Xaml.Thickness(1);
- border.Padding = new Windows.UI.Xaml.Thickness(12);
- border.CornerRadius = new Windows.UI.Xaml.CornerRadius(8);
-
- const stack = new Windows.UI.Xaml.Controls.StackPanel();
- stack.Spacing = 8;
- border.Child = stack;
- return { border, stack };
+function createNavigationItem(key, label, iconGlyph) {
+ const item = new Windows.UI.Xaml.Controls.NavigationViewItem();
+ item.Tag = key;
+ item.Content = String(label);
+
+ const icon = new Windows.UI.Xaml.Controls.FontIcon();
+ icon.Glyph = iconGlyph;
+ item.Icon = icon;
+
+ return item;
+}
+
+function createScrollablePage(content) {
+ const scroll = new Windows.UI.Xaml.Controls.ScrollViewer();
+ scroll.VerticalScrollBarVisibility = Windows.UI.Xaml.Controls.ScrollBarVisibility.Auto;
+ scroll.HorizontalScrollBarVisibility = Windows.UI.Xaml.Controls.ScrollBarVisibility.Disabled;
+ scroll.Content = withContentPadding(content);
+ return scroll;
}
-function buildDemoLayout() {
- const rootScroll = new Windows.UI.Xaml.Controls.ScrollViewer();
- rootScroll.VerticalScrollBarVisibility = Windows.UI.Xaml.Controls.ScrollBarVisibility.Auto;
-
- const content = new Windows.UI.Xaml.Controls.StackPanel();
- content.Margin = new Windows.UI.Xaml.Thickness(24, 20, 24, 20);
- content.Spacing = 10;
- rootScroll.Content = content;
-
- const header = new Windows.UI.Xaml.Controls.TextBlock();
- header.Text = "NativeScript Windows Demo";
- header.FontSize = 30;
- header.FontWeight = Windows.UI.Text.FontWeights.SemiBold;
- content.Children.Append(header);
-
- const subtitle = new Windows.UI.Xaml.Controls.TextBlock();
- subtitle.Text = "WinRT XAML controls created directly from JavaScript";
- subtitle.FontSize = 14;
- subtitle.Foreground = new Windows.UI.Xaml.Media.SolidColorBrush(Windows.UI.Colors.DimGray);
- subtitle.Margin = new Windows.UI.Xaml.Thickness(0, 0, 0, 6);
- content.Children.Append(subtitle);
-
- content.Children.Append(createSectionTitle("Inputs"));
- const inputCard = createControlCard();
-
- const nameBox = new Windows.UI.Xaml.Controls.TextBox();
- nameBox.Header = "Display name";
- nameBox.PlaceholderText = "Type your name";
-
- const password = new Windows.UI.Xaml.Controls.PasswordBox();
- password.Header = "Password";
-
- const toggle = new Windows.UI.Xaml.Controls.ToggleSwitch();
- toggle.Header = "Enable notifications";
- toggle.IsOn = true;
-
- inputCard.stack.Children.Append(nameBox);
- inputCard.stack.Children.Append(password);
- inputCard.stack.Children.Append(toggle);
- content.Children.Append(inputCard.border);
-
- content.Children.Append(createSectionTitle("Selection"));
- const selectionCard = createControlCard();
-
- const combo = new Windows.UI.Xaml.Controls.ComboBox();
- combo.Header = "Theme";
- combo.Items.Append("Ocean");
- combo.Items.Append("Forest");
- combo.Items.Append("Sunset");
- combo.SelectedIndex = 0;
-
- const sliderLabel = new Windows.UI.Xaml.Controls.TextBlock();
- sliderLabel.Text = "Volume";
- const slider = new Windows.UI.Xaml.Controls.Slider();
- slider.Minimum = 0;
- slider.Maximum = 100;
- slider.Value = 72;
-
- const progress = new Windows.UI.Xaml.Controls.ProgressBar();
- progress.Minimum = 0;
- progress.Maximum = 100;
- progress.Value = slider.Value;
- progress.Height = 8;
-
- slider.ValueChanged = function (sender) {
- progress.Value = sender.Value;
- };
-
- selectionCard.stack.Children.Append(combo);
- selectionCard.stack.Children.Append(sliderLabel);
- selectionCard.stack.Children.Append(slider);
- selectionCard.stack.Children.Append(progress);
- content.Children.Append(selectionCard.border);
-
- content.Children.Append(createSectionTitle("Actions"));
- const actionCard = createControlCard();
- const actionRow = new Windows.UI.Xaml.Controls.StackPanel();
- actionRow.Orientation = Windows.UI.Xaml.Controls.Orientation.Horizontal;
- actionRow.Spacing = 10;
-
- const applyButton = new Windows.UI.Xaml.Controls.Button();
- applyButton.Content = "Apply";
- applyButton.MinWidth = 120;
-
- const resetButton = new Windows.UI.Xaml.Controls.Button();
- resetButton.Content = "Reset";
- resetButton.MinWidth = 120;
-
- const status = new Windows.UI.Xaml.Controls.TextBlock();
- status.Text = "Ready";
- status.Margin = new Windows.UI.Xaml.Thickness(0, 6, 0, 0);
-
- applyButton.Click = function () {
- const selectedTheme = combo.SelectedItem ? String(combo.SelectedItem) : "Unknown";
- status.Text = "Saved for " + (nameBox.Text || "Guest") + " with " + selectedTheme + " theme";
- };
-
- resetButton.Click = function () {
- nameBox.Text = "";
- password.Password = "";
- toggle.IsOn = true;
- combo.SelectedIndex = 0;
- slider.Value = 72;
- status.Text = "Reset complete";
- };
-
- actionRow.Children.Append(applyButton);
- actionRow.Children.Append(resetButton);
- actionCard.stack.Children.Append(actionRow);
- actionCard.stack.Children.Append(status);
- content.Children.Append(actionCard.border);
-
- content.Children.Append(createSectionTitle("Data List"));
- const listCard = createControlCard();
- const list = new Windows.UI.Xaml.Controls.ListView();
- list.Height = 180;
- list.Items.Append("Dashboard");
- list.Items.Append("Analytics");
- list.Items.Append("Notifications");
- list.Items.Append("Reports");
- list.Items.Append("Settings");
- listCard.stack.Children.Append(list);
- content.Children.Append(listCard.border);
-
- return rootScroll;
+function buildApp() {
+ console.log("NativeScriptWindowsDemo: buildApp start");
+
+ const shell = createShell();
+ const navItemsByKey = {};
+
+ const pages = {
+ dashboard: createScrollablePage(createDashboardPage(showPage)),
+ gettingStarted: createScrollablePage(createGettingStartedPage()),
+ setup: createScrollablePage(createSetupPage()),
+ components: createScrollablePage(createComponentsPage()),
+ examples: createScrollablePage(createExamplesPage()),
+ };
+
+ function showPage(key) {
+ const page = pages[key] || pages.dashboard;
+ if (shell.kind === "navigation") {
+ const host = shell.contentHost;
+ if (host && typeof host === "object") {
+ host.Child = page;
+ } else {
+ shell.navigation.Content = page;
+ }
+ return;
+ }
+
+ shell.split.Content = page;
+ shell.split.IsPaneOpen = true;
+ }
+
+ if (shell.kind === "navigation") {
+ const host = new Windows.UI.Xaml.Controls.Border();
+ shell.contentHost = host;
+ shell.navigation.Content = host;
+
+ const dashboardItem = createNavigationItem("dashboard", "Overview", "\uE80F");
+ const gettingStartedItem = createNavigationItem("gettingStarted", "Getting Started", "\uE8FD");
+ const setupItem = createNavigationItem("setup", "Setup", "\uE713");
+ const componentsItem = createNavigationItem("components", "Components", "\uE8B8");
+ const examplesItem = createNavigationItem("examples", "Examples", "\uE9CE");
+
+ navItemsByKey.dashboard = dashboardItem;
+ navItemsByKey.gettingStarted = gettingStartedItem;
+ navItemsByKey.setup = setupItem;
+ navItemsByKey.components = componentsItem;
+ navItemsByKey.examples = examplesItem;
+
+ shell.navigation.MenuItems.Append(dashboardItem);
+ shell.navigation.MenuItems.Append(gettingStartedItem);
+ shell.navigation.MenuItems.Append(setupItem);
+ shell.navigation.MenuItems.Append(componentsItem);
+ shell.navigation.MenuItems.Append(examplesItem);
+
+ shell.navigation.SelectedItem = dashboardItem;
+ host.Child = pages.dashboard;
+
+ const resolveNavigationKey = function () {
+ const keys = Object.keys(navItemsByKey);
+
+ for (let i = 0; i < keys.length; i += 1) {
+ const key = keys[i];
+ const item = navItemsByKey[key];
+ if (!item) {
+ continue;
+ }
+
+ try {
+ if (item.IsSelected) {
+ return key;
+ }
+ } catch (_error) {
+ }
+ }
+
+ return null;
+ };
+
+ shell.navigation.SelectionChanged = function () {
+ const key = resolveNavigationKey();
+ if (key && pages[key]) {
+ showPage(key);
+ }
+ };
+ } else {
+ shell.pane.Children.Append(createButton("Overview", function () { showPage("dashboard"); }));
+ shell.pane.Children.Append(createButton("Getting Started", function () { showPage("gettingStarted"); }));
+ shell.pane.Children.Append(createButton("Setup", function () { showPage("setup"); }));
+ shell.pane.Children.Append(createButton("Components", function () { showPage("components"); }));
+ shell.pane.Children.Append(createButton("Examples", function () { showPage("examples"); }));
+ }
+
+ showPage("dashboard");
+ console.log("NativeScriptWindowsDemo: buildApp done");
+ return shell.kind === "navigation" ? shell.navigation : shell.split;
}
try {
- const window = Windows.UI.Xaml.Window.Current;
- window.Content = buildDemoLayout();
- window.Activate();
- console.log("NativeScriptWindowsDemo: layout created");
+ const window = Windows.UI.Xaml.Window.Current;
+ window.Content = buildApp();
+ window.Activate();
+ console.log("NativeScriptWindowsDemo: loaded");
} catch (error) {
- console.log("NativeScriptWindowsDemo: failed to build layout", error && error.message ? error.message : error);
- throw error;
+ console.log("NativeScriptWindowsDemo: failed", error && error.message ? error.message : error);
+ throw error;
}
diff --git a/NativeScriptWindowsDemo/Assets/LockScreenLogo.scale-200.png b/NativeScriptWindowsDemo/Assets/LockScreenLogo.scale-200.png
index 735f57a..502dbad 100644
Binary files a/NativeScriptWindowsDemo/Assets/LockScreenLogo.scale-200.png and b/NativeScriptWindowsDemo/Assets/LockScreenLogo.scale-200.png differ
diff --git a/NativeScriptWindowsDemo/Assets/SplashScreen.scale-200.png b/NativeScriptWindowsDemo/Assets/SplashScreen.scale-200.png
index 023e7f1..26a858c 100644
Binary files a/NativeScriptWindowsDemo/Assets/SplashScreen.scale-200.png and b/NativeScriptWindowsDemo/Assets/SplashScreen.scale-200.png differ
diff --git a/NativeScriptWindowsDemo/Assets/Square150x150Logo.scale-200.png b/NativeScriptWindowsDemo/Assets/Square150x150Logo.scale-200.png
index af49fec..984b1d0 100644
Binary files a/NativeScriptWindowsDemo/Assets/Square150x150Logo.scale-200.png and b/NativeScriptWindowsDemo/Assets/Square150x150Logo.scale-200.png differ
diff --git a/NativeScriptWindowsDemo/Assets/Square44x44Logo.scale-200.png b/NativeScriptWindowsDemo/Assets/Square44x44Logo.scale-200.png
index ce342a2..cb6323d 100644
Binary files a/NativeScriptWindowsDemo/Assets/Square44x44Logo.scale-200.png and b/NativeScriptWindowsDemo/Assets/Square44x44Logo.scale-200.png differ
diff --git a/NativeScriptWindowsDemo/Assets/Square44x44Logo.targetsize-24_altform-unplated.png b/NativeScriptWindowsDemo/Assets/Square44x44Logo.targetsize-24_altform-unplated.png
index f6c02ce..8b8dce0 100644
Binary files a/NativeScriptWindowsDemo/Assets/Square44x44Logo.targetsize-24_altform-unplated.png and b/NativeScriptWindowsDemo/Assets/Square44x44Logo.targetsize-24_altform-unplated.png differ
diff --git a/NativeScriptWindowsDemo/Assets/StoreLogo.png b/NativeScriptWindowsDemo/Assets/StoreLogo.png
index 7385b56..001ccfc 100644
Binary files a/NativeScriptWindowsDemo/Assets/StoreLogo.png and b/NativeScriptWindowsDemo/Assets/StoreLogo.png differ
diff --git a/NativeScriptWindowsDemo/Assets/Wide310x150Logo.scale-200.png b/NativeScriptWindowsDemo/Assets/Wide310x150Logo.scale-200.png
index 288995b..26ea95d 100644
Binary files a/NativeScriptWindowsDemo/Assets/Wide310x150Logo.scale-200.png and b/NativeScriptWindowsDemo/Assets/Wide310x150Logo.scale-200.png differ
diff --git a/NativeScriptWindowsDemo/Assets/cover.png b/NativeScriptWindowsDemo/Assets/cover.png
new file mode 100644
index 0000000..f95aba2
Binary files /dev/null and b/NativeScriptWindowsDemo/Assets/cover.png differ
diff --git a/NativeScriptWindowsDemo/NativeScriptWindowsDemo.csproj b/NativeScriptWindowsDemo/NativeScriptWindowsDemo.csproj
index e7ade5e..1809675 100644
--- a/NativeScriptWindowsDemo/NativeScriptWindowsDemo.csproj
+++ b/NativeScriptWindowsDemo/NativeScriptWindowsDemo.csproj
@@ -37,6 +37,9 @@
PreserveNewest
+
+ PreserveNewest
+
nativescript.dll
diff --git a/NativeScriptWindowsDemo/RuntimeHost.cs b/NativeScriptWindowsDemo/RuntimeHost.cs
index f1ac08a..6da8cd5 100644
--- a/NativeScriptWindowsDemo/RuntimeHost.cs
+++ b/NativeScriptWindowsDemo/RuntimeHost.cs
@@ -1,5 +1,7 @@
using System;
+using System.Diagnostics;
using System.IO;
+using System.Text;
using System.Runtime.InteropServices;
namespace NativeScriptWindowsDemo
@@ -8,9 +10,12 @@ internal sealed class RuntimeHost : IDisposable
{
private const string NativeScriptLibrary = "nativescript";
- [DllImport("kernel32.dll")]
+ [DllImport("kernel32.dll", SetLastError = true)]
private static extern bool AttachConsole(int dwProcessId);
+ [DllImport("kernel32.dll", SetLastError = true)]
+ private static extern bool AllocConsole();
+
private const int ATTACH_PARENT_PROCESS = -1;
[DllImport(NativeScriptLibrary, EntryPoint = nameof(runtime_init))]
@@ -28,6 +33,46 @@ internal sealed class RuntimeHost : IDisposable
private long _runtime;
private bool _initialized;
+ private static void LogHost(string message)
+ {
+ Debug.WriteLine("[RuntimeHost] " + message);
+ try
+ {
+ Console.WriteLine("[RuntimeHost] " + message);
+ }
+ catch
+ {
+ // No attached console stream, debug output still receives logs.
+ }
+ }
+
+ private static void EnsureDiagnosticsConsole()
+ {
+ var attached = AttachConsole(ATTACH_PARENT_PROCESS);
+ if (!attached)
+ {
+ var allocated = AllocConsole();
+ if (!allocated)
+ {
+ var error = Marshal.GetLastWin32Error();
+ LogHost("No console attached (Attach/Alloc failed, Win32=" + error + ").");
+ return;
+ }
+ }
+
+ try
+ {
+ var stdout = Console.OpenStandardOutput();
+ var writer = new StreamWriter(stdout, new UTF8Encoding(false)) { AutoFlush = true };
+ Console.SetOut(writer);
+ Console.SetError(writer);
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine("[RuntimeHost] Failed to rebind console streams: " + ex.Message);
+ }
+ }
+
public void Initialize()
{
if (_initialized)
@@ -35,8 +80,7 @@ public void Initialize()
return;
}
- // Best effort for CLI-launched debug sessions.
- AttachConsole(ATTACH_PARENT_PROCESS);
+ EnsureDiagnosticsConsole();
runtime_install_ctrlc_handler(0);
_runtime = runtime_init(AppContext.BaseDirectory);
diff --git a/TestApp/RuntimeHost.cs b/TestApp/RuntimeHost.cs
index b5946dc..3592fc0 100644
--- a/TestApp/RuntimeHost.cs
+++ b/TestApp/RuntimeHost.cs
@@ -1,5 +1,7 @@
using System;
+using System.Diagnostics;
using System.IO;
+using System.Text;
using System.Runtime.InteropServices;
namespace TestApp
@@ -8,9 +10,12 @@ internal sealed class RuntimeHost : IDisposable
{
private const string NativeScriptLibrary = "nativescript";
- [DllImport("kernel32.dll")]
+ [DllImport("kernel32.dll", SetLastError = true)]
private static extern bool AttachConsole(int dwProcessId);
+ [DllImport("kernel32.dll", SetLastError = true)]
+ private static extern bool AllocConsole();
+
private const int ATTACH_PARENT_PROCESS = -1;
[DllImport(NativeScriptLibrary, EntryPoint = nameof(runtime_init))]
@@ -28,6 +33,46 @@ internal sealed class RuntimeHost : IDisposable
private long _runtime;
private bool _initialized;
+ private static void LogHost(string message)
+ {
+ Debug.WriteLine("[RuntimeHost] " + message);
+ try
+ {
+ Console.WriteLine("[RuntimeHost] " + message);
+ }
+ catch
+ {
+ // No attached console stream, debug output still receives logs.
+ }
+ }
+
+ private static void EnsureDiagnosticsConsole()
+ {
+ var attached = AttachConsole(ATTACH_PARENT_PROCESS);
+ if (!attached)
+ {
+ var allocated = AllocConsole();
+ if (!allocated)
+ {
+ var error = Marshal.GetLastWin32Error();
+ LogHost("No console attached (Attach/Alloc failed, Win32=" + error + ").");
+ return;
+ }
+ }
+
+ try
+ {
+ var stdout = Console.OpenStandardOutput();
+ var writer = new StreamWriter(stdout, new UTF8Encoding(false)) { AutoFlush = true };
+ Console.SetOut(writer);
+ Console.SetError(writer);
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine("[RuntimeHost] Failed to rebind console streams: " + ex.Message);
+ }
+ }
+
public void Initialize()
{
if (_initialized)
@@ -35,8 +80,7 @@ public void Initialize()
return;
}
- // Best effort for CLI-launched debug sessions.
- AttachConsole(ATTACH_PARENT_PROCESS);
+ EnsureDiagnosticsConsole();
runtime_install_ctrlc_handler(0);
_runtime = runtime_init(AppContext.BaseDirectory);
diff --git a/libs/x64/nativescript.dll b/libs/x64/nativescript.dll
index e0c0058..c48c43c 100644
Binary files a/libs/x64/nativescript.dll and b/libs/x64/nativescript.dll differ
diff --git a/metadata/src/declarations/event_declaration.rs b/metadata/src/declarations/event_declaration.rs
index 0e49194..96b7c3d 100644
--- a/metadata/src/declarations/event_declaration.rs
+++ b/metadata/src/declarations/event_declaration.rs
@@ -204,6 +204,21 @@ impl EventDeclaration {
.flatten()
}
+ /// Returns the full name of the underlying delegate type, regardless of
+ /// whether it's a non-generic delegate, generic delegate, or generic
+ /// delegate instance (e.g. `TypedEventHandler`).
+ pub fn delegate_type_full_name(&self) -> Option {
+ self.type_
+ .as_ref()
+ .map(|f| f.as_declaration().full_name().to_string())
+ }
+
+ /// Returns the GUID of the underlying delegate type for any kind of
+ /// delegate declaration (non-generic or generic instance).
+ pub fn delegate_type_id(&self) -> Option {
+ self.type_.as_ref().map(|f| f.id())
+ }
+
pub fn add_method(&self) -> &MethodDeclaration {
&self.add_method
}
diff --git a/metadata/src/declarations/interface_declaration/generic_interface_instance_declaration.rs b/metadata/src/declarations/interface_declaration/generic_interface_instance_declaration.rs
index 983580b..cbf17e9 100644
--- a/metadata/src/declarations/interface_declaration/generic_interface_instance_declaration.rs
+++ b/metadata/src/declarations/interface_declaration/generic_interface_instance_declaration.rs
@@ -74,6 +74,24 @@ impl GenericInterfaceInstanceDeclaration {
full_name
}
}
+
+ pub fn new_with_full_name(
+ open_metadata: Option<&IMetaDataImport2>,
+ open_token: CorTokenType,
+ full_name: String,
+ ) -> Self {
+ Self {
+ base: InterfaceDeclaration::new_with_kind(
+ DeclarationKind::GenericInterfaceInstance,
+ open_metadata,
+ open_token,
+ ),
+ closed_metadata: None,
+ closed_token: CorTokenType::default(),
+ full_name,
+ }
+ }
+
pub fn id(&self) -> GUID {
return GenericInstanceIdBuilder::generate_id(self);
}
diff --git a/nativescript/Cargo.toml b/nativescript/Cargo.toml
index 4ad8af9..691304c 100644
--- a/nativescript/Cargo.toml
+++ b/nativescript/Cargo.toml
@@ -10,7 +10,7 @@ edition = "2021"
[lib]
name = "nativescript"
-crate-type = ["dylib"]
+crate-type = ["cdylib", "rlib"]
[dependencies]
diff --git a/runtime/src/helpers.rs b/runtime/src/helpers.rs
index f08f3fd..9169a24 100644
--- a/runtime/src/helpers.rs
+++ b/runtime/src/helpers.rs
@@ -1,6 +1,126 @@
+use metadata::declarations::base_class_declaration::BaseClassDeclarationImpl;
+use metadata::declarations::class_declaration::ClassDeclaration;
+use metadata::declarations::declaration::DeclarationKind;
+use metadata::declarations::enum_declaration::EnumDeclaration;
+use metadata::declarations::interface_declaration::InterfaceDeclaration;
+use metadata::meta_data_reader::MetadataReader;
+use metadata::signature::Signature;
use regex::Regex;
+use windows::core::HRESULT;
+
use crate::value::NativeType;
+/// E_FAIL — used as the HRESULT for failed COM/WinRT calls originating from JS.
+#[inline]
+pub fn call_failure() -> HRESULT {
+ HRESULT(0x8000_4005u32 as i32)
+}
+
+/// Maps a WinRT signature string to the FFI ABI [`NativeType`] used to describe
+/// the native parameter slot.
+#[inline]
+pub fn ffi_native_type_from_signature(signature: &str) -> NativeType {
+ let signature = signature.trim();
+ let by_ref_inner = signature.strip_prefix("ByRef ").unwrap_or(signature);
+
+ if let Some(element) = by_ref_inner.strip_suffix("[]") {
+ return match element {
+ "UInt8" | "Uint8" | "Int8" | "Byte" | "SByte" => NativeType::Buffer,
+ _ => NativeType::Pointer,
+ };
+ }
+
+ if by_ref_inner.starts_with("Var!")
+ || by_ref_inner.starts_with("MVar!")
+ || by_ref_inner.contains('.')
+ || by_ref_inner == "Object"
+ || by_ref_inner == "Guid"
+ {
+ return NativeType::Pointer;
+ }
+
+ match by_ref_inner {
+ "Void" => NativeType::Void,
+ "String" => NativeType::Pointer,
+ "Char16" => NativeType::U16,
+ "Boolean" => NativeType::Bool,
+ "UInt8" | "Uint8" | "Byte" => NativeType::U8,
+ "Int8" | "SByte" => NativeType::I8,
+ "UInt16" => NativeType::U16,
+ "UInt32" => NativeType::U32,
+ "UInt64" => NativeType::U64,
+ "Int16" => NativeType::I16,
+ "Int32" => NativeType::I32,
+ "Int64" => NativeType::I64,
+ "Single" => NativeType::F32,
+ "Double" => NativeType::F64,
+ _ => NativeType::Pointer,
+ }
+}
+
+/// Generic type parameters in projected WinRT signatures (`Var!`/`MVar!`) map
+/// to opaque object pointers; everything else is unchanged.
+#[inline]
+pub fn normalize_parameter_signature(signature: &str) -> &str {
+ if signature.starts_with("Var!") || signature.starts_with("MVar!") {
+ return "Object";
+ }
+ signature
+}
+
+/// Best-effort mapping of a WinRT signature to the [`NativeType`] used when
+/// parsing JS arguments. Falls back to [`NativeType::Pointer`] for anything not
+/// directly representable as a primitive.
+#[inline]
+pub fn parse_native_type_from_signature(signature: &str) -> NativeType {
+ if signature.starts_with("Var!") || signature.starts_with("MVar!") {
+ return NativeType::Pointer;
+ }
+
+ if let Ok(native_type) = NativeType::try_from(signature) {
+ if native_type != NativeType::Pointer {
+ return native_type;
+ }
+ }
+
+ if let Some(declaration) = MetadataReader::find_by_name(signature) {
+ let lock = declaration.read();
+ match lock.kind() {
+ DeclarationKind::Enum => {
+ if let Some(enum_declaration) = lock.as_any().downcast_ref::() {
+ let underlying_signature = Signature::as_string(&enum_declaration.type_());
+ if let Ok(enum_native) = NativeType::try_from(underlying_signature.as_str()) {
+ return enum_native;
+ }
+ }
+ return NativeType::I32;
+ }
+ DeclarationKind::Class => {
+ if let Some(class_declaration) = lock.as_any().downcast_ref::() {
+ if class_declaration.base_full_name() == "System.Enum" {
+ return NativeType::I32;
+ }
+ }
+ }
+ _ => {}
+ }
+ }
+
+ NativeType::Pointer
+}
+
+/// Recursively counts methods of the inherited interface chain — used to
+/// compute the vtable offset of a method declared on a parent interface.
+pub fn inherited_interface_method_count(interfaces: &[&InterfaceDeclaration]) -> usize {
+ let mut count = 0usize;
+ for interface in interfaces {
+ count += interface.methods().len();
+ count += inherited_interface_method_count(interface.implemented_interfaces().as_slice());
+ }
+ count
+}
+
+
pub struct GenericReturnTypes<'s> {
names: Vec<&'s str>,
types: usize,
@@ -41,44 +161,3 @@ pub fn get_generic_return_types(name: &str) -> GenericReturnTypes {
GenericReturnTypes { names, types }
}
-
-/// Shared mapping from WinRT signature string to FFI `NativeType`.
-/// Used by `MethodCall` and `PropertyCall` during construction.
-#[inline]
-pub(crate) fn ffi_native_type_from_signature(signature: &str) -> NativeType {
- let signature = signature.trim();
- let by_ref_inner = signature.strip_prefix("ByRef ").unwrap_or(signature);
-
- if let Some(element) = by_ref_inner.strip_suffix("[]") {
- return match element {
- "UInt8" | "Uint8" | "Int8" | "Byte" | "SByte" => NativeType::Buffer,
- _ => NativeType::Pointer,
- };
- }
-
- if by_ref_inner.starts_with("Var!")
- || by_ref_inner.contains('.')
- || by_ref_inner == "Object"
- || by_ref_inner == "Guid"
- {
- return NativeType::Pointer;
- }
-
- match by_ref_inner {
- "Void" => NativeType::Void,
- "String" => NativeType::Pointer,
- "Char16" => NativeType::U16,
- "Boolean" => NativeType::Bool,
- "UInt8" | "Uint8" | "Byte" => NativeType::U8,
- "Int8" | "SByte" => NativeType::I8,
- "UInt16" => NativeType::U16,
- "UInt32" => NativeType::U32,
- "UInt64" => NativeType::U64,
- "Int16" => NativeType::I16,
- "Int32" => NativeType::I32,
- "Int64" => NativeType::I64,
- "Single" => NativeType::F32,
- "Double" => NativeType::F64,
- _ => NativeType::Pointer,
- }
-}
diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs
index a4909ef..c154454 100644
--- a/runtime/src/lib.rs
+++ b/runtime/src/lib.rs
@@ -14,18 +14,19 @@ mod proxy_manifest_loader;
use std::any::Any;
use std::cell::RefCell;
-use std::collections::HashSet;
+use std::collections::{HashMap, HashSet};
use std::ffi::{c_char, c_void, CString};
use std::fs;
-use std::hash::{Hash, Hasher};
-use ahash::AHasher;
use std::mem::MaybeUninit;
use std::ops::Deref;
+use std::panic::{catch_unwind, AssertUnwindSafe};
use std::path::{Path, PathBuf};
use std::ptr::{addr_of, addr_of_mut, NonNull};
use std::process::Command;
use std::result;
+use std::sync::atomic::{AtomicPtr, AtomicU32, AtomicU64, Ordering};
use std::sync::{Arc, Once, OnceLock};
+use std::thread::ThreadId;
use std::time::{Duration, Instant};
use libffi::high::arg;
use libffi::low::{CodePtr, ffi_type};
@@ -35,7 +36,7 @@ use parking_lot::lock_api::{MappedRwLockReadGuard, MappedRwLockWriteGuard, RwLoc
use v8::{FunctionTemplate, Global, Local, Number, Object};
use windows::core::{HSTRING, IUnknown, GUID, HRESULT, Interface, IUnknown_Vtbl, PCWSTR, IInspectable, Error};
use windows::Foundation::GuidHelper;
-use windows::Win32::System::Com::{IDispatch, IDispatch_Vtbl};
+use windows::Win32::System::Com::{IAgileObject, IDispatch, IDispatch_Vtbl};
use windows::Win32::System::Console::GetConsoleWindow;
use windows::Win32::System::WinRT::{IActivationFactory, RoActivateInstance, RoGetActivationFactory, RoInitialize, RoUninitialize, RO_INIT_SINGLETHREADED};
use windows::Win32::System::WinRT::Metadata::ELEMENT_TYPE_CHAR;
@@ -53,6 +54,7 @@ use metadata::declarations::delegate_declaration::DelegateDeclarationImpl;
use metadata::declarations::delegate_declaration::generic_delegate_declaration::GenericDelegateDeclaration;
use metadata::declarations::delegate_declaration::generic_delegate_instance_declaration::GenericDelegateInstanceDeclaration;
use metadata::declarations::enum_declaration::EnumDeclaration;
+use metadata::declarations::event_declaration::EventDeclaration;
use metadata::declarations::interface_declaration::InterfaceDeclaration;
use metadata::declarations::namespace_declaration::NamespaceDeclaration;
use metadata::declarations::type_declaration::TypeDeclaration;
@@ -72,6 +74,7 @@ use crate::value::{ffi_parse_bool_arg, ffi_parse_buffer_arg, ffi_parse_f32_arg,
use crate::proxy_manifest_loader::SbgManifestLoader;
thread_local!(static ISOLATE: RefCell