question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

CS/WinRT and WinUI integration

See original GitHub issue

CS/WinRT and WinUI integration spec

Outline

This spec has the following high-level goals:

  1. Detail the fundamental principles of how CS/WinRT interop assemblies will work
  2. Detail the type projections
  3. Callout any outstanding questions or issues related to how CS/WinRT will work

Table of Contents

Overview of CS/WinRT

This section aims to give a high level overview of the CS/WinRT project, and some basic principles of how the tool works.

What is CS/WinRT?

CS/WinRT is a new language projection implementation to allow the .NET runtime to interop with the Windows Runtime (WinRT). The Windows Runtime is a set of libraries, whose APIs are defined in the .winmd file format.

Why CS/WinRT?

The WinRT API surface defines many APIs that are very similar to those that live in .NET. In order to make .NET development feel more natural to .NET developers, there are a set of The current WinRT projections are baked into the .NET Native runtime and compiler. This special and hardcoded knowledge has proved problematic and buggy, and does not scale. The goal with CS/WinRT is to create the proper layer of abstraction for these projections, so that the .NET runtime has no special knowledge of WinRT, and instead just operates on the assemblies like they are regular .NET assemblies (because they are!)

When will CS/WinRT ship?

The plan is to have CS/WinRT ready for the release of .NET5, to be consumed by WinUI3.0. It will ship as a Nuget package on nuget.org.

How does CS/WinRT work?

At a conceptually high level, CS/WinRT works much like Cpp/WinRT. The tool, cswinrt.exe creates wrapper classes, defined in CSharp, that understand the Application Binary Interface (ABI) of the WinRT libraries based off of the .winmd files that are used as inputs.

There will be a single CS/WinRT runtime interop dll (name TBD) that is shared between any CS/WinRT interop assembly. TBD more on this

TODO: Link to tool implementation and/or spec

WinRT to .NET Projections

Foundational types

Below is a list of the foundational types (as they show in the .winmd) and the corresponding .NET type they project to. While many of these are primitive types, this list also consists of many other basic types such as collections.

WinRT Type Projected .NET Type
Windows.Foundation.Object System.Object
Windows.Foundation.Int32 System.Int32
Windows.Foundation.Int64 System.Int64
Windows.Foundation.UInt32 System.UInt32
Windows.Foundation.UInt32 System.UInt64
Windows.Foundation.Object System.Object

Interfaces

TODO: Finish filling this in with collection types

WinRT Type Projected .NET Type
Microsoft.UI.Xaml.Input.ICommand System.Windows.Input.ICommand
Microsoft.UI.Xaml.Interop.IBindableIterable System.Collections.IEnumerable
Microsoft.UI.Xaml.Interop.IBindableVector System.Collections.IList
Microsoft.UI.Xaml.Inteorp.INotifyCollectionChanged System.UInt32
Microsoft.UI.Xaml.Data.INotifyPropertyChanged System.ComponentModel.INotifyPropertyChanged
Microsoft.UI.Xaml.Data.INotifyDataErrorInfo System.ComponentModel.INotifyDataErrorInfo

Structs

The following types don’t have a projection into .NET, although the structs do have more functionality than a classic WinRT struct.

TODO: more on why these aren’t projected to the System.Windows.* types, and should they?

WinRT Type
Windows.Foundation.Point
Windows.Foundation.Rect
Windows.Foundation.Size

Struct Helper classes

Xaml types that get extra members in the CSharp projection.

For example, Xaml’s CornerRadius is just a struct:

struct CornerRadius
{
    DOUBLE TopLeft;
    DOUBLE TopRight;
    DOUBLE BottomRight;
    DOUBLE BottomLeft;
};

But when it’s projected in CSharp, it acquires a constructor and comparison operators:

public struct CornerRadius
{
    public CornerRadius(double topLeft, double topRight, double bottomRight, double bottomLeft);

    public double BottomLeft { get; set; }
    public double BottomRight { get; set; }
    public double TopLeft { get; set; }
    public double TopRight { get; set; }

    public override bool Equals(object obj);
    public bool Equals(CornerRadius cornerRadius);
    public override int GetHashCode();
    public override string ToString();
    public static bool operator ==(CornerRadius cr1, CornerRadius cr2);
    public static bool operator !=(CornerRadius cr1, CornerRadius cr2);
}

There is actually a way for non-CSharp developers to get access to this same functionality with some Helper classes. For example, there’s a CornerRadiusHelper class that has these members on it.

These Helper classes are not projected by CSharp, since the functionality is on the structs already.

Note that Point/Rect/Size are Windows.Foundation structs, but the helper classes are in Xaml’s namespace (e.g. RectHelper).

The structs and their helpers:

Struct Struct helper
CornerRadius CornerRadiusHelper
Duration DurationHelper
DurationType
GridLength GridLengthHelper
Thickness ThicknessHelper
GeneratorPosition GeneratorPositionHelper
Matrix MatrixHelper
KeyTime KeyTimeHelper
RepeatBehavior RepeatBehaviorHelper
RepeatBehaviorType

Note that in addition to adding members to these structs, the projections add ToString() overrides. For example, the ToString for Thickness is something like “10,2,10,2” rather than just the type name.

Exceptions

These exception types live in System.Runtime.WindowsRuntime.UI.Xaml.dll and are automatically created at runtime by the interop layer:

ElementNotAvailableException
ElementNotEnabledException
LayoutCycleException
XamlParseException

The Type Type

WinRT doesn’t officially have the notion of a type. There is no Windows.Foundatation.Type. You can ask an object (IInspectable) for runtime class name, but that’s only a string.

But, Xaml has a type named Windows.UI.Xaml.Interop.TypeName (and associated TypeKind enum) that projects in CSharp to System.Type.

With WinUI3, this type will eventually move to Microsoft.UI.Xaml.Interop.TypeName, however this work has not been done yet because we are still using .NET Native. Once the project system work has been done to move off of .NET Native, we can move this type. Ideally, CS/WinRT already has support for Microsoft.UI.Xaml.Interop.TypeName at that point, and we can make the change in metadata and move all of our test projects at the same time.

ICustomPropertyProvider

Xaml calls to CCWs today and QIs for ICustomPropertyProvider to get properties for data binding. The implementation of that interface uses reflection on the target .Net object.

TODO: More on how this interop will work

System IO

Some of the .NET APIs in the System.IO namespace, for example, System.IO.File were removed from the .NET Native API surface because they did not conform to the sandboxed environment of the app container. Instead, developers used the WinRT equivalent APIs, and to keep along with the example, would use Windows.Storage.StorageFile instead. With moving to .NET5 and CS/WinRT, we want there to be a single runtime and a more uniform API surface area, however that still leaves what to do with these APIs unresolved.

TODO: Gather a complete list of these APIs

WinRT Type .NET Type
Windows.Storage.StorageFile System.IO.File
Windows.Storage.StorageFolder System.IO.Directory

Streams

WinRT APIs that either returned or accepted a stream would use the Windows.Storage.Streams.IRandomAccessStream class at the API surface. There existed some helper extension methods in the .NET/WinRT interop assembly. Rather than relying on those, can we instead just project the Windows.Storage.Streams.IRandomAccessStream as a System.IO.Stream? The extension methods can still exist so that code can compile with minimal changes, but will no longer be required. Another option would be to have the app conversion tool remove the use of these extension methods.

Consuming CS/WinRT

WinRT library authors will consume the CS/WinRT tool through the Nuget. For WinUI control authors writing C++ winrt components, this will be abstracted through some MSBuild targets. The MSBuild targets should generate the CSharp wrappers and compile the code into an interop assembly, and not require the need for a second project for doing so. If developers don’t have the CSharp workload installed, they can opt-out of this by setting an MSBuild property, although we don’t want this to be the default behavior. It should first be validated and confirmed how C++ WinRT component authors generate their Nuget packages. The Win2D Nuget is probably a good starting point for seeing how these Nugets are generated.

Authoring WinRT APIs in CSharp

Compiling CSharp WinRT components into a .winmd allows for the following scenarios:

  • C++ Applications referencing a C# component
  • C# background tasks

In order to do this, the winmdexp tool needs to be updated to work with the new projections.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:9 (9 by maintainers)

github_iconTop GitHub Comments

1reaction
stevenbrixcommented, Apr 23, 2020

Yeah, I’ll go ahead and do it for you 😃

1reaction
jkoritzinskycommented, Feb 20, 2020
Read more comments on GitHub >

github_iconTop Results From Across the Web

Walkthrough—Create a C# component with WinUI 3 ...
In Solution Explorer, right-click on the project node, and select Manage NuGet Packages. ii. Search for the Microsoft.Windows.CsWinRT NuGet ...
Read more >
A deep-dive into WinUI 3 in desktop apps - Windows Blog
This interop code uses the winrt.runtime.dll library. As you can guess, the cswinrt.exe gets all the WinUI WinMD files and generates C# interop ......
Read more >
How to test a C++/Winrt runtimeclass that implements ...
2 - A CS/WinRT projection library for the C++ component (written ... In the WinUI Desktop application project, everything is working fine.
Read more >
Integration testing with WinUi 3 : r/dotnet
Unit testing is better than integration testing because when you have to test the whole finished unit you find yourself constantly having to ......
Read more >
How to Access Native Code from WebView2 with ...
A step-by-step guide on how to access native code in JavaScript within a WinUI 3 application.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found