introduction to writing metro style apps in native c++ marc grégoire software architect...
TRANSCRIPT
Introduction to Writing Metro Style Apps in Native C++
Marc GrégoireSoftware [email protected] 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
Windows Core OS Services
JavaScript(Chakra)
C#VB
Metro style Apps
Communication & Data
Application Model
Devices & Printing
WinRT APIs
Graphics & Media
XAML HTML / CSS
HTMLJavaScrip
t
CC++
C#VB
Desktop Apps
Win32
.NET / SL
Internet Explorer
CC++
Syste
m S
erv
ices
Vie w
Mod
el
Con
troll
er
Core
CC++
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
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
2. Allocation ref new Reference-counted allocation
3. Pointer & Reference
^ Strong pointer (“hat” or “handle”)
% Strong reference
C++ Extensions (C++/CX)
ModuleInternals
written in C++
WinRT External Surface
for WinRT callers/callees
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(); // ref count = 1 p2->Name = "John"; // ref count = 1 p = p2; // ref count = 2} // ref count = 1p = nullptr; // ref count = 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)
Example:public ref class Person{ public: Person(String^ name, String^ email); void Greet(Person^ other);
internal: ~Person(); void SetPassword(const std::wstring& passwd);};
Public/protected methods only WinRT parameters
Private/internal methods any C++ types as parameters
Usage:Person^ p = ref new Person("John");p->Greet(ref new Person("Jim"));
WinRT Interface
Definingpublic interface class IShape{ void Draw();};
Inheritingpublic interface class ISelectableShape : IShape{ void Select();};
Implementingref class Rectangle : ISelectableShape{ public: virtual void Draw(); virtual void Select();};
UsingIShape^ shape = ref new Rectangle();shape->Draw();
WinRT Property
Defining Trivial properties (with private backing store)
public: property String^ Name;
User defined propertiespublic: property Person^ Sibling {
Person^ get() { InitSiblings(); return _sibling; }
void set(Person^ value) { _sibling = value; NotifySibling(); }
}
private: Person^ _sibling;
UsingPerson^ 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-functionauto p = ref new PropertyChanged(UIPropertyChanged);
From class-memberauto p = ref new PropertyChanged(this, MainPage::OnPropertyChanged);
Invokingp("Visible", "f");
WinRT Event Defining
Trivial event (with private backing store)public: event PropertyChanged^ OnPropertyChanged;
User defined propertiespublic: 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);
Unsubscribingperson->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 exceptionstry { … } 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 ownexceptions 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
Defininggeneric<typename T, typename U> public interface class IPair {
property T First;property U Second;
};
Implementingref class PairStringUri: IPair<String^, Uri^> {public:
property String^ First;property Uri^ Second;
};
UsingIPair<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 definitionref 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 elementsitems->Append("Hello");
Returning a read-only view of the vectorIVectorView<String^>^ view = items->GetView();
Getting notification for changesitems->VectorChanged += ref new VectorChangedEventHandler<String^> (this, &MyClass::VectorChanged);
Map and ObservableMap Defining
using namespace Platform::Collections;auto favorites = ref new Map<String^, Uri^>();
Adding elementsfavorites->Insert("MSDN", ref new Uri("http://msdn.com"));
Checking and removing elementsif (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::vectorVector<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.