Presentation: “Introduction to Writing Metro Style Apps in Native C++”

advertisement
Introduction to Writing Metro
Style Apps in Native C++
Marc Grégoire
Software Architect
marc.gregoire@nuonsoft.com
http://www.nuonsoft.com/
http://www.nuonsoft.com/blog/
May 8th 2012
Agenda






Windows 8 Platform
Windows Runtime (WinRT)
C++ Extensions (C++/CX)
Asynchronous programming model
Libraries (WinRT   STL)
XAML
Windows 8 Platform
Model
Controller
View
Metro style Apps
XAML
XAML
C
C++
Desktop Apps
HTML / CSS
C#
VB
JavaScript
(Chakra)
JavaScript
C
C++
C#
VB
Internet
Explorer
Win32
.NET
/ SL
HTML
Core
System Services
WinRT APIs
Communication
& Data
Graphics & Media
Devices & Printing
Application Model
Windows Core OS Services
Windows 8 Platform – Where can C++ be used?

Metro Hybrid Apps
 HTML5
+ Javascript front-end
 C++ components

Metro XAML Apps
 UI
using XAML
 C++ code behind

Metro high performance 2D/3D Apps
 C++
with DirectX rendering
Windows Runtime

Set of language extensions and libraries to allow
direct consumption and authoring of WinRT types
 Strongly-typed
system for Windows Runtime
 Automatically reference counted
 Exception-based
 Deep integration with STL
 Well defined binary contract across module boundaries,
ABI-safe
C++ Extensions (C++/CX)
C++ Extensions (C++/CX)
Key Bindings
Feature
Summary
1. Data Types
ref class
Reference type
value class
Value type
interface class
Interface
property
Property with get/set
event
“Delegate property” with add/remove/raise
delegate
Type-safe function pointer
generic
Type-safe generics
ref new
Reference-counted allocation
2. Allocation
3. Pointer & Reference ^
%
Strong pointer (“hat” or “handle”)
Strong reference
C++ Extensions (C++/CX)
C/C++
External Surface
for native
callers/callees
Automatic Lifetime Management




Handle (^ / Hat) is smart pointer to WinRT objects
Reference counted
Allocated with ref new
Example:
Person^ p;
{
Person^ p2 = ref new Person();
p2->Name = "John";
p = p2;
}
p = nullptr;
//
//
//
//
//
ref
ref
ref
ref
ref
count
count
count
count
count
=
=
=
=
=
1
1
2
1
0  ~Person()
Automatic Lifetime Management


On the stack, or as a member of another WinRT
type
Example:
{
}
Person p;
p.Name = "John";
/* ... */
// ~Person()
WinRT Class


Use ref class to define new WinRT classes (ABI-safe
cross-language classes) Usage:
Person^ p = ref new Person("John");
Example:
p->Greet(ref new Person("Jim"));
public ref class Person
{
public:
Person(String^ name, String^ email);
void Greet(Person^ other);
Public/protected methods  only
WinRT parameters
internal:
~Person();
void SetPassword(const std::wstring& passwd);
};
Private/internal methods
 any C++ types as
parameters
WinRT Interface

Defining

public interface class IShape
{
void Draw();
};

ref class Rectangle : ISelectableShape
{
public:
virtual void Draw();
virtual void Select();
};
Inheriting
public interface
class ISelectableShape : IShape
{
void Select();
};
Implementing

Using
IShape^ shape = ref new Rectangle();
shape->Draw();
WinRT Property

Defining
 Trivial
properties (with private backing store)
public: property String^ Name;
 User
defined properties
public: property Person^ Sibling {
Person^ get() { InitSiblings(); return _sibling; }
void set(Person^ value) { _sibling = value; NotifySibling(); }
}
private: Person^ _sibling;

Using
Person^ p = ref new Person("John");
p->Sibling = ref new Person(p->Name);
WinRT Delegate

Declaring
public delegate void PropertyChanged(String^ propName, String^ propValue);

Instantiating

From lambda:
auto p = ref new PropertyChanged(
[](String^ pn, String^ pv) {
cout << pn << " = " << pv;
});

From free-function
auto p = ref new PropertyChanged(UIPropertyChanged);

From class-member
auto p = ref new PropertyChanged(this, MainPage::OnPropertyChanged);

Invoking
p("Visible", "f");
WinRT Event

Defining

Trivial event (with private backing store)
public: event PropertyChanged^ OnPropertyChanged;

User defined properties
public: event PropertyChanged^ OnNetworkChanged {
EventRegistrationToken add(PropertyChanged^);
void remove(EventRegistrationToken t);
void raise(String^, String^);
}

Using

Subscribing
person->OnPropertyChanged += propertyChangedDelegate;
auto token = person->OnPropertyChanged::add(propertyChangedDelegate);

Unsubscribing
person->OnPropertyChanged -= token;
person->OnPropertyChanged::remove(token);
WinRT Exceptions



Under the covers, WinRT uses COM, thus HRESULTs
WinRT wraps HRESULTs into exceptions
Throwing exceptions
throw ref new InvalidArgumentException();
throw ref new COMException(E_*);

Catching exceptions
try { … } catch (OutOfMemoryException^ ex) { … }

Access HRESULT value via ex->HResult
WinRT Exceptions


Only a fixed set of exceptions available
Catch all WinRT exceptions:
catch (Platform::Exception^) { }

You cannot derive your own
exceptions from Exception
HRESULT
Exception
E_OUTOFMEMORY
OutOfMemoryException
E_INVALIDARG
InvalidArgumentException
E_NOINTERFACE
InvalidCastException
E_POINTER
NullReferenceException
E_NOTIMPL
NotImplementedException
E_ACCESSDENIED
AccessDeniedException
E_FAIL
FailureException
E_BOUNDS
OutOfBoundsException
E_CHANGED_STATE
ChangedStateException
REGDB_E_CLASSNOTREG
ClassNotRegisteredException
E_DISCONNECTED
DisconnectedException
E_ABORT
OperationCanceledException
WinRT Generics

Defining
generic<typename T, typename U>
public interface class IPair {
property T First;
property U Second;
};

Implementing
ref class PairStringUri:
IPair<String^, Uri^> {
public:
property String^ First;
property Uri^ Second;
};
Using

IPair<String^, Uri^>^ uri =
ref new PairStringUri();
auto first = uri->First; // String^
auto second = uri->Second; // Uri^
WinRT .winmd Metadata Files

.winmd files


Contain the metadata representation of WinRT types
To consume a winmd file:


Right click on project in Solution Explorer > References > Add New Reference…
Or
#using <Company.Component.winmd>


Make sure the winmd and implementation dll is packaged together with your
application
To produce a .winmd file:

Start from the “C++ WinRT Component Dll” template

Define public types (ref classes, interfaces, delegates, etc.)
WinRT Partial Runtime Classes

Partial class definition
partial ref class MainPage: UserControl, IComponentConnector
{
public:
void InitializeComponent();
void Connect() {
btn1->Click += ref new EventHandler(this, &MainPage::Button_Click); }
};

Class definition
ref class MainPage
{
public:
MainPage() { InitializeComponent(); }
void Button_Click(Object^ sender, RoutedEventArgs^ e);
};
Async
Async with PPL Tasks




Windows 8 Metro only allows asynchronous operations for
anything that can take longer than a couple milliseconds.
For example: there are no synchronous file operations possible
in Metro.
Advantage: keeps UI fast and fluid
Disadvantage: programming can be more complex, but new
PPL tasks support helps alot here.
Async with PPL Tasks

Example: create a file in the standard “Pictures”
folder, without PPL Tasks:
StorageFolder^ folder = KnownFolders::PicturesLibrary;
auto createStorageFileOp = folder->CreateFileAsync("myfile.txt");
createStorageFileOp->Completed =
ref new AsyncOperationCompletedHandler<StorageFile^>(
[](IAsyncOperation<StorageFile^>^ asyncOp, AsyncStatus status) {
StorageFile^ storageFile = asyncOp->GetResults();
/* Do something with the file. */
}
);
Async with PPL Tasks

with PPL Tasks:
StorageFolder^ folder = KnownFolders::PicturesLibrary;
create_task(folder->CreateFileAsync("myfile.txt")).then(
[](StorageFile^ storageFile) {
/* Do something with the file. */
}
);
Libraries (WinRT   STL)
Vector and ObservableVector

Instantiating
using namespace Platform::Collections;
Vector<String^>^ items = ref new Vector<String^>();

Adding elements
items->Append("Hello");

Returning a read-only view of the vector
IVectorView<String^>^ view = items->GetView();

Getting notification for changes
items->VectorChanged += ref new VectorChangedEventHandler<String^> (this,
&MyClass::VectorChanged);
Map and ObservableMap

Defining
using namespace Platform::Collections;
auto favorites = ref new Map<String^, Uri^>();

Adding elements
favorites->Insert("MSDN", ref new Uri("http://msdn.com"));

Checking and removing elements
if (favorites->HasKey("MSDN"))
favorites->Remove("MSDN");
Integration with STL Algorithms



WinRT String has Begin()/End() member methods.
For WinRT collections, collection.h defines begin() and end()
functions.
Example:
IVector<int>^ v = GetItems();
int sum = 0;
std::for_each(begin(v), end(v),
[&sum](int element) {
sum += element;
});
Integration with STL Containers



Conversion is possible between STL containers and WinRT
containers
String^  std::wstring (via wchar_t*)
Vector  std::vector
std::vector<int> v;
v.push_back(10);
auto items = ref new Vector<int>(v);

Vector  std::vector
Vector<int>^ items = ...;
std::vector<int> v = to_vector(items);
XAML
Windows 8 Platform – Where can C++ be used?

Metro Hybrid Apps
 HTML5
+ Javascript front-end
 C++ components

Metro XAML Apps
 UI
using XAML
 C++ code behind

Metro high performance 2D/3D Apps
 C++
with DirectX rendering
Demo C++ and XAML
Resources

“Using Windows Runtime With C++” – Herb Sutter


http://channel9.msdn.com/Events/BUILD/BUILD2011/TOOL-532T
“Building Windows Metro style apps in C++/XAML”
– Vikas Bhatia, Joanna Mason

http://channel9.msdn.com/Events/BUILD/BUILD2011/TOOL-479T
Questions
?
I would like to thank Herb Sutter from Microsoft
for his permission to base this presentation on one
that he wrote for Build 2011.
Download