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.