Click here to Skip to main content
15,879,326 members
Articles / Programming Languages / C# 4.0

How to call WinRT APIs from .NET desktop apps

Rate me:
Please Sign up or sign in to vote.
4.83/5 (12 votes)
5 Feb 2013Public Domain6 min read 90.3K   1.4K   46   16
Explains how to create a .NET app which invokes WinRT APIs on Windows 8.

Introduction

This article shows the steps you need to make a .NET desktop app that invokes the new WinRT APIs that come with Windows 8.

File > NewProject > Online > Templates > VisualBasic > WinRT Console Application Template

That's all you need (requires VS2012 and Windows 8).

What are WinRT APIs?

  1. WinRT APIs are a bunch of new, modern APIs that were introduced in Windows 8. Some of them are UI APIs for specifically for the XAML UI of "app-store-style" apps, formerly known as Metro. Others of them provide core OS functionality like files, streams, bitmaps. In many cases, .NET and Win32 already had similar functionality. In some cases, the WinRT APIs are cleaner and better.
  2. WinRT APIs are the APIs you'll primarily be using when you build app-store-style apps (Metro apps). These app-store-style apps are also allowed to use a partial set of .NET APIs, and a partial set of Win32 APIs, and a partial set of COM APIs. Typically you'll use .NET APIs if they're available, and otherwise you'll fall back to WinRT APIs.
  3. WinRT APIs are a cross-language API. Microsoft did lots of work to make it easy to access these APIs from JavaScript, C++, VB, C#, and F#.

  4. WinRT APIs are a new form of interop. They are found in a new kind of assembly, .WinMD. You can find these assemblies on a Win8 machine under c:\windows\system32\WinMetadata, and also (if you install the Windows SDK) under C:\Program Files (x86)\Windows Kits\8.0\References\CommonConfiguration\Neutral. Also, third-parties will be producing their own WinMDs.
  5. WinRT APIs are an enhanced form of COM. In particular, WinMD files are the equivalent of old COM type-libraries (.TLB), but stored using the same binary format as .NET assemblies. That means you can load .WinMD files into your favourite inspection tool such as Redgate Reflector. Fortunately, the extra work done my Microsoft makes it much easier to use WinRT APIs than it was to use COM.

The accompanying code is a VB console app which demonstrates a few WinRT APIs - StorageFolder (to look at files and folders), BitmapDecoder (to load images), StreamSocketListener (to handle TCP requests).

There are two reasons why you might want to use WinRT APIs from desktop apps:

  • First, if you're prototyping code for a Windows App Store application, it's sometimes easier to prototype + debug it first in a console app: easier to set breakpoints, use Console.WriteLine, faster to start-up, less boilerplate, etc.
  • Second, the new WinRT APIs are clean and modern, and better in many cases than the alternatives. If you're willing to restrict the audience of your code to just Windows 8, then they're worth looking into.

Quick checklist

Or, if you want to do the same manually... If you have already read this article before, and are just visiting to remember the steps, here they are:

Unload .vbproj or .csproj:

<TargetPlatformVersion>8.0</TargetPlatformVersion>

Add References:

Windows:

  • System.Net.Http.dll (pick 4.0.0.0)
  • C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETCore\v4.5\System.Runtime.WindowsRuntime.dll
  • C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\Facades\System.Runtime.dll
  • C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\Facades\System.Threading.Tasks.dll
  • C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\Facades\System.IO.dll
  • C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\Facades\System.Runtime.InteropServices.WindowsRuntime.dll

Project-level imports:

  • System.IO
  • System.Runtime.InteropServices.WindowsRuntime

Async Main:

VB.NET
Sub Main
    MainAsync().GetAwaiter().GetResult()
End Sub 

Async Function MainAsync() As Task 
    ... async code goes here
End Function

Getting started

You'll need to have VS2012 and Windows 8 to use this code, and follow this article. I've written everything out in VB, but the same techniques work equally well in C#.

  1. Start a new project:
  2. File > New > Project > VisualBasic > Windows > ConsoleApplication

  3. Mark your project as targeting (requiring) the Win8 platform.
  4. This is documented on MSDN, How to: Add or Remove References By Using the Reference Manager subheading "Core Subgroup" -- well-hidden under the stairs in a filing cabinet with a "beware of the tiger" sign on it!

    • Unload your project
    • Image 1

    • Edit it and add in a target framework directive
    • XML
      <TargetPlatformVersion>8.0</TargetPlatformVersion>

      Image 2

      Image 3

    • Reload your project.
    • Image 4

  5. Add references:
  6. AddReference > WindowsCore > Windows.winmd

    The “Windows” tab only appears in the AddReference dialog if your project is set to target the Windows 8.0 platform.

    Image 5

    AddReference > Assemblies > Framework > System.Net.Http.dll (v4, not v2!)

    AddReference to the following files:

    • AddReference > Browse > C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETCore\v4.5\System.Runtime.WindowsRuntime.dll
    • AddReference > Browse > C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\Facades\System.Runtime.dll
    • AddReference > Browse > C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\Facades\System.Threading.Tasks.dll
    • AddReference > Browse > C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\Facades\System.IO.dll
    • AddReference > Browse > C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\Facades\System.Runtime.InteropServices.WindowsRuntime.dll

    Project > Properties > References > ImportedNamespaces > for the following namespaces:

    • System.IO
    • System.Runtime.InteropServices.WindowsRuntime
    • These imported namespaces are there so you can use the handy extension methods like IBuffer.ToArray() and IInputStream.AsStreamForRead().

Sub Main and Async

Most interesting WinRT APIs are async, so they have to go in an async method. But Sub Main isn’t itself allowed to be async. So this is how we do it:

VB.NET
Module Module1
    Sub Main() 
        MainAsync().GetAwaiter().GetResult()
    End Sub

    Async Function MainAsync() As Task
        ' code goes here...
    End Function
End Module  

You can also write MainAsync().Wait(), but that's not as good. The reason has to do with what happens to any exception that might come out of MainAsync(). As we've written it above, GetAwaiter().GetResult() will show you the details of that exception, and allow you to "[X] break if this exception is thrown". But all that Wait() will show is an AggregateException.

Incidentally, each time our code resumes after an “await”, it might resume on a different thread. You can avoid this by coding up an AsyncPump.Run() method, as described here: http://blogs.msdn.com/b/pfxteam/archive/2012/01/20/10259049.aspx

Using WinRT APIs

StorageFolders. Note: you can't use FilePickers in a console app since they need a UI!

VB.NET
Dim folder = Windows.Storage.KnownFolders.DocumentsLibrary
Dim opts As New Windows.Storage.Search.QueryOptions(
                      Windows.Storage.Search.CommonFileQuery.OrderByName, {".txt"})
Dim files = Await folder.CreateFileQueryWithOptions(opts).GetFilesAsync(0, 20)
For Each file In files
    Console.WriteLine(file.Path)
Next  

Streams. Note: when you dispose of an IO.StreamReader, it automatically disposes the underlying stream that it wraps.

VB.NET
Using reader = New IO.StreamReader(Await files.First.OpenStreamForReadAsync())
    Dim txt = Await reader.ReadToEndAsync()
    Console.WriteLine(txt.Substring(0, 100))
End Using 

Graphics. Incidentally, Windows.Graphics.Imaging is for the raw graphics (which can be done in a console app), but Windows.UI.Xaml.Media.Imaging is for graphics as they appear in App-Store style applications (can't be done in a console app).

VB.NET
Dim pics = Await Windows.Storage.KnownFolders.PicturesLibrary.GetFilesAsync(
                         Windows.Storage.Search.CommonFileQuery.OrderBySearchRank, 0, 1)
Using stream = Await pics.First.OpenReadAsync()
    Dim decoder = Await Windows.Graphics.Imaging.BitmapDecoder.CreateAsync(stream)
    Console.WriteLine(decoder.OrientedPixelWidth & "x" & decoder.OrientedPixelHeight)
End Using 

HttpClient. Actually, this is just part of the .NET Framework (not WinRT), and is the recommended replacement for WebRequest and WebClient. I’m mentioning it here because it’s in System.Net.Http.dll, which is referenced automatically in Windows App Store projects, but not in desktop projects.

VB.NET
Dim client As New Net.Http.HttpClient()
Dim html = Await client.GetStringAsync("http://www.microsoft.com")
Console.WriteLine(html.Substring(0, 100)) 

WinRT Sockets. To end, here’s a bigger example using my favorite language features – async and XML literals! Note the "using r=, w=" clauses. AsStreamForRead() produces an IO.Stream which, when disposed, will also dispose the underlying WinRT Socket.InputStream. And New IO.StreamReader produces a stream which, when disposed, disposes of its underlying stream. Likewise for the writers. So all six(!) streams in this code will dispose correctly.

VB.NET
Using server As New Windows.Networking.Sockets.StreamSocketListener
    Dim serverDoneSignal As New TaskCompletionSource(Of Object)
    AddHandler server.ConnectionReceived, 
        Async Sub(sender, args)
            Using r = New IO.StreamReader(args.Socket.InputStream.AsStreamForRead()),
                  w = New IO.StreamWriter(args.Socket.OutputStream.AsStreamForWrite())
                Dim request = ""
                While True
                    Dim s = Await r.ReadLineAsync() 
                    If String.IsNullOrWhiteSpace(s) Then Exit While
                    request &= s & vbCrLf 
                End While 
                Console.WriteLine("<--------" & vbCrLf & request)
                Dim body = <html>
                              <head>
                                   <title>Hello World</title>
                               </head>
                               <body>
                                   <%= Iterator Function()
                                          For i = 0 To 9
                                               Yield <p>Hello word #<%= i %></p>
                                           Next
                                       End Function() %>
                               </body>
                          </html> 
                Dim headers = "HTTP/1.0 200 OK" & vbCrLf &
                              "Content-Type: text/html; charset=utf-8" & vbCrLf & vbCrLf
                Await w.WriteAsync(headers)
                Await w.WriteAsync(body.ToString())
            End Using 
            serverDoneSignal.SetResult(Nothing)
        End Sub 
    Await server.BindServiceNameAsync("")
    Diagnostics.Process.Start("http://127.0.0.1:" & server.Information.LocalPort & "/")
    Await serverDoneSignal.Task
End Using  

Disclaimer

Disclaimer: Although I work at Microsoft on the VB/C# language team, this article is strictly a personal amateur effort based on public information and experimentation - it's not in my professional area of expertise, is written in my own free time, and neither Microsoft nor I make any claims about its correctness.

License

This article, along with any associated source code and files, is licensed under A Public Domain dedication


Written By
Technical Lead
United States United States
Lucian studied theoretical computer science in Cambridge and Bologna, and then moved into the computer industry. Since 2004 he's been paid to do what he loves -- designing and implementing programming languages! The articles he writes on CodeProject are entirely his own personal hobby work, and do not represent the position or guidance of the company he works for. (He's on the VB/C# language team at Microsoft).

Comments and Discussions

 
QuestionEditing project file is unnecessary Pin
Sam Hobbs11-Feb-24 10:36
Sam Hobbs11-Feb-24 10:36 
Questionwhat is WinRT ? Pin
Tridip Bhattacharjee18-Dec-14 21:00
professionalTridip Bhattacharjee18-Dec-14 21:00 
SuggestionDifferences in Win 8.1 .NET 4.5.1 Pin
lansoprazole2-Jun-14 23:11
lansoprazole2-Jun-14 23:11 
QuestionReason's for Adding WinRT API in Desktop Apps. Pin
Ranjan.D8-Jan-13 14:33
professionalRanjan.D8-Jan-13 14:33 
AnswerRe: Reason's for Adding WinRT API in Desktop Apps. Pin
FIorian Schneidereit8-Aug-14 15:34
FIorian Schneidereit8-Aug-14 15:34 
QuestionCan I add references to the Win rt project (dll)? Pin
Hitesh Chaudhary7-Nov-12 20:46
Hitesh Chaudhary7-Nov-12 20:46 
Questionpublish causes ResolveManifestFiles task failed erro Pin
EdCoughlin16-Oct-12 18:46
EdCoughlin16-Oct-12 18:46 
QuestionThank you Pin
Albarhami13-Sep-12 4:11
Albarhami13-Sep-12 4:11 
QuestionThanks Pin
Albarhami13-Sep-12 3:40
Albarhami13-Sep-12 3:40 
QuestionUnload Project? Pin
dtanderson12-Sep-12 10:13
dtanderson12-Sep-12 10:13 
AnswerRe: Unload Project? Pin
ljw100412-Sep-12 10:26
ljw100412-Sep-12 10:26 
When you create a new desktop app, it by default targets .NET45. There's a drop-down in the IDE that lets you change that to target lower versions of .NET.

But there isn't an IDE dropdown that lets you chose which version of Windows your app targets.

Editing .proj files by hand is always an easy escape valve, and means that the VS team isn't forced to expose every last thing through a UI under Project>Properties. Other examples: if you have a desktop VB project and want to use the VBCore feature, you have to add <vbruntime>Embed manually. And the IDE for VB only shows a few "treat warnings as errors" options, so for fine-grained control you also do that in the .vbproj file.
GeneralMy vote of 5 Pin
Kanasz Robert12-Sep-12 3:18
professionalKanasz Robert12-Sep-12 3:18 
QuestionUsing controls Pin
Veler12-Sep-12 0:44
Veler12-Sep-12 0:44 
Questionregarding WinRT APIs Pin
Tridip Bhattacharjee11-Sep-12 20:08
professionalTridip Bhattacharjee11-Sep-12 20:08 
AnswerRe: regarding WinRT APIs Pin
André Ziegler11-Sep-12 23:45
André Ziegler11-Sep-12 23:45 
GeneralRe: regarding WinRT APIs Pin
ljw100412-Sep-12 6:41
ljw100412-Sep-12 6:41 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.