Check out Hilo for Windows 8!

I’m working with the patterns & practices team on a Metro style app with C++ and XAML called Hilo. Hilo is a basic photo viewing and tagging app that totally re-imagines Hilo for Windows 7 by embracing new form factors and experiences that Windows 8 enables.

One of the more exciting aspects of Hilo is the use of the new PPL tasks to enable a fast and fluid user experience. The heart of PPL tasks, the concurrency::task class, simplifies the process of performing operations asynchronously, or in the background, and then using the results of the asynchronous operations to update the UI.

For example, Hilo defines the ThumbnailGenerator class to generate thumbnails for pictures that are displayed on the app’s Start menu tile. The ThumbnailGenerator::Generate queues a task that converts each image in the provided vector to a thumbnail that is displayed on the tile. The call to concurrency::when_all enables this method to collect the results when they are ready and produce a second vector that contains the resulting thumbnail images.

  1: task<Platform::Collections::Vector<StorageFile^>^> ThumbnailGenerator::Generate( 
  2:     IVector<StorageFile^>^ files, 
  3:     StorageFolder^ thumbnailsFolder)
  4: {
  5:     vector<task<StorageFile^>> thumbnailTasks;
  6:  
  7:     unsigned int imageCounter = 0;
  8:     for_each(begin(files), end(files),
  9:         [&imageCounter, thumbnailsFolder, &thumbnailTasks](StorageFile^ imageFile)
  10:     {
  11:         wstringstream localFileName;
  12:         localFileName << ThumbnailImagePrefix << imageCounter++ << ".jpg";
  13:  
  14:         thumbnailTasks.push_back(
  15:             CreateLocalThumbnailAsync(
  16:             thumbnailsFolder,
  17:             imageFile, 
  18:             ref new String(localFileName.str().c_str()),
  19:             ThumbnailSize));   
  20:     });
  21:  
  22:     return when_all(begin(thumbnailTasks), end(thumbnailTasks)).then(
  23:         [](vector<StorageFile^> files)
  24:     {
  25:         auto result = ref new Platform::Collections::Vector<StorageFile^>();
  26:         for_each(begin(files), end(files), [result](StorageFile^ file)
  27:         {
  28:             if (file != nullptr)
  29:             {
  30:                 result->Append(file);
  31:             }
  32:         });
  33:         return result;
  34:     });
  35: }

This method behaves asynchronously. The caller to this method receives a task object and can then chain additional tasks that will run after that task completes.

Here’s another example. This one creates a chain of continuations to save the thumbnail image to disk. The ThumbnailGenerator::InternalSaveToFile method is called by ThumbnailGenerator::CreateLocalThumbnailAsync in the previous example.

  1: task<StorageFile^> ThumbnailGenerator::InternalSaveToFile(
  2:     StorageFolder^ thumbnailsFolder, 
  3:     InMemoryRandomAccessStream^ stream, 
  4:     Platform::String^ filename)
  5: {
  6:     auto imageFile = make_shared<StorageFile^>(nullptr);
  7:     auto streamReader = ref new DataReader(stream);
  8:     task<unsigned int> loadStreamTask(
  9:         streamReader->LoadAsync(static_cast<unsigned int>(stream->Size)));
  10:  
  11:     return loadStreamTask.then(
  12:         [thumbnailsFolder, filename](unsigned int loadedBytes)
  13:     {
  14:         return thumbnailsFolder->CreateFileAsync(
  15:             filename, 
  16:             CreationCollisionOption::ReplaceExisting);
  17:  
  18:     }).then([streamReader, imageFile](StorageFile^ thumbnailDestinationFile) 
  19:     {
  20:         (*imageFile) = thumbnailDestinationFile;
  21:         auto buffer = streamReader->ReadBuffer(
  22:             streamReader->UnconsumedBufferLength);
  23:  
  24:         return FileIO::WriteBufferAsync(thumbnailDestinationFile, buffer);
  25:  
  26:     }).then([imageFile]()
  27:     {
  28:         return (*imageFile);
  29:     });
  30: }

Although this method is called as part of another asynchronous operation, we got in the habit of always using asynchronous operations so that we can later compose them together. This is key to keeping work off of the UI thread, and thus keeping the app responsive to user input.

We also strive to use lambda functions, standard algorithms, the auto keyword, and other modern C++ constructs as much as possible.

Check out Hilo for Windows 8 at https://hilo.codeplex.com. You’ll need Windows 8 Consumer Preview and Microsoft Visual Studio 11 Express Beta for Windows 8 to run the sample.

This project is a work in progress. Try it today and be sure to join us on the Discussions tab. We’d love to hear your feedback on our progress!