Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Under the hood Part 4 : C++ WinRT Component DLL & C++ XAML application – WinRT, Windows 8, C++, Metro

0.00/5 (No votes)
5 Mar 2012 1  
Calling WinRT Component from C++ We have developed a C++ WinRT Component DLL & C#.NET application in the post here Under the hood Part 1 : C++ WinRT Component DLL & C#.NET Metro application we have seen the compiler generated components for making the C# application access the C++ WinRT component he

Calling WinRT Component from C++

We have developed a C++ WinRT Component DLL & C#.NET application in the post here Under the hood Part 1 : C++ WinRT Component DLL & C#.NET Metro application

we have seen the compiler generated components for making the C# application access the C++ WinRT component here Under the hood Part 2 : C++ WinRT Component DLL & C#.NET Metro application

We have seen the packaging and installation process that happens in the background during building and deploying of the applications here Under the hood Part 3 : WinRT, Windows 8, C++, C#.NET, Metro, WinRT Component DLL

Going further, I created a C++ Metro application and accessed the C++ WinRT Component DLL from this application. The interesting part here is that C++ applications is XAML based. No more .RC and resource.h files in C++ (for metro). In the previous post, we created a WinRT C++ DLL that contains a class calculatorSample. Now let us create a C++ application to consume the C++ WinRT DLL.

To get started with creating a C++ XAML application, go to Visual Studio 2011 –> Solution Explorer–> New Project –> Go to Installed Templates section –> Visual C++ –>Select Application and name it as CPPApplication1 as shown in the following fig 1.

image

Fig 1: Creating a C++ XAML application.

Right click on the project, click on Add References and the following dialog shown in figure 2 comes up.

image

Fig 2: Reference manager dialog to add references to another components.

Click on Solution section –> Projects and Select CppWinRTComponentDLL –> click on Add button and click on Close as shown in figure 3.

image

Fig 3: Selecting WinRT CppWinRTComponentDLL.

The CppWinRTComponentDLL reference appears in the References section as shown in the following figure 4.

image

Fig 4: CppWinRTComponentDLL dll appears in the References section.

Goto MainPage.xaml.cpp and include the namespace for CppWinRTComponentDLL

using namespace CppWinRTComponentDll;

Then create an object of calculatorSample on the heap using ref new. In this scenario, ref new is like cocreateinstance of COM. It’s a smart allocator. we also use ref class to indicate the authoring of a Windows Runtime class . using ^ to represent a "refcounted" pointer in ZW fits quite well

The following code shows how to use the ref new expression to create a new reference-counted Windows Runtime object. Note that you use the ^ ("hat") symbol instead of the pointer dereference operator (*) when declaring the variable, but that you use the familiar -> operator to access the objects instance members. Note also that you do not call delete explicitly on the object. The object will be destroyed deterministically when the last remaining copy of it goes out of scope. At the lowest level, the object is basically a COM object owned by a smart pointer.

CalculatorSample^ calcobj = ref new  CalculatorSample();
 txtAddResult->Text = calcobj->Add(10,20).ToString();

So from the C++ application, we are calling the C++ Windows Runtime Component DLL. This is all native code. C++ calling C++ and everything is ref counted.

Compiler options: /ZW enable WinRT language extensions /AI<dir> add to assembly search path <dir> is the folder where the compiler searches the winmd files /FU<file> forced using assembly/module force the inclusion of the specified winmd file /D "WINAPI_FAMILY=2" set this define to compile against the ModernSDK subset of Win32

Linker options: /APPCONTAINER[:NO] marks the executable as runnable in the appcontainer (only) /WINMD[:{NO|ONLY}] emits a winmd; if "ONLY" is specified, does not emit the executable, but just the winmd /WINMDFILE:filename name of the winmd file to emit /WINMDDELAYSIGN[:NO] /WINMDKEYCONTAINER:name /WINMDKEYFILE:filename used to sign the winmd file

However, in a Metro style app or Windows Runtime component, all the C++ code is native. The /ZW compiler option causes the Component Extensions to be compiled for Windows Runtime. The /cli compiler option causes them to be compiled for C++/CLI. Currently, C++/CLI is not supported for Metro style apps

Code snippet of the complete MainPage class.

//
 // MainPage.xaml.cpp
 // Implementation of the MainPage.xaml class.
 //

 #include "pch.h"
 #include "MainPage.xaml.h"
 using namespace Windows::UI::Xaml;
 using namespace Windows::UI::Xaml::Controls;
 using namespace Windows::UI::Xaml::Data;
 using namespace CPPApplication1;
 using namespace CppWinRTComponentDll;
 MainPage::MainPage()
 {
     InitializeComponent();
				      CalculatorSample^ calcobj = ref newCalculatorSample();
     txtAddResult->Text = calcobj->Add(10,20).ToString();    int result;
     HRESULT hr = calcobj->__cli_Add(20,30,&result);
     txtAddResult->Text = result.ToString();
 } MainPage::~MainPage()
 {
 }

All Windows Runtime types derive from the universal base class Platform::Object. There is therefore an implicit conversion from any Windows Runtime object to Platform::Object.

Code snippet of the XAML page.

<UserControl x:Class="CPPApplication1.MainPage"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

    mc:Ignorable="d"

     d:DesignHeight="768" d:DesignWidth="1366">

    <Grid x:Name="LayoutRoot" Background="#FF0C0C0C">

        <TextBox x:Name="txtAddResult" HorizontalAlignment="Left" Text="TextBox" VerticalAlignment="Top" Margin="343,90,0,0" Width="212"/>

        <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="Calling C++ component Add method from C++ XAML Application" VerticalAlignment="Top" Margin="81,90,0,0" Height="45" Width="258" FontSize="14" FontWeight="Bold"/>    </Grid>

</UserControl>

Build the solution and deploy the application. The application output is as follows.image

Configuration settings

Enable Windows Runtime Extensions enables the runtime extensions throughout the type system which includes the ability to do Boxing. I.e. Boxing to WinRT type system. Every fundamental types and WinRT types are derived from Platform.Object.image

heap-allocated objects with heap semantics

Calculator^ calc = ref new Calculator(); // Calculator is a ref class from a custom WinRT component

txtResult->Text = calc->Add(10, 20).ToString();

The ^syntax will fire a destructor when the refcount on the object drops to 0, or if you explicitly call delete. (So if you handed the object out it’s not necessarily at the end of your scope)

heap-allocated objects with Stack semantics

Calculator calc;

txtResult->Text = calc.Add(10, 20).ToString();

Both of those create heap-allocated objects behind the scenes, but the difference is whether you logically have heap semantics vs. stack semantics.

The stack syntax will fire a destructor when the object goes out of scope (or on an exception etc.). This is important when you e.g. handed of the object to another thread or async callback, so there may still be a refcount on it, but you need to get rid of it right away. (E.g. a file handle that needs to be closed otherwise the file is locked). The main advantage is exception-safe deterministic destruction.

PS: Because of the nature of refcounting, it’s a little bit less important with WinRT to have deterministic destruction than with e.g. the /clr and a garbage collected heap (where the point of destruction is virtually random). However, you will find that with async patterns it is common to get into a situation where you’re transfer the ownership of an object from one thread to another (e.g. via a lambda). There is then a race condition between the two threads for releasing the object. This is generally still ok, but if the object represents a file or other exclusive resource it might be critical to perform the destruction at a specific time, rather than relying on the timing between the two threads.

value classes & Ref classes

Int32 x(15); // Compiles and x is initialized and works as expected.

String str("test1"); // Doesn’t compile and compiler complains C3149: ‘Platform::String’ : cannot use this type here without a top-level ‘^’

Int32 is a value class, and String or the custom winRT component are all ref class. They are different.

Differences between C++/CLI and WinRT C++

In terms of the differences like flags are as follows.

Basic types:
/clr: From mscorlib.dll (System::* types)
/ZW: From vccorlib.dll (Platform::* types)

Lifetime management: /clr: Garbage collected
/ZW: Refcounted

Cycles Broken:
/clr: By garbage collector
/ZW: Broken by user (weak references or explicit delete)

Code generation:
/clr: MSIL + native code. Can create a cross-platform binary if MSIL-only.
/ZW: Native code only. Binaries target a specific platform.

Object Creation:
/clr: gcnew
/ZW: ref new

interior_ptr:
/clr: Supported
/ZW: Not supported

pin_ptr:
/clr: Supported
/ZW: Not supported

V% (% when it refers to a byref (kind’a like an "interior_ref") ):
/clr: Supported
/ZW: Not supported

R% (% when it refers to an implicitly dereferenced ref type):
/clr: Supported
/ZW: Supported

Ref to ^:
/clr: R^%
/ZW: R^&

Boxing:
/clr: syntax V^
/ZW: IReference<V>^

Dereferenced box type:
/clr: V%
/ZW: const V

Generics:
/clr: Generics classes, interfaces & delegates allowed.
/ZW: Generic interfaces & delegates only.

Static constructors:
/clr: Supported
/ZW: Not supported

Address of member of ref class:
/clr: Returns an interior_ptr
/ZW: Returns a type*

friends:
/clr: Not supported
/ZW: Supported

C++ class embedded in ref class:
/clr: Not supported
/ZW: Supported

ref class embedded in C++ class: /clr: Not supported
/ZW: Supported (R-on-stack)

embedded in C++ class:
/clr: Not supported (Needs GCHandle)
/ZW: Supported

^ embedded in value class with value class on native heap:
/clr: Not supported
/ZW: Supported (for String^)

Global ^: /clr: Not supported
/ZW: Supported

Global R-on-stack: /clr: Not supported
/ZW: Supported

Finalizer:
/clr: Supported
/ZW: Not supported

Destructor:
/ZW: Runs on IDisposable::Dispose (delete / stack unwind) only
/clr: Runs on IDisposable::Dispose (delete / stack unwind) -or- last release (never both)

T::typeid: /clr: Supported
/ZW: Not supported

R-on-stack (ref class on stack) syntax is supported on C++/cli and C++/CX, but you’ll notice that unfortunately the /CX implementation in the developer preview release has a code generation bug that will make it impractical to test this right now. (R^ and R% should be fine though). The most important reason for R-on-stack is exception-safe destruction (Like ‘using’ gives you in C#) – other than that it is purely compiler syntactic sugar.

"If one advances confidently in the direction of his dreams, and endeavors to live the life which he has imagined, he will meet with success unexpected in common hours." — Henry David Thoreau

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here