Skip to content

fix: WinRT projection gaps behind core storage, settings and picker APIs - #37

Merged
triniwiz merged 2 commits into
mainfrom
fix/winrt-projection-gaps
Nov 6, 2026
Merged

triniwiz merged 2 commits into
mainfrom
fix/winrt-projection-gaps

Conversation

@triniwiz

@triniwiz triniwiz commented Nov 6, 2026

Copy link
Copy Markdown
Member

Runtime side of NativeScript/NativeScript#11613, NativeScript/NativeScript#11614 and NativeScript/NativeScript#11616. The core side is on NativeScript feat/windows (097ece1ee, 5513b7fd6).

Projection (classic + napi)

  • Interface-typed returns wrap as their runtime class. IPropertySet declares no members of its own, only the generic IMap/IIterable it requires, so ApplicationData.Current.LocalSettings.Values and CoreApplication.Properties came back with no HasKey/Lookup/Insert/First. The classic return_value_from_kind path and the napi proxy path now resolve the runtime class from GetRuntimeClassName, as the ns_proxy builder already did.
  • Public names reach [Overload]-only methods. StorageFile.CopyAsync/MoveAsync overloads are all named CopyOverload*/MoveOverload*, so file.CopyAsync(...) was undefined on classic. The class member index now also records the public name. Prototype methods switch overload by argument count, so RenameAsync(name) and DeleteAsync() no longer hit the overload that takes an extra option argument.
  • Picker owner window. Objects implementing IInitializeWithWindow were initialized with GetConsoleWindow(), which is null in a packaged app, so pickers failed. They now get a visible, unowned top-level window of this thread (then this process, then the console). The napi activation paths now do the same.

.NET bridge

  • WinRT wrappers don't expose __native_ptr, so a WinRT object passed to dotnet.invoke fell through to toString() and arrived as System.String. The encoders (classic and napi, args and callback values) now send the wrapper's COM instance as a WinRT ref (tag 0x0A) directly. The pointer is borrowed: the wrapper keeps it alive during the synchronous coercion, and the managed wrapper takes its own reference.
  • CoerceBin projects WinRT refs through WinRT.MarshalInspectable<object>.FromAbi (by reflection) when C#/WinRT is loaded, so the object is a real FileOpenPicker and works with WinRT.Interop.InitializeWithWindow. It falls back to the existing Marshal paths otherwise.

Not runtime bugs (from the same reports)

  • HSTRING marshaling is lossless. Emoji, combining marks and embedded NULs round-trip through JsonValue, PropertySet and the clipboard. Clipboard NUL truncation is the OS behavior (clipboard text is NUL-terminated).
  • Task-returning dotnet.invoke calls stopped blocking in a6666c5. The reporter is on 0.1.0-alpha.144, which predates that.

Testing

  • New projection_test.rs: IPropertySet return members; CopyAsync/MoveAsync/RenameAsync(name)/DeleteAsync() against a temp folder.
  • cargo test -p runtime --lib: 165 passed, 11 failed. The 11 are the known environment-dependent baseline failures and are unchanged.
  • windows-napi npm test: 439/439. dotnet-bridge-tests: 136/136.
  • The rewritten core file-system module passes 30/30 checks on classic (sync only, since the test runner has no event loop) and 34/34 on napi (sync and async). Core application-settings passes 10/10 on both.
  • Not tested: a real picker dialog in a packaged app.

- Interface-typed returns wrap as their runtime class. IPropertySet
  (ApplicationDataContainer.Values, CoreApplication.Properties) declares
  no members itself, so HasKey/Lookup/Insert/First were missing.
- Methods whose overloads all carry [Overload] names are reachable by
  their public name (StorageFile.CopyAsync/MoveAsync), and prototype
  methods switch overload on argc (RenameAsync(name), DeleteAsync()).
- Objects implementing IInitializeWithWindow (pickers) get the app's
  top-level window as owner instead of the console window, which a
  packaged app does not have.
WinRT wrappers do not expose __native_ptr, so a projected object passed
to dotnet.invoke fell through to toString() and arrived as a string.
Encode the wrapper's COM instance as a WinRT ref (tag 0x0A) directly,
and have the bridge project it through C#/WinRT when loaded, so it
casts to its projected type (FileOpenPicker) and works with
WinRT.Interop.InitializeWithWindow.
@coderabbitai

coderabbitai Bot commented Nov 6, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: d290a747-3107-48fe-b76e-91060ff25c61

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@triniwiz
triniwiz merged commit 81a79cc into main Nov 6, 2026
4 checks passed
@triniwiz
triniwiz deleted the fix/winrt-projection-gaps branch November 6, 2026 01:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant