Friday, December 20, 2013

What are you Awaiting for - How to Turn a C/C++ Callback into a C++/Cx WinRT IAsyncAction

Windows and Windows Phone 8 and its WinRT / WinPRT component model provide a nice way to leverage good ol' native C/C++ libraries in all WinMD language projections by wrapping them in a WinRT C++/Cx component. Such a native WinRT component only exposes WinRT types and can therefore be consumed through the WinMD projections also in C# or WinJS.
Often those good ol' native libraries provide events or callback functions for asynchronous calls. This means one would also have to provide a WinRT wrapper for those events and callbacks as well, although the WinRT has the nice IAsyncAction and IAsyncOperation constructs together with the Parallel Patterns Library (PPL) which make the WinRT component way better to use.
This post describes how to plug both worlds together to turn your good ol' C++ code into rose colored C++/Cx consumable through WinMD.

We won't go too deep into C++/Cx in general here. There's a good intro at the MSDN and also a nice Quick Reference which provides a table how Standard C++ types and constructs compare to C++/Cx. I also don't cover how the PPL and WinRT async works here, but there's a great MSDN page: Creating Asynchronous Operations in C++ for Windows Store Apps.


Assuming you have a good ol' native interface like this with a defined callback template:
template <typename TCallback>
HRESULT StartAsyncOperation(const TCallback &callback)
{
...
}


It could be used like this using a C++11 lambda as callback function:
StartAsyncOperation([this](HRESULT error) -> HRESULT
{
   // Do whatever here after the async is done...
   // Notify the calling code through an event or another callback 
   // that the async operation has finished.
   return S_OK;
});

It's worth mentioning this will also work with C function pointers and you can use a C++ 11 lambda for it as long as the lambda does not capture any variable. Stateless lambdas will just degrade to function pointers.
// Definition of fucntion pointer and a function expecting it as parameter
typedef void (*SomeOtherCallback)(int param1);

FunctionExpectingSomeOtherCallback(SomeOtherCallback cb);

// Example call using a stateless lambda
FunctionExpectingSomeOtherCallback([](int param1)
{
   // Perform some operation with param1
});

This is how your C++/Cx WinRT component's method which wraps the above C++ template could look like:
Windows::Foundation::IAsyncAction^ MyWinRtComponent::RunAsync()
{
 // Setup  the Task Completion Event and the async Task
 Concurrency::task_completion_event<void> tce;
 auto tsk = Concurrency::create_task(tce);
 Windows::Foundation::IAsyncAction^ asyncOp = Concurrency::create_async( [tsk]() 
            -> Concurrency::task<void> 
 {
  return tsk;
 });

 // Run good ol' native code wih callback defined as C++ lambda
 StartAsyncOperation([this, tce](HRESULT error) -> HRESULT
 {
  try
  {
   // Check for error and wrap in platfrom exception
   if (FAILED(error))
   {
    throw Platform::Exception::CreateException(error);
   }
  }
  catch(...)
  {
   // Pass exception on to calling code using the 
   // Task Completion Event's dedicated method
   tce.set_exception(std::current_exception());
   return error;
  } 

  // Set the Task Completion Event's Result to mark the Task as complete
  // If a IAsyncOperation is used the result value is passed
  tce.set();

  return S_OK;
 });

 return asyncOp;
}


You could then use your WinRT component in C# like this:
var component = new MyWinRtComponent();
await component.RunAsync();


And similar in WinJS using a JS Promise:
this._component.runAsync().then(function () {
 WinJS.log("My component finished the async call! :-)", null, "status");
});


Way better API for the custom WinRT component if you ask me!
The trick to achieve that is the usage of the PPL's create_async, create_task and especially the task_completion_event which provides a nice way to make that callback-based model work with the proper WinRT modern async Task-based way.

How to Encode and Save a WriteableBitmap with Windows WinRT


Windows WinRT 8.1 brought the support of the RenderTargetBitmap and the ability to render the visual tree of the UI into a bitmap. WriteableBitmapEx makes it even easier in the latest version and you might end up in a situation where you want to save a WriteableBitmap to a file or to a stream in general. For that the raw pixel array of the WriteableBitmap needs to be encoded into a common format like JPEG, PNG, etc.

Here's a code snippet how this can be achieved:






private static async Task SaveWriteableBitmapAsJpeg(WriteableBitmap bmp, string fileName)
{
   // Create file in Pictures library and write jpeg to it
   var outputFile = await KnownFolders.PicturesLibrary.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);
   using (var writeStream = await outputFile.OpenAsync(FileAccessMode.ReadWrite))
   {
      await EncodeWriteableBitmap(bmp, writeStream, BitmapEncoder.JpegEncoderId);
   }
   return outputFile;
}

private static async Task EncodeWriteableBitmap(WriteableBitmap bmp, IRandomAccessStream writeStream, Guid encoderId)
{         
   // Copy buffer to pixels
   byte[] pixels;
   using (var stream = bmp.PixelBuffer.AsStream())
   {
      pixels = new byte[(uint) stream.Length];
      await stream.ReadAsync(pixels, 0, pixels.Length);
   }

   // Encode pixels into stream
   var encoder = await BitmapEncoder.CreateAsync(encoderId, writeStream);
   encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied,
      (uint) bmp.PixelWidth, (uint) bmp.PixelHeight,
      96, 96, pixels);
   await encoder.FlushAsync();
}

It's all  pretty straightforward actually: The SaveWriteableBitmapAsJpeg creates a file in the user's pictures library and passes the file's stream and an BitmapEncoder ID on to the EncodeWriteableBitmap method which is doing the actual work. EncodeWriteableBitmap first copies the WriteableBitmap pixel buffer into a byte array, then creates the BitmapEncoder based on the file's stream and the desired BitmapEncoder ID, then sets the pixels and flushes all into the stream.
The BitmapEncoder class supports a couple of BitmapEncoder IDs out of the box like JPEG, PNG and more.

Monday, December 2, 2013

Easy Render! - WriteableBitmapEx now with Better Support for Win 8.1 RenderTargetBitmap


The lack of WriteableBitmap.Render in Windows WinRT 8.0 was quite an issue for many apps, but fortunately did WinRT 8.1 (re-)introduce the RenderTargetBitmap class which provides the functionality of rendering the visual tree of the UI to a bitmap. The new update of WriteableBitmapEx makes it even easier to use with a WriteableBitmap by introducing the FromPixelBuffer method.

WriteableBitmapEx is available for 4 platforms: Windows Phone 8 and 7, WPF, Silverlight and Windows Store WinRT .NET XAML 8 and 8.1.
You can download the binaries here or via the NuGet packageThe packages contain the WriteableBitmapEx binaries. As usual all samples and the source code can be found in the repository.



How to use
The below code snippet shows how a part of the UI can be rendered into a WriteableBitmap via RenderTargetBitmap, how it can be modified and then finally presented back into the UI by using an Image control.

// Render some UI to a RenderTargetBitmap
var renderTargetBitmap = new RenderTargetBitmap();
await renderTargetBitmap.RenderAsync(Panel);
            
// Get the pixel buffer and copy it into a WriteableBitmap
var pixelBuffer = await renderTargetBitmap.GetPixelsAsync();
var width = renderTargetBitmap.PixelWidth;
var height = renderTargetBitmap.PixelHeight;
var wbmp = await new WriteableBitmap(1, 1).FromPixelBuffer(pixelBuffer, width, height);

// Modify the WriteableBitmap
wbmp.FillEllipse(10, 10, 256, 256, Colors.Salmon);
// ... More drawing including writeableBitmap.Blit(...) might go here

// Assign WriteableBitmap to an Image control to present it
ImgMirror.Source = wbmp;

Quick! - How to Open WP Settings from Code

The Windows Phone File and Uri associations are very useful for implementing custom cross-app functionality like Pictures Lab and other apps provide. Windows Phone also provides uri schemes for many built-in apps and settings which can be very handy.
The Windows Phone 8 update GDR3 introduced a new setting to lock the screen rotation. This setting is quite useful especially when reading in bed or for providing on-screen QR codes to scanners.
This useful screen rotation lock is unfortunately hidden in the settings and it takes a few taps to access it. Therefore I've written a tiny free app called Screen Rotation Lock. It provides quick access to the screen rotation settings through a pinned secondary tile.



The relevant code in the MainPage is rather straight forward but there are some details which are worth sharing and which apply to any shortcut uri navigation:

protected override void OnNavigatedTo(NavigationEventArgs e)
{
   base.OnNavigatedTo(e);

   // Actual shortcut navigation?
   if (NavigationContext.QueryString.ContainsKey(UriQueryStringKeyPage))
   {
      // If coming from setting than skip here
      if (e.NavigationMode == NavigationMode.Back)
      {
         Application.Current.Terminate();
      }
      // Otherwise go to setting
      Windows.System.Launcher.LaunchUriAsync(new Uri("ms-settings-screenrotation:"));
   }

   //Check for support
   var gdr3Version = new Version(8, 0, 10492);
   if (Environment.OSVersion.Version < gdr3Version)
   {
      MessageBox.Show(String.Format("Sorry, your phone does not support the screen rotation lock feature yet. You need to have the Windows Phone version {0} installed  (WP 8 GDR 3).\r\nThe app will now exit.", gdr3Version), "Not supported version", MessageBoxButton.OK);
      Application.Current.Terminate();
   }
}

The first if statement tests if the navigation comes from the secondary tile with the associated key UriQueryStringKeyPage. If it's a back navigation, the user was actually forwarded already to the setting and tapped back. In that case we don't want the user to land in our app, but rather go back to the start screen where she/he comes from, so we close our app. If it's not a back navigation the forward to the setting takes place using the Launcher API and the LaunchUriAsync method with the right uri for screen rotation.
The last if statement tests the version of the device and shows an error message if the device does not have GDR3 installed. This is done as last statement since it's actually only needed when the user wants to pin the secondary tile shortcut and opens the app itself.