C#/WinRT Authoring Preview and Updates

This post has been republished via RSS; it originally appeared at: Windows Blog.

The C#/WinRT team is excited to announce our latest release, which includes a preview of C#/WinRT authoring with the latest C#/WinRT NuGet package, as well as updates to the .NET 5.0 SDK with the .NET February update. Since our last blog post on C#/WinRT v1.0, we have some new features to show off! The latest C#/WinRT NuGet package, which is version 1.1.2-prerelease.210208.6, includes a preview of C#/WinRT authoring. This allows component authors to create and package their own C# .NET 5 Windows Runtime components that can be consumed in native applications. In this blog post, we walkthrough the latest C#/WinRT authoring support.   C#/WinRT has also made a few additions and bug-fixes to the runtime and Windows projections as part of the .NET 5.0 SDK February update. These updates to the SDK align with C#/WinRT version 1.1.1, which was released last month. We have added support for SupportedOSPlatform attributes, which is a feature that provides platform compatibility assistance in Visual Studio for .NET 5 developers calling platform-specific APIs.   To keep up to date with the latest updates on C#/WinRT, visit the C#/WinRT repo and our docs page. 

Preview of C#/WinRT Authoring 

C# .NET 5 component authors can now create their own Windows Runtime types and package them as Windows Runtime components. You can implement runtime classes in a C# library project, generate its WinMD metadata file, and distribute the WinRT component as a NuGet package. C#/WinRT provides hosting support which loads the .NET runtime, so that your C# authored component can be consumed from non-.NET languages such as C++ and Rust. This preview of authoring also supports project references to your component with a few project modifications, with more details on how to configure this in these authoring docs. Authoring and consuming components with WinUI 3 is currently not supported, but look out for WinUI 3 support in next month’s release!  In the following sections, we’ll dive deeper into authoring a simple WinRT component and consuming it as a package reference. We recommend that you upgrade to the latest .NET 5.0 SDK update while using C#/WinRT authoring. Here is a more detailed walkthrough for authoring, as well as the related sample code. For more details on C#/WinRT authoring and hosting support, refer to these docs. 

Authoring your WinRT component 

To author your C# runtime component, first create a new C# project in Visual Studio using the Class Library template. I named my project AuthoringDemo. Depending on your Visual Studio version, the project template may allow you to choose to target .NET 5, or it may be created using the netcoreapp3.1 target framework moniker. In either case, update the TargetFramework property in the project file to target .NET 5 with a specific Windows API versionhere we use the latest Windows version, net5.0-windows10.0.19041.0 
<PropertyGroup> 
  <TargetFramework>net5.0-windows10.0.19041.0</TargetFramework> 
  <Platforms>x64</Platforms> 
</PropertyGroup>
Next, add a NuGet reference to the latest C#/WinRT package. Right-click on your project, select Manage NuGet packagessearch for Microsoft.Windows.CsWinRT and install the latest packagewhich is version 1.1.2-prerelease.210208.6 as of this writing. You will need to add the following C#/WinRT properties to the project file 
<!-- CsWinRT Properties --> 
<PropertyGroup> 
  <CsWinRTComponent>true</CsWinRTComponent> 
  <CsWinRTWindowsMetadata>10.0.19041.0</CsWinRTWindowsMetadata>	  	 
</PropertyGroup>
The CsWinRTComponent property tells C#/WinRT that the .NET 5 component will follow the WinRT rules, and generates a WinMD file for the component so it can be hosted by other languages that support WinRT. For more details on C#/WinRT project properties, refer to our NuGet documentation.  You can implement your WinRT component using class (.cs) files in your C# library project. You can expose any WinRT types in your component, including .NET mappings of WinRT types. In general, make sure your component follows the relevant WinRT guidelines. Here I renamed the file to “Example.cs” and created a simple WinRT component.  
// Example.cs 
namespace AuthoringDemo 
{ 
    public sealed class Example 
    { 
        public int SampleProperty { get; set; }   

        public static string SayHello() 
        { 
            return "Hello from your C# WinRT component"; 
        } 
    } 
}

C#/WinRT also provides diagnostic error messages to ensure your authored WinRT components are valid. For existing UWP .NET Native managed components, the metadata for C# WinRT components is generated by the winmdexp tool. The Windows Runtime has more constraints on code than C#, so this tool was equipped with diagnostic messages to prevent you from writing runtime errors. In C#/WinRT we have added source generator with diagnostics, alerting you to similar errors in your code at build-time before a WinMD file is generated. Below is an example of one of these diagnostics—since currently all authored runtime classes must be marked sealed, you will see the following error if you forget to do so. 

"Error CsWinRT1005: Exporting unsealed types is not supported. Please mark type Example as sealed."

Build and package your WinRT component  

To generate a NuGet package for your component, add the GeneratePackageOnBuild property to your project file. I’ve also specified a custom output folder named “nuget” for my package to be generated to. Alternatively, you can right-click on the AuthoringDemo project and select Pack.  
<PropertyGroup> 
    <GeneratePackageOnBuild>true</GeneratePackageOnBuild> 
    <PackageOutputPath>.\nuget</PackageOutputPath> 
</PropertyGroup>
When the package is built, C#/WinRT automatically configures the hosting and component assemblies to allow for consumption from native apps. However, if you prefer not to rely on automatic packaging, these docs provide more details on generating a custom NuGet package.  Now build the AuthoringDemo project. You should be able to see the generated WinMD file under the Generated Files folder, as well as in your build output directory. Since we configured the project to generate a package on build, you can also see that “AuthoringDemo.1.0.0.nupkg” has been successfully created below. 

Consume your WinRT component from a native application 

To consume your component, first create a new native WinRT application. Here we added a new Windows Console Application (C++/WinRT) project to the solution named “CppConsoleApp”. From this project, add a NuGet package reference to the component, AuthoringDemo.1.0.0.nupkg. You may need to configure your package sources—to do this, click on the Settings gear in NuGet Package Manager, and add a package source to the appropriate path.   Here’s an example of what the package sources look like after adding the appropriate NuGet path. Make sure to select Update and then OK.   After configuring your package sources, you should now be able to search for and install the AuthoringDemo” package.  Next, you will need to add two files to the CppConsoleApp project to be able to host your component: WinRT.Host.runtimeconfig.json and CppConsoleApp.exe.manifest. For more details on the steps below and managed component hosting, see the hosting docs  To add the runtimeconfig and manifest files, right-click on the CppConsoleApp project and choose Add -> New Item, and use the Text File template. Here are the contents of WinRT.Host.runtimeconfig.json. Note for the “tfm entry, a custom self-contained .NET 5 installation can be referenced using the DOTNET_ROOT environment variable. 
{ 
    "runtimeOptions": { 
        "tfm": "net5.0", 
        "rollForward": "LatestMinor", 
        "framework": { 
            "name": "Microsoft.NETCore.App", 
            "version": "5.0.0" 
        } 
    } 
}
For the manifest file, since the application is not MSIX-packaged you need to include activatable class registrations for your runtime classes. Note that WinRT.Host.dll produced by C#/WinRT is used as the host DLL, and not the actual managed component DLL. Here are the contents of CppConsoleApp.exe.manifest: 
<?xml version="1.0" encoding="utf-8"?> 
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1"> 
  <assemblyIdentity version="1.0.0.0" name="CppConsoleApp"/> 
  <file name="WinRT.Host.dll"> 
    <activatableClass 
        name="AuthoringDemo.Example" 
        threadingModel="both" 
        xmlns="urn:schemas-microsoft-com:winrt.v1" /> 
  </file> 
</assembly>
You will need to add both the WinRT.Host.runtimeconfig.json and CppConsoleApp.exe.manifest files to the application output. To do this in Visual Studio, select each of these files in your Solution Explorer, and in the Content field select True from the drop-down menu, like below.  Next in the pch.h under Header Files, add the following line of code to include your component:  
#include <winrt/AuthoringDemo.h>
Finally, in main.cpp under Source FilesI added the following code to use the authored component. 
#include "pch.h" 
#include "iostream" 
  
using namespace winrt; 
using namespace Windows::Foundation; 
using namespace std; 
  
int main() 
{ 
    init_apartment(); 
  
    AuthoringDemo::Example ex; 
    ex.SampleProperty(42); 
    wcout << ex.SampleProperty() << endl; 
    wcout << ex.SayHello().c_str() << endl; 
}
Now when you run the console application, you will see this in the output!  Thanks for following along with this walkthrough of C#/WinRT authoringin the upcoming weeks wwill continue improving the project support and end-to-end authoring experience, so stay tuned! The team is also working to provide more complete support for authoring and consuming components using WinUI 3. For more details on authoring and consuming C# WinRT componentssee this walkthrough and our authoring docs. 

.NET 5.0 SDK Updates - SupportedOSPlatform attributes 

In addition to the latest C#/WinRT authoring preview, the team has also made a couple updates for the .NET 5.0 SDK February update with C#/WinRT version 1.1.1. This includes several bug-fixes to the runtime and Windows SDK projections provided by C#/WinRT—a full list can be found here.  One C#/WinRT feature that we have added as part of the February update is support for SupportedOSPlatform attributes. With the integration of these attribute checks in Visual Studio, you now get a CA1416 warning when calling platform-specific APIs that are not supported on the platform versions your project supports. Let’s check out an example of what this looks like. 
using System;
using Windows.Devices.Display;
using Windows.Devices.Enumeration;
namespace Net5ConsoleApp
{
    class Program
    {   
        static async System.Threading.Tasks.Task Main(string[] args)
        {
            var deviceInformations = await DeviceInformation.FindAllAsync(DisplayMonitor.GetDeviceSelector());
            foreach (DeviceInformation device in deviceInformations)
            {
                DisplayMonitor displayMonitor = await DisplayMonitor.FromInterfaceIdAsync(device.Id);
                // Print some info about the display monitor
                Console.WriteLine("DisplayName: " + displayMonitor.DisplayName);
                Console.WriteLine("ConnectionKind: " + displayMonitor.ConnectionKind);
                // Warning CA1416: This call site is reachable on: 'Windows' 10.0.17763.0 and later.
                // 'DisplayMonitor.IsDolbyVisionSupportedInHdrMode.get' is only supported on: 'Windows' 10.0.19041.0 and later.
                Console.WriteLine("IsDolbyVisionSupported: " + displayMonitor.IsDolbyVisionSupportedInHdrMode);
            }
        }
    }
}
The program above is part of a .NET 5 console application, with the following properties set in the project file: 
<TargetFramework>net5.0-windows10.0.19041.0</TargetFramework> 
<SupportedOSPlatformVersion>10.0.17763.0</SupportedOSPlatformVersion>
The program uses the DisplayMonitor class in the WinRT APIs to print some information about display monitor devices that are connected to the system, such as the display name, connection kind, and whether it supports Dolby Vision in HDR mode, which is a new API addition in 19041. This is an example of what the output looks like—since I am running the application on a Windows OS version greater than 19041, there are no runtime errors.  Notice in the code above that the following warning message appears when accessing the last property, IsDolbyVisionSupportedInHdrMode 

Warning CA1416: This call site is reachable on: 'Windows' 10.0.17763.0 and later. 'DisplayMonitor.IsDolbyVisionSupportedInHdrMode.get' is only supported on: 'Windows' 10.0.19041.0 and later. 

This is because the application supports a lower OS platform version of 10.0.17763.0, while the property IsDolbyVisionSupportedInHdrMode is only available in 10.0.19041.0 or greater. Users running the application on a lower Windows version such as 10.0.17763.0 would get a runtime error without guarding this property call.   We do realize that this warning message leads developers to use version checks instead of presence checks, which may be undesirable for WinRT APIs. Because different Windows devices may support different APIs, our guidance is to always do presence checks for light up scenarios instead of explicit version checks. The recommendation for writing version adaptive code is to surround the property call with a presence check using one of the ApiInformation methods. This ensures that users running the application on an OS version lower than 10.0.19041.0 will not get any runtime errors. While the CA1416 warning persists, Visual Studio gives you the option to suppress it directly in the source file with a #pragma warning as shown below. Another option is to configure the severity of the warnings.
if (ApiInformation.IsPropertyPresent("Windows.Devices.Display.DisplayMonitor", "IsDolbyVisionSupportedInHdrMode")) 
{ 
#pragma warning disable CA1416 // Validate platform compatibility 
      Console.WriteLine("IsDolbyVisionSupported: " + displayMonitor.IsDolbyVisionSupportedInHdrMode); 
#pragma warning restore CA1416 // Validate platform compatibility 
}
As you can see, this feature helps ensure that developers call platform-specific Windows APIs appropriately when supporting earlier Windows OS versions by adding a warning message. 

Closing 

We encourage developers to try out C#/WinRT authoring and submit feedback to our repo as we continue to improve the project support for a more streamlined end-to-end authoring experience. We are working on support for more authoring scenarios such as integration with WinUI 3 desktop applications and authoring out-of-process components for use in packaged applications.  C#/WinRT also continues to make bug-fixes for the .NET 5.0 SDK as part of their monthly updates. To stay up to date on the latest fixes, file any issues, and for any questions or feedback, visit the C#/WinRT repo.  Angela Zhang – C#/WinRT PM 

Leave a Reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.