Using the Windows Runtime from a Non-Metro Application

12 Comments September 20, 2011


I know a lot of people believe that the new Windows Runtime APIs included in Windows 8 can only be accessed from Metro style applications. A big part of the reason why people believe this is because the version of Visual Studio that ships with the Windows 8 Developer Preview only supports creating Metro style applications. However, I set out this morning to use Windows Runtime APIs from a non-Metro application. Here's what I did.

First, in Notepad, I created the following C# source code in EnumDevices.cs:

using System;
using System.Threading.Tasks;
using Windows.Devices.Enumeration;
using Windows.Foundation;

class App {
static void Main() {
EnumDevices().Wait();
}

private static async Task EnumDevices() {
// To call DeviceInformation.FindAllAsync:
// Reference Windows.Devices.Enumeration.winmd when building
// Add the "using Windows.Devices.Enumeration;" directive (as shown above)
foreach (DeviceInformation di in await DeviceInformation.FindAllAsync()) {
Console.WriteLine(di.Name);
}
}
}

Second, I created a Build.bat file which I run from the Developer Command Prompt to build this code (This should be 1 line but I wrap it here for read ability):

csc EnumDevices.cs
/r:c:\Windows\System32\WinMetadata\Windows.Devices.Enumeration.winmd
/r:c:\Windows\System32\WinMetadata\Windows.Foundation.winmd
/r:System.Runtime.WindowsRuntime.dll
/r:System.Threading.Tasks.dll

Then, at the command prompt, I just run the EnumDevices.exe to see the output.

 

Let me also explain how the async stuff works:

The XxxAsync methods (like DeviceInformation.FindAllAsync above) is a Windows Runtime method (defined in Windows.Devices.Enumeration.winmd) that returns a DeviceInformationFindAllAsyncOperation object which implements the Windows Runtime's IAsyncOperation<TResult> interface where TResult is the Windows.Devices.Enumeration.DeviceInformationCollection type. This interface is defined in the Windows.Foundation.winmd file.

Using the await keyword causes the compiler to look for a GetAwaiter method on this interface. Since IAsyncOperation<TResult> does not define a GetAwaiter method, the compiler wants to look for an extension method. In the System.Runtime.WindowsRuntime.dll assembly is the static System.WindowsRuntimeSystemExtensions class. This class defines several GetAwaiter extensions methods and the compiler emits code that invokes the GetAwaiter extension method that takes an IAsyncOperation<TResult> and returns a System.Runtime.CompilerServices.TaskAwaiter<TResult> object (defined in the System.Threading.Tasks.dll which is why this assembly is referenced). Since TResult is the Windows.Devices.Enumeration.DeviceInformationCollection type, the await operator ultimately returns this type which is then used by the foreach loop. Inside the loop, I just display the Name property for each DeviceInformation object.

 

Because you cannot mark an entry point method (like Main) as being async, I moved the code that calls await into its own EnumDevices method, marked this method as async, and make it return a Task. Then Main invokes this method and calls Wait on the returned Task so that the application doesn't terminate until EnumDevices has run all the way through to completion.


12 Comments

  • Gravatar Image
    Stephen Cleary September 20, 2011 2:14 PM

    Thanks for this blog post! I am hoping that WinRT will be usable from Desktop apps (officially); it would be nice to kiss p/Invoke goodbye.

    BTW, I have an AsyncContext class that is nice to use for async Console apps and unit testing (you can keep async void instead of changing to async Task). It's part of this library:
    http://nitoasyncex.codeplex.com/

  • Gravatar Image
    Pedro September 20, 2011 4:11 PM

    Cool!

  • Gravatar Image
    Konstantin September 21, 2011 1:43 AM

    Very interesting and in-depth explanation, as usual :)

  • Gravatar Image
    Dew Drop &ndash; September 21, 2011 | Alvin Ashcraft&#039;s Morning Dew September 21, 2011 8:53 AM

    PingBack from http://www.alvinashcraft.com/2011/09/21/dew-drop-september-21-2011/

  • Gravatar Image
    Sriharsha Vardhan September 24, 2011 1:43 AM

    Hi Jeffrey

    I know you always make things feel fundamental by bridging gap for old time programmers like me. Learnt VC++, and then .Net from your books. Now looking forward to learn this phenomenal new trend from Microsoft.

  • Gravatar Image
    Crissy November 23, 2011 7:23 AM

    Hey, you're the goto expert. Thanks for hnaigng out here.

  • Gravatar Image
    Nathan March 7, 2012 4:30 PM

    is it possible to create a non-metro style app in visual studio 2011?

  • Gravatar Image
    Al March 21, 2012 10:32 AM

    Thanks very much for this sample. I tried to build it on Consumer Preview 8250 x64 with the matching version of VS 11 Ultimate beta installed, and it would not compile. There appears to be some breaking change.

    First, a message said to add a reference to System.Runtime, so I added a ref to System.Runtime.dll to the command line.

    But then I got the following new error:

    enumdevices.cs(15,34): error CS4028: 'await' requires that the type
    'Windows.Foundation.IAsyncOperation Windows.Devices.Enumeration.DeviceIn
    formationCollection ' have a suitable GetAwaiter method. Are you missing
    a using directive for 'System'?

    The code already has "using System". I have tried many things, but cannot resolve this. For example, I searched and cannot find a version of System.Runtime.WindowsRuntime.dll on my system which lists GetAwaiter() in System.WindowsRuntimeSystemExtensions. (e.g. 4.0.30319)

    Any help in resolving this error will be appreciated! Thx.

  • Gravatar Image
    asava samuel March 15, 2013 3:04 AM

    Here is a database compatible with Windows Runtime:
    https://www.kellermansoftware.com/p-49-ninja-winrt-database.aspx

  • Gravatar Image
    pence April 22, 2013 1:35 AM

    I'm impressed, I must say. Really hardly ever do I encounter a blog that's each educative and entertaining, and let me tell you, you've hit the nail on the head. Your idea is outstanding; the issue is one thing that not sufficient individuals are speaking intelligently about. I am very joyful that I stumbled across this in my search for one thing relating to this.

  • Gravatar Image
    circulatory April 22, 2013 4:31 AM

    I critically take pleasure in your posts. Thank you

Have a Comment?

Archives

Blogs