Martin's Tex-Blog

Posts on programming and generally technical topics

Archive for the ‘WinRT’ Category

Background Task Sample in C++ Metro Style App

leave a comment »


In this post I will show step by step how to write metro style app that will register for system notifications. In samples section for Metro style apps in MSDN dev center, you can find “Background Task Sample” sample code for C# and JavaScript. There is also a white paper for Background tasks at this link:

http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=27411

One thing I was not able to reproduce from this document is putting Run() method inside main app.

Sample app described below registers background task to Internet availability event. You can easily change it to TimerTrigger, but testing it is very difficult since you must wait 15 minutes before it will be notified to you. I have also found that TimeZoneChange event is easy to trigger manually, you just have to change your time zone.

I assume you have installed Windows Developer Preview

1. Open Visual Studio Express 11  and create new project : “Visual C++” -> “Windows Metro Style” -> Application. Name it BackgroundSample.

2. Now add WinRT Component DLL. Choose File -> New Project -> “Visual C++” -> “Windows Metro Style” -> “WinRT Component DLL”. Name it BackgroundTask, and choose “Add to solution” in Solution combobox.

3. In solution explorer right click on BackgroundTaskSample project and choose Project Dependencies. Then check “BackgroundTask” from project list.

4. Now you have to reference your WinRT component in main app. Once again right click on BackgroundSample project and choose References… Click on Add New Reference, and once new window shows up, double click on BackgroundTask item. There should appear a green tick on the left of it.

5. Now we need to setup Background Task declaration in manifest file. Double click on Package.appxmanifest file in BackgroundSample project file list. Then:

– from Application UI tab change “Toast Capable:” from No to Yes. We will use toast to inform of background task completion.

– make sure “Internet (client)” capability is checked on Capabilities tab

– On Declarations tab choose “Background Tasks” from available declarations combobox, and click Add. Then check SystemEvent and Timer. Change EntryPoint to: BackgroundTask.WinRTComponent.

6. Ok, now lets start coding. Open MainPage.xaml.cpp file in you main app, and add in MainPage::MainPage following code (below using namespace code block):


using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Data;
using namespace Windows::ApplicationModel::Background;
using namespace Windows::Data::Xml::Dom;
using namespace Windows::UI::Notifications;

ToastNotifier^ toastNotifier = nullptr; // Ugly global variable
void DisplayToastWithImage(String^ str) {
  XmlDocument^ toastXml =
    ToastNotificationManager::GetTemplateContent(ToastTemplateType::ToastText01);
  XmlNodeList^ textElements = toastXml->GetElementsByTagName("text");
  for (int i = 0; i Length; i++) {
    XmlText^ newNode = toastXml->CreateTextNode(str);
    textElements->Item(i)->AppendChild((IXmlNode^)newNode);
  }
  ToastNotification^ toast = ref new ToastNotification(toastXml);
  if ( toastNotifier == nullptr )
    toastNotifier = ToastNotificationManager::CreateToastNotifier();
    toastNotifier->Show(toast);
}

in MainPage::MainPage() add following code below InitializeComponent():


/// If task was already registered then only add Completed event handler
/// System remembers registrations even if app was closed.
bool registrationIsRequired = true;
auto iter = BackgroundTaskRegistration::AllTasks->First();
if ( iter->HasCurrent ) {
  do {
    auto guid = iter->Current->Key;
    IBackgroundTaskRegistration^ task = iter->Current->Value;
    registrationIsRequired = false;
    DisplayToastWithImage("Already registered");
    task->Completed += ref new BackgroundTaskCompletedEventHandler(this, &MainPage::OnCompleted);
    //task->Unregister(true);
    } while ( iter->MoveNext() );
}

if ( registrationIsRequired ) {
  BackgroundTaskBuilder^ myTaskBuilder = ref new BackgroundTaskBuilder();
  ISystemTrigger^ trigger = ref new SystemTrigger(SystemTriggerType::InternetAvailable, false);
  myTaskBuilder->SetTrigger(trigger);
  myTaskBuilder->TaskEntryPoint = "BackgroundTask.WinRTComponent";
  myTaskBuilder->Name = "InternetAvailableChange";
  IBackgroundTaskRegistration^ taskReg = myTaskBuilder->Register();
  taskReg->Completed += ref new BackgroundTaskCompletedEventHandler(this, &MainPage::OnCompleted);
  DisplayToastWithImage("Registered");
}

Now add OnCompleted method (and appropriate declaration in MainPage header file):

void MainPage::OnCompleted(Windows::ApplicationModel::Background::IBackgroundTaskRegistration^ sender, Windows::ApplicationModel::Background::BackgroundTaskCompletedEventArgs^ args) {
  /// This code will be called even if App is closed.
  DisplayToastWithImage("MainPage::OnCompleted");
}

Whats left is to modify WinRT Component project:

add

using namespace Windows::ApplicationModel::Background;

in WinRTComponent.h file, then derive WinRTComponent class from IBackgroundTask and implement Run method:

public: virtual void Run(IBackgroundTaskInstance^ taskInstance) override {
}

it is empty, because we show Toast in OnCompleted method in main app.

…thats all, after running this app, you can turn off your network card and again on, and a “MainPage::OnCompleted” toast will show up.

Below you will find attached sample project:

BackgroundTaskSample.zip

Advertisements

Written by Marcin

January 30, 2012 at 2:55 am