Share via



2012

Volume 27

Windows Runtime and C++ - Porting Desktop Applications to the Windows Runtime

By Diego Dagum | 2012

Windows 8 embodies a new design philosophy for Microsoft platforms. In Windows 8, you can create apps using UI technologies such as XAML and HTML5. Microsoft provides two new app models: the Windows Runtime Library (WRL), which helps you develop Windows Store apps with C#, Visual Basic and C++, and the Windows Library for JavaScript (WinJS), which lets you create HTML5 and JavaScript apps.

The WRL is to Windows 8 what the Microsoft Foundation Class framework (MFC) or the C-like Win32 APIs are to the desktop environment. Consequently, existing desktop applications must be adapted to run under the Windows Runtime. The dilemma comes with applications that depend heavily on MFC, Win32 or other application frameworks. What happens with them if they’re ported to the Windows Runtime? What happens thereafter? Is it necessary to maintain both codebases—tablet and desktop?

In this article, I’ll show you how you can identify and extract substantial portions from the application codebase and share them between the two environments. You’ll see how this refactoring activity is also an opportunity to leverage some new C++11 features for conciseness and maintainability. And the benefits are more than just gaining a new Windows Store version of an existing app; the existing application codebase is upgraded as well.

Portability and Its Dilemmas

It’s always easier to build an application with portability and other non-functional requirements from scratch, architecting it accordingly. In practice, though, application developers are often challenged by unforeseen requirements that emerge after the application has been deployed. Satisfying these later needs may prove problematic if the application is architected in a way that makes new features difficult to implement without rewriting large portions. The new parts can eventually lead to an application breakage in production if not carefully tested.

Because of this, I decided to use as an example an existing application instead of creating my own demo. As you’ll see, I chose an MFC calculator sample published by Microsoft for Visual Studio 2005  (bit.ly/OO494I).

The option of rewriting the entire application seems appealing at first, because you want to get rid of code you don’t want to maintain—you’d rather redo it from scratch, but this time do it well. But management can’t be convinced because it erodes the return on investment (ROI) expected from the original application, unless that app stays in production for users whose platforms can’t run the new application. If this is the case, two similar codebases will need to be maintained, increasing costs (twice the work—or more—to implement new features or fix bugs, for example).

It’s unlikely that all of the original code can be reused in different environments (Windows desktop and the Windows Runtime, in this case). However, the more that can be shared, the lower the costs and, consequently, the higher the profits.

Back to the Basics: Separation of Concerns

Separation of concerns (SoC) is an established concept today, published in many software architecture books. One of its natural consequences is that API-related code is cohesively grouped (not to say hidden) into well-segmented components that offer an abstract interface to the rest. Thus, a concrete data repository is never exposed explicitly to code that performs domain logic, presentation logic and so forth. These components just “talk” to the abstract interface.

SoC is nowadays widely adopted among developers. As a consequence of the Web explosion that began in the late ’90s, many standalone applications were broken up in modules that were then distributed across layers and tiers.

If you have applications developed without regard for SoC, you can bring them into the modern world by refactoring. Refactoring is a healthy practice performed nowadays thanks to the wide adoption of Agile practices, which promote building the simplest things that can possibly work, getting all tests passed and maximizing software throughput, time to market and so forth. However, agility doesn’t leave much room for enabling new channels until this becomes a need. Here we are, then.

A Typical Porting Scenario

The sample MFC application I mentioned earlier, a basic calculator, is shown in Figure 1.

The Microsoft MFC Calculator
Figure 1 The Microsoft MFC Calculator

This sample is great to illustrate the porting process for the following reasons:

  • It’s small enough for you to get the overall idea of what it does.
  • It’s large enough to allow me to show the process in detail. The average application will probably have a larger codebase, but the porting will consist of a repetition of the steps I’ll describe here.
  • The code is coupled enough to show decoupling through refactoring. It was probably intentionally coupled to keep the codebase compact and comprehensible. I’ll decouple the code until I get a common codebase that’s used by MFC and Windows 8 versions. I won’t decouple further, but I’ll suggest how much more the code can be decoupled.

The original calculator application contains two classes: CCalc­App and CCalcDlg. CCalcApp models the calculator as a running process whose InitInstance function instantiates a CCalcDlg (see Figure 2). CCalcDlg models the main window, its controls (panel and buttons) and associated events.

Original Calculator Sample Class Diagram Showing Essentials
Figure 2 Original Calculator Sample Class Diagram Showing Essentials

CCalcDlg derives from MFC CDialog and its implementation does everything, from its basic mapping of window messages, to its functions and the implementation of the calculator logic triggered as a response to these events. Figure 3 shows what happens when the equal sign button is clicked (presumably after two operands and an operator were entered). Figure 4shows the CCalcDlg functions that add behavior at all levels: event reaction, domain logic and presentation.

Sequence Diagram for an Event—Clicking the Equal Sign Button

Figure 3 Sequence Diagram for an Event—Clicking the Equal Sign Button

Figure 4 CCalcDlg
// CCalcDlg.cpp
// Window messages trigger CCalcDlg function invocations
BEGIN_MESSAGE_MAP(CCalcDlg, CDialog)
  ON_WM_PAINT()
  ON_COMMAND_RANGE(IDB_0, IDB_9, OnClickedNumber)
  ON_BN_CLICKED(IDB_CLEAR, OnClickedClear)
  ON_BN_CLICKED(IDB_DIVIDE, OnClickedDivide)
  ON_BN_CLICKED(IDB_EQUAL, OnClickedEqual)
  ON_BN_CLICKED(IDB_MINUS, OnClickedMinus)
  ON_BN_CLICKED(IDB_PLUS, OnClickedPlus)
  ON_BN_CLICKED(IDB_TIMES, OnClickedTimes)
  ON_EN_SETFOCUS(IDE_ACCUM, OnSetFocusAccum)
END_MESSAGE_MAP()
 
...
 
// Event reaction
void CCalcDlg::OnClickedEqual() {
  PerformOperation();
  m_operator = OpNone;
}
 
// Domain logic
void CCalcDlg::PerformOperation() {
  if (m_bOperandAvail) {
    if (m_operator == OpNone)
      m_accum = m_operand;
    else if (m_operator == OpMultiply)
      m_accum *= m_operand;
    else if (m_operator == OpDivide) {
      if (m_operand == 0)
        m_errorState = ErrDivideByZero;
      else
        m_accum /= m_operand;
      }
    else if (m_operator == OpAdd)
      m_accum += m_operand;
    else if (m_operator == OpSubtract)
      m_accum -= m_operand;
  }
 
  m_bOperandAvail = FALSE;
  UpdateDisplay();
}
 
// Presentation logic
void CCalcDlg::UpdateDisplay() {
  CString str;
  if (m_errorState != ErrNone)
    str.LoadString(IDS_ERROR);
  else {
    long lVal = (m_bOperandAvail) ? m_operand : m_accum;
    str.Format(_T("%ld"), lVal);
  }
  GetDlgItem(IDE_ACCUM)->SetWindowText(str);
}

Because CCalcDlg is tied to MFC, the logic I want to use in the Windows Store version of the application can’t be ported as is. I’ll have to do some refactoring.

Refactoring to Decouple Reusable Components

To create a Windows Store version of this calculator, I don’t need to recode everything. Much of the behavior, such as what’s shown in Figure 4, could be reused if it were not so tied to the MFC-based CCalcDlg. I’ll refactor the application in a way that reusable parts (the calculator behavior in this case) are isolated from implementation-specific components.

I’ll assume you’ve not only heard about the Model-View-Controller (MVC) architecture pattern but have also applied it. I’ll just recap the pattern here: the Model consists of domain objects (both stateless and not) and doesn’t know or care about the View technology. The View is implemented in some user-interaction technology (HTML, Qt, MFC, Cocoa, among others) that’s suitable for the application device. It doesn’t know how the domain logic is implemented; its function is just to display domain data structures or part of them. The Controller acts as a go-between by capturing user input to trigger actions in the domain, which causes the View to update to reflect a newer status.

MVC is widely known, but it’s not the only way to isolate the UI from the domain. In the calculator scenario I’ll rely on an MVC variation known as Presentation Model (bit.ly/1187Bk). I initially considered Model-View-ViewModel (MVVM), another variation that’s popular among Microsoft .NET Framework developers. Presentation Model was a better fit for this scenario, though. Presentation Model is ideal when you want to implement a new user-interaction technology (Windows 8, in this case), but no changes are to be made in terms of the UI behavior. This pattern still considers a Model and a View as before, but the Controller role is played by an abstract representation of the View named the Presentation Model. This component implements the common behaviors of the View, including part of its status, without regard for the technology of the View.

Figure 5depicts the modified version of the MFC application.

The Namespace Calculator::View Consolidates the View Behavior in Its Associated Presentation Model
Figure 5 The Namespace Calculator::View Consolidates the View Behavior in Its Associated Presentation Model

CalculatorPresentationModel keeps a reference to the View (modeled as the interface ICalculatorView), because once it’s determined that the View status has changed, it invokes the function UpdateDisplay. In the MFC sample, the View is CCalcDlg itself because that’s the class that deals directly with MFC.

CCalcDlg creates its Presentation Model in its constructor:

CCalcDlg::CCalcDlg(CWnd* pParent) 
  : CDialog(CCalcDlg::IDD, pParent)
{
  presentationModel_ = 
    unique_ptr<CalculatorPresentationModel>(
    new CalculatorPresentationModel(this));
  ...
}

As you can see, I leveraged a C++11 smart pointer here called unique_ptr (see bit.ly/KswVGy for more information). Smart pointers have the ability to release the object they reference when it’s no longer required. I used the smart pointer here to ensure that the Presentation Model is destroyed when the View lifecycle ends. The View keeps capturing window events, delegating to the Presentation Model with or without massaging the input, as shown in Figure 6.

 

Figure 6 Some View Functions Showing Delegation

// The parameter nID contains the ASCII code of a digit
void CCalcDlg::OnClickedNumber(UINT nID) {
  ASSERT(nID >= IDB_0 && nID <= IDB_9);
  presentationModel_->ClickedNumber(nID - IDB_0);
}
 
// Unchanged delegation
void CCalcDlg::OnClickedClear() {
  presentationModel_->ClickedClear();
}
 
enum Operator { OpNone, OpAdd, OpSubtract, OpMultiply, OpDivide };
 
// The Presentation Model contains a single method for all binary operations
void CCalcDlg::OnClickedDivide() {
  presentationModel_->ClickedOperator(OpDivide);
}
 
void CalculatorPresentationModel::ClickedOperator(Operator oper) {
  // PerformOperation is now in the PresentationModel;
  // it was in CCalcDlg (now being "the View")
  PerformOperation();
  m_operator = oper;
}
 
void CalculatorPresentationModel::PerformOperation() {
  if (m_errorState != ErrNone)
    return;
 
  if (m_bOperandAvail) {
    if (m_operator == OpNone)
      m_accum = m_operand;
    else if (m_operator == OpMultiply)
      m_accum *= m_operand;
  ... // Same as in Figure 4
 
  m_bOperandAvail = false;
  // This is an inline function defined just below
  UpdateDisplay();
}
 
// The UI refresh is deferred back to the actual View
inline void CalculatorPresentationModel::UpdateDisplay() {
  if (view_)
    view_->UpdateDisplay();
}

You’ll find this reworked version of the MFC sample in the folder mfccalc in the downloadable companion sample. You might notice there’s no Model. In this example, the domain logic would’ve been a class containing functions for the four fundamental arithmetic operations, something like what’s shown in Figure 7.

Figure 7 A Pure Implementation That Includes a Calculator “Model”

// Namespace Calculator::Model
class CalculatorModel {
public:
  long Add(const long op1, const long op2) const {
    return op1+op2;
  }
 
  long Subtract(const long op1, const long op2) const {
    return op1-op2;
  }
 
  long Multiply(const long op1, const long op2) const {
    return op1*op2;
  }
 
  long Divide(const long op1, const long op2) const {
    if (operand2)
      return operand1/operand2;
    else
      throw std::invalid_argument("Divisor can't be zero.");  }
};
 
// Namespace Calculator::View
class CalculatorPresentationModel {
public:
  ...
  void PerformOperation();
  ...
private:
  // The Presentation Model contains a reference to a Model
  unique_ptr<Model::CalculatorModel> model_;
  ...
}
 
void CalculatorPresentationModel::PerformOperation()
{
  if (m_errorState != ErrNone)
    return;
 
  // Same like before, but this time the PresentationModel asks
  // the model to execute domain activities instead of doing it itself
  if (m_bOperandAvail) {
    if (m_operator == OpNone)
      m_accum = m_operand;
    else if (m_operator == OpMultiply)
      m_accum = model_->Multiply(m_accum, m_operand);
    else if (m_operator == OpDivide) {
      if (m_operand == 0)
        m_errorState = ErrDivideByZero;
      else
        m_accum = model_->Divide(m_accum, m_operand);
    }
    else if (m_operator == OpAdd)
      m_accum = model_->Add(m_accum, m_operand);
    else if (m_operator == OpSubtract)
      m_accum = model_->Subtract(m_accum, m_operand);
  }
 
  m_bOperandAvail = false;
  UpdateDisplay();
}

I decided to skip the Model in this small scenario, leaving its logic inside the Presentation Model. This will not be typical in most cases, and the Model logic will have to be implemented in its own class or set of classes. If you like, you can refactor the sample toward a purist approach as an exercise. If you do, you must pay special attention when implementing the function CalculatorModel::Divide because the Model is a reusable component that might be called by an automated process instead of some user interaction. In that case, it wouldn’t matter that a division by zero throws an exception; at that point it would be an unexpected situation. But you don’t have to remove the non-zero divisor-checking from the Presentation Model. Preventing erroneous data from forwarding to inner layers is always healthy. The exception thrown by the Model is a last-resort measure when nothing else is available.

Go ahead and run the refactored solution mfccalc in the companion code, and notice that it still behaves as before, which is just what I wanted: to set up the code for a port without losing functionality. A serious refactoring process must consider a set of automated tests to confirm that the application behavior wasn’t affected as a consequence. Native unit testing is available in Visual Studio 2012 and all its developer editions, including the free Express for Windows 8 (which doesn’t come with MFC or other frameworks for desktop development, though). 

Take a look at the solution Calculator\CalculatorTests in the companion code. The namespace Calculator::Testing contains a class PresentationModelTest whose methods test those of CalculatorPresentationModel, as shown in Figure 8.

Figure 8 Isolating Errors with Native Unit Testing

// Namespace Calculator::Testing
TEST_CLASS(PresentationModelTest) {
private:
  CalculatorPresentationModel presentationModel_;
public:
  TEST_METHOD_INITIALIZE(TestInit) {
    presentationModel_.ClickedClear();
  }
 
  TEST_METHOD(TestDivide) {
    // 784 / 324 = 2 (integer division)
    presentationModel_.ClickedNumber(7);
    presentationModel_.ClickedNumber(8);
    presentationModel_.ClickedNumber(4);
 
    presentationModel_.ClickedOperator(OpDivide);
 
    presentationModel_.ClickedNumber(3);
    presentationModel_.ClickedNumber(2);
    presentationModel_.ClickedNumber(4);
 
    presentationModel_.ClickedOperator(OpNone);
 
    Assert::AreEqual<long>(2, presentationModel_.GetAccum(),
      L"Divide operation leads to wrong result.");
    Assert::AreEqual<CalcError>(ErrNone, 
      presentationModel_.GetErrorState(),
      L"Divide operation ends with wrong error state.");
  }
 
  TEST_METHOD(TestDivideByZero) {
    // 784 / 0 => ErrDivideByZero
    presentationModel_.ClickedNumber(7);
    presentationModel_.ClickedNumber(8);
    presentationModel_.ClickedNumber(4);
 
    presentationModel_.ClickedOperator(OpDivide);
 
    presentationModel_.ClickedNumber(0);
 
    presentationModel_.ClickedOperator(OpNone);
 
    Assert::AreEqual<CalcError>(ErrDivideByZero, 
      presentationModel_.GetErrorState(),
      L"Divide by zero doesn't end with error state.");
  }
 
  ... // More tests for the remaining calculator operations
};

By the way, unit testing is one of the most appreciated consequences of this Presentation Model pattern: The UI behavioral test automation is the same for the domain logic that, in this sample, I embedded in the Presentation Model. Thus, you can open new channels to your application (for example, Cocoa, Qt, wxWidgets or even non-native ones such as HTML5 or Windows Presentation Foundation) with the certainty that errors, if any, are happening in the new user-interaction components rather than the existing ones. You can leverage the code coverage feature to make sure that all lines of code are tested at least once.

Opening a XAML Façade to the Calculator Application

With the code refactored, I’m ready to create a new Windows UI for the MFC calculator. It’s simply a matter of creating a new View for the Presentation Model pattern described earlier.

Windows 8 offers three technologies: XAML, HTML and DirectX.

  • XAML is the XML-based markup language that lets you declare visual UI elements, data to bind to UI controls and handlers to call in response to events. These events are typically defined in so-called codebehind components that can be created in an extended C++ syntax known as C++ Component Extensions for the Windows Runtime (C++/CX), or created in other programming languages. I’ll present a XAML-based calculator face.
  • HTML lets you set which UI behaviors defined in Java­Script run in the Internet Explorer “Chakra” engine. It’s possible—as I’ll demonstrate in the next section—to invoke C++-based components from the JavaScript code.
  • DirectX is ideal for multimedia-intensive apps. Because the calculator isn’t a multimedia app, I won’t discuss this here. DirectX apps can use XAML through interop, which you can read more about at bit.ly/NeUhO4.

To create a XAML view, I chose the basic Blank App from the list of Visual C++ Windows 8 templates and created a project called XamlCalc.

This blank template contains just an empty MainPage.xaml, which I’ll fill with controls to make the Windows 8 counterpart of the former CCalcDlg control in the MFC version. This is all that’s necessary to port the calculator application because it consists of a single window only, with no navigation. When porting your application, you might consider the other templates so you can offer a page-navigation mechanism that provides an intuitive and predictable UX. You’ll find guidance about this on the “Designing UX for Apps” page (bit.ly/Izbxky).

The blank template also comes with an App.xaml file, similar in purpose to the class CCalcApp in the MFC version (see Figure 2). It’s a bootstrap loader that initializes the rest of the components and passes control over to them. The function CCalcApp::InitInstance creates a CCalcDlg window, which then serves as a UI. (You’ll find all of these in the XamlCalc solution in the downloadable companion code.) In the XAML case, App::OnLaunched is generated by default in the codebehind source file, App.xaml.cpp, and triggers an initial navigation to MainPage:

void App::OnLaunched(
  Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^ pArgs) {
  ...
  // Create a Frame to act navigation context and navigate to the first page
  auto rootFrame = ref new Frame();
  if (!rootFrame->Navigate(TypeName(MainPage::typeid))) {
    throw ref new FailureException("Failed to create initial page");
  }
  ...
}

I use the Visual Studio built-in XAML editor to create an immersive calculator page by dragging controls from the toolbox and completing some manual editing, such as user-defined styles, data binding, associated events and so forth. The resulting XAML looks like the code in Figure 9. The calculator is shown in Figure 10.

Figure 9 A XAML Version of the MFC Calculator

<Page
  Loaded="Page_Loaded"
  x:Class="XamlCalc.MainPage" ...>
 
  <Grid Background="Maroon">
    ...
    <Border Grid.Row="1" Background="White" Margin="20,0">
      <TextBlock x:Name="display_" TextAlignment="Right" FontSize="90"
        Margin="0,0,20,0" Foreground="Maroon" HorizontalAlignment="Right"
        VerticalAlignment="Center"/>
    </Border>
    <Grid Grid.Row="2">
      ...
      <Button Grid.Column="0" Style="{StaticResource Number}"
        Click="Number_Click">7</Button>
      <Button Grid.Column="1" Style="{StaticResource Number}"
        Click="Number_Click">8</Button>
      <Button Grid.Column="2" Style="{StaticResource Number}"
        Click="Number_Click">9</Button>
      <Button Grid.Column="3" Style="{StaticResource Operator}"
        Click="Plus_Click">+</Button>
    </Grid>
    ...
    <Grid Grid.Row="5">
      ...
      <Button Grid.Column="0" Style="{StaticResource Number}"
        Click="Number_Click">0</Button>
      <Button Grid.Column="1" Style="{StaticResource Operator}"
        Click="Clear_Click">C</Button>
      <Button x:Name="button_equal_" Grid.Column="2"
        Style="{StaticResource Operator}" Click="Equal_Click"
        KeyUp="Key_Press">=</Button>
      <Button Grid.Column="3" Style="{StaticResource Operator}"
        Click="Divide_Click">/</Button>
    </Grid>
  </Grid>
</Page>

The Look and Feel of the XAML Calculator
Figure 10 The Look and Feel of the XAML Calculator

I defined the style of the buttons (for both numbers and operators) in App.xaml, so I don’t need to reiterate colors, alignments, fonts and other properties for each button. Similarly, I associated event handlers to the Click property of each button; the handlers are MainPage methods defined in the codebehind source file MainPage.xaml.cpp. Here are a couple of examples, one for clicked numbers and one for the divide operation:

void MainPage::Number_Click(Platform::Object^ sender,
  Windows::UI::Xaml::RoutedEventArgs^ e)
{
  Button^ b = safe_cast<Button^>(sender);
  long nID = (safe_cast<String^>(b->Content)->Data())[0] - L'0';
  presentationModel_->ClickedNumber(nID);
}
 
void MainPage::Divide_Click(Platform::Object^ sender,
  Windows::UI::Xaml::RoutedEventArgs^ e)
{
  presentationModel_->ClickedOperator(OpDivide);
}

As you can see, these C++/CX methods in MainPage just take event information and give it to an instance of my standard C++ class, CalculatorPresentationModel, to perform the actual UI activity. This demonstrates that it’s possible to take standard C++ logic from existing native applications and reuse it in a brand-new C++/CX Windows Store application. This reusability lowers the cost of maintaining both versions, as they can both leverage any update inside the common components—the CalculatorPresentationModel in this case.

Implementation-specific components can be called back by the common components as long as they implement well-defined abstract interfaces. In my example, for instance, Calculator­PresentationModel::UpdateDisplay delegates the actual job into an instance of ICalculatorView:

inline void CalculatorPresentationModel::UpdateDisplay(void) {
  if (view_)
    view_->UpdateDisplay();
}

In the MFC version, ICalculatorView is implemented by the MFC-based CCalcDlg class. Take a look at the refactored sequence diagram in Figure 11 and compare it with the original in Figure 3.

The Sequence Diagram for the Equal Sign Button in the Decoupled MFC Version
Figure 11 The Sequence Diagram for the Equal Sign Button in the Decoupled MFC Version

To keep the XAML version analogous to the MFC case, I should’ve implemented ICalculatorView in MainPage. Instead, I had to implement ICalculatorView as a different class because MainPage is a C++/CX class and, therefore, can’t derive from a standard C++ class. C++ and its projection into the Windows Runtime (C++/CX) have different type systems—which interoperate nicely in any case. Implementing a pure C++ ICalculatorView interface wasn’t a big deal:

namespace XamlCalc {
  class CalcView : public ICalculatorView {
  public:
    CalcView() {}
    CalcView(MainPage^ page) : page_(page) {}
    inline void UpdateDisplay()
      { page_->UpdateDisplay(); }
  private:
    MainPage^ page_;
  };
}

Standard C++ and C++/CX classes can’t derive from each other, but they can still hold references to each other—in this case the private member page_, which is a reference to a C++/CX MainPage. To update the display control in the XAML version, I just change the Text property of the MainPage.xaml TextBlock control called display_:

void MainPage::UpdateDisplay() {
  display_->Text = (presentationModel_->GetErrorState() != ErrNone) ?
    L"ERROR!" :
    safe_cast<int64_t>(presentationModel_->GetValue()).ToString();
}

Figure 12 shows the XAML calculator class diagram.

The XAML-C++/CX Calculator Application Class Diagram
Figure 12 The XAML-C++/CX Calculator Application Class Diagram

Figure 13 shows the sequence corresponding to the action of pressing the equal sign button in the XAML version.

The Sequence Diagram for the Equal Sign Button in the XAML version.
Figure 13 The Sequence Diagram for the Equal Sign Button in the XAML version

I should mention that the WRL heavily promotes asynchronous processing through all of its APIs for event handling. My code is 100 percent synchronous, though. I could’ve made it asynchronous by using the task-based Parallel Patterns Library, which implements tasks and continuations based on Windows 8 asynchrony concepts. This wasn’t justified in my small example, but it’s worth reading more about it at the “Asynchronous Programming in C++” page in the Windows Developer Center (bit.ly/Mi84D1).

Press F5 and run the application to see the XAML version in action. When migrating or creating your Windows Store applications, it’s important that you design your application UI based on the new Windows Experience design patterns, described on the Microsoft Dev Center (bit.ly/Oxo3S9). Follow the recommended patterns for commanding, touch, flipped orientation, charms and more in order to keep your application UX-intuitive for first-time users.

Another Example: A New Windows UI HTML Calculator

The XAML example is enough to get the initial MFC-based calculator sample running side by side with Windows 8. However, under certain circumstances (such as the expertise of your team or to leverage existing assets), you might consider HTML and JavaScript instead of XAML for the UI.

The Presentation Model design pattern described in this article is still useful, even if your UI contains logic in a non-C++ language like JavaScript. This miracle is possible because, in the Windows 8 environment, JavaScript projects to the Windows Runtime much as C++ does, making it possible for both to interoperate as they both share the type system established by the WRL.

In the companion code, you’ll find a solution called HtmlCalc that contains a default.html page similar to MainPage.xaml. Figure 14 shows a UI description comparable to the XAML version showed in Figure 9.

Figure 14 The HTML Markup for the Calculator UI

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>HTMLCalc</title>
    <!-- WinJS references -->
    <link href="//Microsoft.WinJS.0.6/css/ui-dark.css" rel="stylesheet">
    <script src="//Microsoft.WinJS.0.6/js/base.js"></script>
    <script src="//Microsoft.WinJS.0.6/js/ui.js"></script>
    <!-- HTMLCalc references -->
    <link href="/css/default.css" rel="stylesheet">
    <script src="/js/default.js"></script>
  </head>
  <body onkeypress="Key_Press()">
    <table border="0">
      <tr>
        <td class="Display" colspan="7" id="display_">0 </td>
      </tr>
      <tr>
        <td>
          <button class="Number" onclick="Number_Click(7)">7</button>
        </td>
        <td>
          <button class="Number" onclick="Number_Click(8)">8</button>
        </td>
        <td>
          <button class="Number" onclick="Number_Click(9)">9</button>
        </td>
        <td>
          <button class="Operator" onclick="Plus_Click()">+</button>
        </td>
      </tr>
      ...
      <tr>
        <td>
          <button class="Number" onclick="Number_Click(0)">0</button>
        </td>
        <td>
          <button class="Operator" onclick="Clear_Click()">C</button>
        </td>
        <td>
          <button class="Operator" onclick="Equal_Click()">=</button>
        </td>
        <td>
          <button class="Operator" onclick="Divide_Click()">/</button>
        </td>
      </tr>
    </table>
  </body>
</html>

The codebehind role in HTML pages is played by JavaScript code. Indeed, you’ll find such code in the file js\default.js. My Calculator­PresentationModel, because it’s a standard C++ class, can’t be invoked directly from the JavaScript portion, but you can do it indirectly via a bridging C++/CX component—Calculator::View::CalcView.

Instancing this component from JavaScript is as easy as declaring the following in default.js:

// This is JavaScript code, instancing a C++/CX proxy to my PresentationModel
var nativeBridge = new Calculator.View.CalcView();

As an example of this approach, pressing the equal sign button triggers a call to the following JavaScript function:

function Equal_Click() {
    display_.textContent = nativeBridge.equal_click();
}

This propagates the call to CalcView::equal_click, which “talks” natively with my standard C++ CalculatorPresentationModel:

String^ CalcView::equal_click() {
  presentationModel_->ClickedOperator(OpNone);
  return get_display();
}
 
String^ CalcView::get_display() {
  return (presentationModel_->GetErrorState() != ErrNone) ?
    L"ERROR!" :
    safe_cast<int64_t>(presentationModel_->GetValue()).ToString();
}

In this particular scenario, the C++/CX component CalcView just forwards every request to the standard C++ PresentationModel (see the sequence diagram in Figure 15). We can’t avoid it on our way to the reusable C++ component, though (see Figure 15).

The Sequence Diagram for the Equal Sign Button in the Hybrid HTML-C++ Version
Figure 15 The Sequence Diagram for the Equal Sign Button in the Hybrid HTML-C++ Version

Because the C++/CX proxy must be created manually, the associated cost shouldn’t be ignored. Still, you can balance it against the benefit of reusing components, as I do in my scenario with CalculatorPresentationModel.

Go ahead and press F5 to see the HTML version in action. I’ve shown how to reuse existing C++ code to expand its reach to the novel framework in Windows 8, without dropping the original channels (MFC in my case). We’re now ready for some final reflections.

Hello (Real) World!!

My porting scenario is a particular case, which may not be your particular case, which may not be someone else’s particular case. Much of what I showed here is applicable to the MFC Calculator scenario, and I might make different decisions if I were porting a different application to the WRL. Consequently, here are some general conclusions about porting applications:

  • Standard plain objects—those that have no specific relation with third-party APIs—have maximum reusability and, therefore, no- or low-cost portability. In contrast, reusability is constrained when objects have explicit ties to non-standard APIs, such as MFC, Qt and the WRL. For example, MFC is available only on the Windows desktop. Qt, on the other hand, is present in other environments, though not in all. In such cases, avoid mixtures that erode reusability by making application objects “talk” to abstract classes. Then derive from these classes to create third-party-aware implementations. Look at what I did with ICalculatorView (the abstract class) and its implementations CCalcDlg and XamlCalc::CalcView. For Windows 8 development, get familiar with the WRL APIs and which Win32 APIs they’re replacing. You’ll find more information at bit.ly/IBKphR.
  • I applied the Presentation Model pattern because my goal was to mimic in the Windows Runtime what I already had on the desktop. You might decide to cut features if they don’t make much sense—such as applying styles to text in a mobile e-mail app. Or you might add features that leverage your new target platform—think, for instance, about image stretching via multi-touch in an image-viewer application. In such cases, another design pattern might be more suitable.
  • The Presentation Model I used is great for maintaining business continuity and for low maintenance costs. This lets me deliver Windows Store versions of the app without cutting ties with customers who prefer the original MFC option. Maintaining two channels (XAML and MFC or HTML and MFC) isn’t twice the cost as long as I have reusable components like CalculatorPresentationModel.
  • The overall reusability of an application is determined by the ratio of code lines that are common to all versions versus code lines for maintaining specific versions (components maintained by third parties aren’t considered). There are cases where applications rely heavily on non-standard APIs (such as an augmented-reality app that leverages OpenGL and iOS sensors). The reusability ratio can be so low that you might eventually decide to port the application without component reusability other than the conceptual one.
  • Don’t start asking who could have so poorly architected the existing application, making your porting job so difficult. Start refactoring it instead. Keep in mind that Agile methodologies aren’t aimed at mature, robust, highly reusable architectures; what they emphasize is software delivery. Making software generic and extensible for future reusability and portability requires a lot of experience, as it’s not easy to make design decisions in the dark.
  • You might be porting your application to Windows 8, iOS or Android with the intention to sell it through the marketplaces of these platforms. In that case, keep in mind that your application must pass a certification process before being accepted (bit.ly/L0sY9i). This could force you to support UI behaviors you never contemplated in your original version (such as touch-first, charms and so forth). Failing to meet certain standards could result in your application being rejected. Don’t overlook such “regulatory compliance” when estimating costs.

Meeting the Challenge

The new Windows Runtime and the still-ubiquitous Windows desktop pose a challenge to developers who don’t want to pay the extra cost of maintaining a separate application per platform. Throughout this article, I demonstrated that existing codebases can be leveraged not only to enable new channels but also to improve through refactoring the quality of existing codebases.


Diego Dagum is a software architect and trainer with more than 20 years of experience in the industry. He can be reached at email@diegodagum.com.

Thanks to the following technical experts for reviewing this article:Marius Bancila, Angel Jesus Hernandez and the Windows 8 team