How to use specific WinRT API from Desktop apps: capturing a photo using your webcam into a WPF app - Eternal Coding - HTML5 / Windows / Kinect / 3D development - Site Home - MSDN Blogs

How to use specific WinRT API from Desktop apps: capturing a photo using your webcam into a WPF app


 

How to use specific WinRT API from Desktop apps: capturing a photo using your webcam into a WPF app

  • Comments 9

Windows Runtime (WinRT) APIs are a platform-homogeneous application architecture on the Windows 8 operating system. These APIs are used to develop Windows Store applications.

However, some APIs can also be called from the desktop. The MSDN documentation is really useful to determine which are compatible. For instance, here is the requirements of the MediaCapture class of WinRT:

image

As you can see, this API can be called by a desktop application.

A friend of mine, Christophe Nasarre (who is Premier Field Engineer at Microsoft France) wrote a great tool to get the list of all supported WinRT APIs for desktop applications:

image

Creating a WPF app that can access WinRT APIs

First of all, let’s start with a simple WPF 4.5 application. The main page will look like this:

<Window x:Class="WPF_WinRT.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Image x:Name="displayImage"/>
    </Grid>
</Window>

Nothing special. Just an Image control to display the photo.

To add support for WinRT, you will have to unload the project from Visual Studio 2013 and add the following lines into the project file:

  <PropertyGroup>
    <TargetPlatformVersion>8.0</TargetPlatformVersion>
  </PropertyGroup>

These lines allow you to reference Windows core APIs for WinRT (once you have reloaded your project):

image

Using MediaCapture API

The MediaCapture class is a wonderful tool to access microphone and camera. Here is a standard (and simple) code used to get a photo from a webcam:

var devices = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture);
if (devices.Count == 0)
{
    MessageBox.Show("Unable to connect to a video capture device", "Error", MessageBoxButton.OK);
    return;
}

var mediaCapture = new MediaCapture();
mediaCapture.Failed += (s, errorEventArgs) => MessageBox.Show("Unable to start capture:" + 
errorEventArgs.Message,
"Error", MessageBoxButton.OK); await mediaCapture.InitializeAsync(); var jpgProperties = ImageEncodingProperties.CreateJpeg(); jpgProperties.Width = (uint)displayImage.ActualWidth; jpgProperties.Height = (uint)displayImage.ActualHeight; using (var randomAccessStream = new InMemoryRandomAccessStream()) { await mediaCapture.CapturePhotoToStreamAsync(jpgProperties, randomAccessStream); }

If you try to compile it, you will get some errors.

The first one is related to System.Runtime:

The type 'System.Collections.Generic.IEnumerable`1<T0>' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.

To solve this issue (mainly related to missing types), you just have to add a reference to this assembly (System.Runtime.dll):

image

The second error is the related to the await keyword. Actually, in order to await an IAsyncAction (the result type of FindAllAsync method for instance), you have to provide a GetAwaiter method:

'await' requires that the type 'Windows.Foundation.IAsyncOperation<Windows.Devices.Enumeration.DeviceInformationCollection>' have a suitable GetAwaiter method. Are you missing a using directive for 'System'?

To fix this issue, you have to reference the following assembly (System.Runtime.WindowsRuntime.dll):

image

Finally a last error remains:

Property, indexer, or event 'Windows.Media.Capture.MediaCapture.Failed' is not supported by the language; try directly calling accessor methods 'Windows.Media.Capture.MediaCapture.add_Failed(Windows.Media.Capture.MediaCaptureFailedEventHandler)' or 'Windows.Media.Capture.MediaCapture.remove_Failed(System.Runtime.InteropServices.WindowsRuntime.EventRegistrationToken)'

To add the missing interop features, just add the following assembly (System.Runtime.InteropServices.WindowsRuntime):

image

Once you have added these three references you are done! Nothing more is required.

However, you must note that event though some WinRT APIs are available for the Desktop, this is NOT the case for XAML controls (such as CaptureElement for instance).

Converting IRandomAccessStream to System.IO.Stream

The last point here is about the IRandonAccessStream (implemented by the InMemoryRandomAccessStream class). If we want to work with WPF, we have to convert it to System.IO.Stream.

Obviously, there is a simple way to do that: You just have to reference System.IO.WindowsRuntimeStreamExtensions class. Using this class, you will be able to use handy extensions methods such as AsStream:

using (var randomAccessStream = new InMemoryRandomAccessStream())
{
    await mediaCapture.CapturePhotoToStreamAsync(jpgProperties, randomAccessStream);

    randomAccessStream.Seek(0);
    using (var ioStream = randomAccessStream.AsStream())
    {
        var bitmapImage = new BitmapImage();
        bitmapImage.BeginInit();
        bitmapImage.StreamSource = ioStream;
        bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
        bitmapImage.EndInit();

        displayImage.Source = bitmapImage;
    }
}

And that’s it! You can now use the power of some WinRT APIs from your desktop app!

[Video] Another WinRT/Desktop application

Christophe Nasarre also created an excellent video which talk about the same topic. This is a really good and educational resource:
http://blogs.msdn.com/b/mspfe/archive/2013/09/24/winrt-for-desktop-apps.aspx

Leave a Comment
  • Please add 3 and 7 and type the answer here:
  • Post
  • Great

  • its nice to see windows released api fr accessing webcam from desktop !

    i am web developer and want to create html5 app fr windows store so how can i accsess this api from javascript in IE browser

  • The solution link point to HelloWorld.

  • The DualApiFinder requires .NET 3.5!!! Why? We have the Windows 8!

    Funny...

  • Thanks for taking the time to write this!  By any chance do you have a sample project that demonstrates this?

  • Thanks for this great example. I'm running into a problem where the async methods are throwing errors that they don't have IsCompleted methods declared. I'm pretty new to the async stuff introduced in 4.0. Any ideas?

  • I am getting the following error message: The 'await' operator can only be used within an async method. Consider marking this method with the 'async' modifier and changing its return type to 'Task'. I was wondering if you could help.

  • Hello yes you jus thave to mark your method like this:

    async Task MyFunc()

    {

    }

  • My picture comes out as black. How to solve this??

Page 1 of 1 (9 items)