Calling Windows 10 APIs From Your WPF Application

Did you know that you can call Windows 10 WinRT APIs from your WPF and WinForms apps? In this blog post I’ll show you how to display toast messages from a WPF application by using the Windows 10 ToastNotificationManager.

In the previous blog post you learned that you can host UWP Controls in WPF, WinForms, and Win32 with a technology called XAML Islands.

But sometimes you don’t want to include a UWP Control in your WPF app. Instead, you want to call a Windows 10 API. Or maybe you want to do both: Include a UWP control and call a Windows 10 API. In any case, you need to reference the Windows 10 WinRT APIs in your WPF project. Let’s see how to do this.

Reference the Windows 10 WinRT APIs in your WPF project

If you’ve tried already in the past to use Windows 10 WinRT APIs in WPF, you might have come across documentation that said that you have to reference several files …

  • … from .NET Framework – like System.Runtime.WindowsRuntime.dll
  • and from the corresponding Windows SDK, like Windows.Foundation.UniversalApiContract.winmd

This is not necessary anymore. Microsoft made this whole process much simpler.

All you need to do to use Windows 10 WinRT APIs in your WPF project is to install the NuGet package Microsoft.Windows.SDK.Contracts.

That package is the the so-called Windows 10 WinRT API Pack . Let me quote the package description:

The Windows 10 WinRT API Pack enables you to add the latest Windows Runtime APIs support to your .NET Framework 4.5+ and .NET Core 3.0+ libraries and apps. This package includes all the supported Windows Runtime APIs up to Windows 10 version 1903

Wow, amazing. Just adding a single NuGet package and it works. Let’s try it.

Add the NuGet package

Let’s create a brand new WPF application and let’s install the NuGet package Microsoft.Windows.SDK.Contracts. It’s still in preview, so ensure to check the “Include prerelease” option like below:

When you look at the dependencies of the Microsoft.Windows.SDK.Contracts package, you can see that it brings in the other stuff that you had to add manually before this package existed, like the System.Runtime.WindowsRuntime.dll that I mentioned above:

Switch from packages.config to PackageReference

When you install the Microsoft.Windows.SDK.Contracts NuGet package in a .NET Core WPF app, you’re fine. But in a .NET Framework WPF app, you have to switch the NuGet package management format from packages.config to PackageReference, else it won’t work. The description of the Microsoft.Windows.SDK.Contracts package contains also this statement:

Requires default package management format set to PackageReference, and NuGet 4.0 or higher.

If you have a .NET Framework WPF app that still uses packages.config, just right-click on “References” in the Solution Explorer. In the context menu you find a menu item to“Migrate packages.config to PackageReference”, as you can see in the screenshot below.

After you clicked that menu item, the packages.config file will be deleted and the references to the NuGet packages are stored in the .csproj file. Great, now installing the NuGet package Microsoft.Windows.SDK.Contracts works fine, and you should see that package including its dependencies in the references like below:

Now, no matter if you’re using .NET Core 3 or .NET Framework, you’re ready to display a toast message from your WPF app. Let’s write the code.

Display a Toast Message

Let’s add a simple Button in the MainWindow.xaml file:

<Button Content="Show Toast"
        Padding="10"
        HorizontalAlignment="Center"
        VerticalAlignment="Center"
        Click="ButtonShowToast_Click"/>

In the codebehind file (MainWindow.xaml.cs), let’s add this ButtonShowToast_Click event handler:

private void ButtonShowToast_Click(object sender, RoutedEventArgs e)
{
    string title = "The current time is";
    string timeString = $"{DateTime.Now:HH:mm:ss}";
    string thomasImage = "https://www.thomasclaudiushuber.com/thomas.jpg";

    string toastXmlString =
    $@"<toast><visual>
            <binding template='ToastGeneric'>
            <text>{title}</text>
            <text>{timeString}</text>
            <image src='{thomasImage}'/>
            </binding>
        </visual></toast>";

    var xmlDoc = new XmlDocument();
    xmlDoc.LoadXml(toastXmlString);

    var toastNotification = new ToastNotification(xmlDoc);

    var toastNotifier = ToastNotificationManager.CreateToastNotifier();
    toastNotifier.Show(toastNotification);
}

As you can see in the code snippet above, the ButtonShowToast_Click event handler initializes a toastXmlString variable with a valid toast template. Then it loads that string into an XmlDocument (the WinRT one from the namespace Windows.Data.Xml.Dom). Next a ToastNotification object is created with that XmlDocument.

Then a ToastNotifier instance is created by calling the static CreateToastNotifier method of the ToastNotificationManager class. Finally, the Show method is called on that ToastNotifier instance to show the toast notification.

You can just copy paste that code snippet into your app. When you place the cursor on the ToastNotificationManager class, you can press “CTRL+.” and Visual Studio will suggest you to add a using directive for the WinRT namespace Windows.UI.Notifications, as you can see below:

For the XmlDocument class, you need to add a using directive for Windows.Data.Xml.Dom (and not for the .NET variant that lives in System.Xml). The using directives of the MainWindow.xaml.cs file look like below. As you can see, a nice mixture between .NET and WinRT namespaces:

using System;
using System.Windows;
using Windows.Data.Xml.Dom;
using Windows.UI.Notifications;

Now let’s run the application and let’s push the “Show Toast”-Button in the MainWindow.

Let’s click this nice Button.

Oh no, we get an Exception at the line where the CreateToastNotifier method is called. It says “Element not found”. What does this mean?

The problem here is that your WPF application doesn’t have a package identity. A UWP app has a package identity, and it is installed in Windows 10 with that identity. But a WPF app doesn’t have such an identity, so let’s create one.

Create an Identity for Your WPF App

You can easily create an identity for your WPF app by packaging it as MSIX. To do this, just add a Windows Application Packaging Project to your solution. In the previous blog post we used the Windows Application Packaging Project already to target a specific windows version with WPF. This time we need that Packaging Project to get an identity, and in addition, that Packaging Project let’s us target a specific windows version. So let’s add it. Let’s right-click the solution and let’s add a new Windows Application Packaging Project.

My WPF project is called “WpfCallingWin10Api.Framework”. Let’s call the packaging project “WpfCallingWin10Api.Framework.App. The creation shows the dialog below, where I select 18362 as a minimum version:

After that packaging project was added to the solution, you have to right-click the “Applications” node in Solution Explorer to reference the WPF project. Finally, set the packaging project as a startup project. The final result should look like this:

Now with the Packaging Project set as a start up project, let’s try the app again, as we have now an identity.

Let’s Toast It!

Let’s run the application and let’s click the “Show Toast”-Button.

*drumroll*

And voilà! In the bottom right corner of my screen, above the icon tray, appears a nice toast that displays the current time like we’ve specified it with the toast template, including the thomas.jpg that we’ve also specified in that toast template.

The toast is shown above the icon tray in the bottom right corner of my screen.

Fantastic, it just works!

And all that was necessary were these 2 steps:

Go and Grab the Code!

I have created this sample for you with .NET Framework and .NET Core. Grab the .NET Framework and .NET Core solutions from this Git repository to try it on your own, and don’t forget to set the packaging project as a startup project:

https://github.com/thomasclaudiushuber/Wpf-Calling-Win10-WinRT-Toast-Api

Can we talk again about XAML Islands?

Sure. What’s the question?

Hey Thomas, at the beginning of this blog post you wrote this:
“… sometimes you don’t want to include a UWP Control in your WPF app. Instead, you want to call a Windows 10 API.  Or maybe you want to do both: Include a UWP control and call a Windows 10 API. In any case, you need to reference the Windows 10 WinRT APIs in your WPF project. Let’s see how to do this. “

But in your previous blog post where you used XAML Islands to display the UWP MapControl in a WPF app, you neither referenced the UWP .winmd file, nor did you install the Microsoft.Windows.SDK.Contracts package. But in this blog post you’re saying “In any case, you need to reference the Windows 10 WinRT APIs in your WPF project.”

In your previous blog post you didn’t add a reference, why did it work there?

Ok, let’s answer this.

In the previous blog post we installed the NuGet package Microsoft.Toolkit.Wpf.UI.Controls. That package contains wrapper controls for WPF that make the usage of UWP controls like MapControl and InkCanvas straight forward. Or in other words: That package makes the usage of XAML Islands straight forward.

We installed the preview4 version of that NuGet package. And now go and click here on this NuGet link to look at the Dependencies of the preview4 version of that package, the latest available version.

Instead of clicking on the link above, you can also manage NuGet packages in Visual Studio, search for that preview version of the Microsoft.Toolkit.Wpf.UI.Controls package, click on it and look at its dependencies. The dependencies of that Microsoft.Toolkit.Wpf.UI.Controls package look like below. Do you notice something?

Exactly, the package Microsoft.Toolkit.Wpf.UI.Controls has a dependency on Microsoft.Windows.SDK.Contracts.

That means in other words: If you’re using that XAML Islands NuGet package, you automatically get access to the Windows 10 WinRT APIs, as Microsoft.Windows.SDK.Contracts is added too, as it is a dependency.

Isn’t this awesome? I love it!

Happy coding,
Thomas

Share this post

Comments (14)

  • Dew Drop – April 29, 2019 (#2947) | Morning Dew Reply

    […] Calling Windows 10 APIs From Your WPF Application (Thomas Claudius Huber) […]

    April 29, 2019 at 12:43 pm
  • Robert Mühsig Reply

    Is the MSIX still needed for the deployment? I read somewhere that with the most recent Win10 Version even non UWP/MSIX apps should be able to use the Win10 APIs, e.g. a „classic“ WPF app.

    May 5, 2019 at 6:10 pm
  • Fabio Corvino Reply

    Sorry, but there is something that is confusing me and the overall process is not working.
    I’m using .NET Framework 4.7.2 and Windows 1803.
    So, the statement: “The Windows 10 WinRT API Pack enables you to add the latest Windows Runtime APIs support to your .NET Framework 4.5+ and .NET Core 3.0+ libraries and apps. This package includes all the supported Windows Runtime APIs up to Windows 10 version 1903”, for me (Italian) it means that it supports also previous versions.
    Unfortunately if I configure the Packaging Project to run for 18362 min 17134, I get the error: “Your application has a dependency on ‘WpfAppCallingWin10API’, which has a TargetPlatformMinVersion of ‘10.0.18362.0’. Your application’s TargetPlatformMinVersion is ‘10.0.17134.0’. Change ‘WpfAppCallingWin10API’s TargetPlaformMinVersion to be less than or equal to ‘10.0.17134.0’.”
    Whereas if I configure the Packaging Project to run for 18362 min 18362, it compiles but, when I start it, I receive the error: “DEP3321: To deploy this application, your deployment target should be running Windows Universal Runtime version 10.0.18362.0 or higher. You currently are running version 10.0.17134.829. Please update your OS, or change your deployment target to a device with the appropriate version.”
    Am I missing something?

    June 20, 2019 at 9:55 am
  • Harish Kaushal Reply

    A BIG THANK YOU Thomas for this article. I was struggling to solve element issue in my WPF app. But now i have another issue and i want to ask if its possible or not.

    I am actually new to .NET coding and your Pluralsight courses has helped me a lot. Thank you :)

    Issue :-

    I have WPF app and using above method i have enabled toast notifications for my app. But i want my app to have “Run As different User” option because of some business requirement. But now start up project is UWP app so now i don’t have that option anymore.

    So is there any way i can have “Run As different user” option for my UWP app?

    Appreciate your response.

    July 3, 2019 at 11:14 am
    • Thomas Claudius Huber Reply

      Hi Harish, great question. I don’t have an answer for this yet. I need to try it. But maybe you want to use an application.manifest in a normal Win32 WPF app instead of using the packaging project that makes it a UWP app.

      September 12, 2019 at 10:07 am
  • Taras Reply

    Hi Thomas,
    What options do I have if I want to develop my app for Windows 7+, but also want to use Win10 APIs when the app is running in Win10?
    Is recompiling an app for Win7 without referencing Win10 DLLs a must?

    July 4, 2019 at 2:28 pm
    • Thomas Claudius Huber Reply

      Hi Taras,

      great question. I think so it is a must, as you need to change the application manifest

      September 12, 2019 at 10:05 am
  • Callon Reply

    Great post. Have you tried using the Win10 share Contract in a WPF app? Following your guidelines above results in the same error even through I wrapped it in a Windows Package Installer.

    August 5, 2019 at 5:50 pm
    • Callon Reply

      The error I get is…

      System.Exception: ‘Element not found.

      This method cannot be called while the app is in the background’

      August 5, 2019 at 5:52 pm
    • Thomas Claudius Huber Reply

      Hi Callon, I haven’t tried to use that contract yet.

      September 12, 2019 at 10:04 am
  • Leszek Reply

    Windows 10 version 1903
    Does it always needs to be shown with the latest windows version? Writing application for business means that the business is NOT on the latest version of Windows.

    Can a packaged app be still deployed using ClickOnce?

    How to use loggers, like log4net, etc. that writes to a file outside UWP Storage?

    How to use old, non NET STandard 2.0 technologies, like Linq2SQL within UWP UI Project?
    using AppService and Net Framework project as proxy?

    Best regards

    August 8, 2019 at 9:39 am
    • Thomas Claudius Huber Reply

      Hi Leszek,

      great questions. I don’t have answers to all these questions. But with UWP, you get a similar deployment model like ClickOnce that allows you to use a URI for the package. I think MSIX is the future for deployment and packaging.

      Linq2SQL is really old. I think you should move that code to Entity Framework Core

      September 12, 2019 at 10:10 am

Leave a Reply to Fabio Corvino Cancel 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.