Windows Runtime
Repenser le développement d'applications avec Windows Runtime
Jason Olson
Développer des applications Windows et utiliser les nouvelles fonctionnalités Windows proposées par votre langage de programmation préféré n'a pas toujours été une chose simple. Il a fallu investir pour améliorer l'expérience de développement de bout en bout sur Windows, afin que les clients bénéficient de la meilleure expérience possible sur Windows 8 et que les développeurs aient les moyens de créer les meilleures applications sur Windows. Windows Runtime (WinRT) est au cœur de ces investissements.
Windows Runtime fait partie d'un processus qui avait pour but de repenser l'expérience du développeur pour Windows. Il s'agit de la surface API Windows moderne utilisée pour créer de nouvelles applications du Windows Store sur Windows 8. Dès le départ, Windows Runtime est conçu pour prendre en charge sans discrimination plusieurs langages de programmations majeurs (C#/Visual Basic, JavaScript et C++), afin de permettre aux développeurs d'exploiter leurs compétences et ressources existantes, et de fournir une surface API bien pensée, conçue de manière cohérente, et profondément intégrée à la chaîne d'outils de développement.
Windows Runtime permet de choisir le langage
Il existe une grande diversité parmi les développeurs d'applications. Certains utilisent JavaScript/HTML/CSS pour créer des applications Web, d'autres C#/Visual Basic pour créer des applications avec le Microsoft .NET Framework, et d'autres encore sont des développeurs natifs qui utilisent C++ pour développer les leurs. Windows Runtime permet d'écrire des applications du Windows Store dans tous ces langages, afin que l'ensemble de ces développeurs puissent créer d'excellentes applications Windows, comme l'illustre la figure 1.
Figure 1 Windows Runtime permet d'écrire de nouvelles applications du Windows Store dans plusieurs langages
Cela bénéficie aux développeurs comme aux consommateurs. La création d'applications du Windows Store représente un marché très lucratif pour les développeurs. Grâce à la prise en charge de tous les principaux langages Microsoft, un nombre impressionnant de développeurs est désormais capable de créer de formidables applications Windows que les consommateurs voudront acheter et utiliser.
En tant que développeur, vous avez acquis des compétences et de l'expérience dans votre langage de programmation favori. Vous avez également engrangé beaucoup de ressources que vous utilisez dans votre développement d'applications (telles que du code, des infrastructures de build, etc.). Vous ne devriez pas avoir à apprendre un langage de programmation et un ensemble d'outils entièrement nouveaux simplement pour développer des applications du Windows Store sur Windows 8 alors que Microsoft fournit déjà une vaste gamme de langages de programmation et d'outils de développement.
Windows Runtime est naturel et familier
La précédente expérience de développement Windows a été conçue alors que C était le langage de programmation dominant et que le code basé sur l'exception était rare, et qu'un système d'exploitation Windows pouvait être lié par un langage unique. Le monde du développeur d'aujourd'hui a bien changé. Les fonctionnalités de programmations telles que les espaces de noms, les collections, les événements, l'asynchronie, etc. sont plus que banales de nos jours, elles sont attendues.
Examinons l'utilisation d'un des périphériques les plus communs sur Windows de nos jours : la webcam. Voici comment une partie de l'API de la webcam était auparavant déclarée dans Windows :
HWND VFWAPI capCreateCaptureWindow(
LPCTSTR lpszWindowName,
DWORD dwStyle,
int x,
int y,
nit nWidth,
int nHeight,
HWND hWnd,
int nID
);
Les API Windows précédentes étaient principalement déclarées dans un fichier d'en-tête natif (*.h) qui était fourni par le Windows SDK. Le SDK comprenait aussi un fichier .lib auquel du code utilisant l'API était lié. Les API Windows étaient implémentées en C/C++ en tant que fonctions C simples ou composants COM natifs et packagées dans un fichier .dll fourni dans Windows. Ce modèle de programmation était conçu nativement et privilégiait la performance avant tout.
Il n'y avait ni noms d'espaces, ni collections modernes, ni exceptions vraies. Même pour les développeurs natifs classiques, l'expérience de développement n'était pas idéale car il y avait des problèmes avec IntelliSense, avec la consultation de code, aucuns noms d'espaces, et bien d'autres choses.
Cette plateforme entièrement native présentait aussi de véritables problèmes d'utilisation pour les développeurs .NET qui essayaient d'utiliser des API Windows, comme l'illustre la figure 2.
Figure 2 La plateforme précédente, entièrement native, présentait de véritables problèmes d'utilisation
[DllImport("avicap32.dll", EntryPoint = "capCreateCaptureWindow")]
static extern int capCreateCaptureWindow(
string lpszWindowName, int dwStyle,
int X, int Y, int nWidth, int nHeight,
System.IntPtr hwndParent, int nID);
[DllImport("avicap32.dll")]
static extern bool capGetDriverDescription(
int wDriverIndex,
[MarshalAs(UnmanagedType.LPTStr)] ref string lpszName,
int cbName,
[MarshalAs(UnmanagedType.LPTStr)] ref string lpszVer,
int cbVer);
Quelqu'un se devait d'écrire du code supplémentaire pour combler manuellement les lacunes entre votre code et les API Windows traditionnelles. Si personne ne le faisait, vous en étiez réduit à essayer d'écrire ce code compliqué vous-même. Beaucoup de ressources pour les développeurs visent spécifiquement à combler ces lacunes, notamment pinvoke.net, la bibliothèque d'exemples Vista Bridge (code.msdn.microsoft.com/VistaBridge) et le Pack de code d'API Windows pour Microsoft .NET Framework (code.msdn.microsoft.com/WindowsAPICodePack).
À présent, avec Windows 8, vous pouvez utiliser les API Windows dès réception de Windows, de la même manière que vous utilisez d'autres API dans vos applications aujourd'hui (telles que dans le .NET Framework pour les développeurs C#/Visual Basic). Plus personne n'a besoin d'écrire de code supplémentaire pour combler les lacunes entre votre code et les API Windows traditionnelles. Par exemple, l'utilisation de la webcam est beaucoup plus simple aujourd'hui :
using Windows.Media.Capture;
MediaCapture captureMgr = new MediaCapture();
await captureMgr.InitializeAsync();
// Start capture preview; capturePreview
// is a CaptureElement defined in XAML
capturePreview.Source = captureMgr;
await captureMgr.StartPreviewAsync();
Alors, pour les développeurs, en quoi l'utilisation de Windows Runtime est naturelle et familière ? Comme beaucoup d'applications récupèrent des données à partir d'Internet, examinons cette question dans le contexte d'un scénario de réseau courant : la récupération d'un flux RSS. Voici le code C# pour récupérer un tel flux de manière asynchrone :
var feedUri =
new Uri("http://www.devhawk.com/rss.xml");
var client = new Windows.Web.Syndication.SyndicationClient();
var feed = await client.RetrieveFeedAsync(feedUri);
var title = feed.Title.Text;
Voici son équivalent en code Visual Basic :
Dim feedUri = New Uri("http://www.devhawk.com/rss.xml");
Dim client = New Windows.Web.Syndication.SyndicationClient();
Dim feed = Await client.RetrieveFeedAsync(feedUri);
Dim title = feed.Title.Text;
Hormis les noms d'espaces racine (Windows), il n'y a guère de différences dans ce code par rapport au code que vous écrivez déjà dans le .NET Framework. Il y a des noms d'espaces. Des classes et des constructeurs. Des méthodes et des propriétés. Les identificateurs sont en casse Pascal car ils sont dans le .NET Framework et nous utilisons aussi le mot clé await pour la programmation asynchrone : rien de surprenant pour un développeur qui écrit du code à l'aide de C# et de Visual Basic de nos jours.
L'expérience de développement C++ est semblable à celle de C#/Visual Basic, car elle utilise des noms d'espaces, des classes, des constructeurs, des méthodes et des propriétés. Vous pouvez aussi utiliser des types C++ intégrés tels que des chaînes (contrairement aux types de données Win32 précédents). Les opérateurs standard tels que « :: », « -> » et d'autres sont aussi utilisés comme prévu. Pour la programmation asynchrone, nous fournissons une expérience similaire à l'exécution simultanée. Voici le code C++ pour récupérer un flux RSS de manière asynchrone :
auto feedUri = ref new
Windows::Foundation::Uri("http://www.devhawk.com/rss.xml");
auto client = ref new Windows::Web::Syndication::SyndicationClient();
task<SyndicationFeed^>
retrieveTask(client->RetrieveFeedAsync(feedUri));
retrieveTask.then([this] (SyndicationFeed^ feed) {
this->title = feed->Title->Text;
});
Enfin, voici le JavaScript, qui affiche quelques différences intéressantes à code équivalent :
var title;
var feedUri =
new Windows.Foundation.Uri("http://www.devhawk.com/rss.xml");
var client = new Windows.Web.Syndication.SyndicationClient();
client.retrieveFeedAsync(feedUri).done(function (feed) {
title = feed.title.text;
});
Vous remarquerez qu'en JavaScript toutes les méthodes et propriétés sont en casse mixte, car c'est quelque chose de naturel et de familier pour les développeurs JavaScript. Nous utilisons aussi une infrastructure de promesses avec des fonctions anonymes lors de l'écriture de code asynchrone. Nous continuons aussi d'exploiter ici les types intégrés du langage.
L'expérience de développement est aussi familière, avec des outils auxquels les développeurs s'attendent, tels qu'IntelliSense et des outils standard de fonctionnement comme ILDASM et .NET Reflector (voir la figure 3).
Figure 3 IntelliSense Visual Studio pour les API WinRT
Windows Runtime permet cette expérience naturelle et familière en développant et en combinant des concepts fondamentaux de .NET et de .COM pour ajouter une sémantique moderne aux API WinRT, telles que des classes, des constructeurs, des statiques et des événements. Cette sémantique peut être exposée de différentes manières à partir de différents langages, selon ce qui est naturel et familier aux développeurs dans un langage donné.
Cela est rendu possible car toutes les API WinRT comprennent des métadonnées utilisées par les langages de programmation pour connaître la façon dont une API est exposée via Windows Runtime. Les fichiers de métadonnées WinRT utilisent une version mise à jour du format de métadonnées .NET. Ces métadonnées sont à la disposition de n'importe quel développeur car elles sont installées sur chaque ordinateur Windows 8.
En repensant la surface de développement d'API Windows, on n'a pas l'impression d'apprendre ou d'utiliser une nouvelle plateforme. Cela ne semble pas « étranger ». Cela ressemble à du code que l'on a l'habitude d'écrire. Vous mettez à profit vos compétences et ressources existantes lorsque vous créez de nouvelles applications du Windows Store.
Windows Runtime déborde de fonctionnalités
Windows Runtime possède moins d'API que Win32, par conséquent il est facile à apprendre, et pourtant, il fourmille de fonctionnalités. La richesse de Windows Runtime est trop vaste pour être couverte dans un article si court, mais les fonctionnalités standard de Windows et les nouvelles fonctionnalités de Windows 8 auxquelles vous vous attendez sont bel et bien là, comme l'illustre la figure 4.
Figure 4 Windows Runtime inclut les fonctionnalités standard de Windows et les nouvelles fonctionnalités de Windows 8
Et Windows Runtime est conçu de manière cohérente à travers l'utilisation d'un ensemble unique et unifié de directives de conception d'API. Vous apprenez les concepts et la conception une fois pour toutes avec une seule API, et vous pouvez ensuite appliquer ce savoir à l'aide de différentes API sur l'ensemble de la surface API Windows.
Sur le Centre de développement Windows (dev.windows.com), vous trouverez beaucoup d'exemples qui couvrent la plupart de ces sujets. En voici déjà quelques-uns.
Contrats Vous pouvez permettre à des utilisateurs de faire une recherche dans votre application lorsqu'ils sélectionnent le talisman Rechercher et afficher des suggestions dans le volet Rechercher. Votre application peut également partager du contenu avec une autre via le talisman Partager. Voici quelques exemples :
Social À l'aide de classes provenant du nom d'espaces Windows.ApplicationModel.Contacts, vous pouvez lancer le sélecteur de contacts et obtenir des contacts. Pour les applications qui doivent fournir des contacts à d'autres applications, vous pouvez utiliser la classe ContactPickerUI pour créer une collection de contacts :
Médias De la simple lecture et capture médias jusqu'au transcodage et à la lecture médias sur des périphériques externes via le contrat Play To, vous trouverez des API Windows dans l'espace de noms Windows.Media :
Sécurité Vous pouvez récupérer des informations d'identification qui peuvent ensuite être transmises à des API qui en ont besoin (par exemple, pour la prise en charge de l'authentification unique). Vous pouvez aussi utiliser un chiffrement fort par mot de passe pour stocker de manière sécurisée des informations privées sur un ordinateur local afin de protéger des comptes de carte de crédit, des comptes bancaires et des logiciels. Vous pouvez même effectuer plusieurs formes de chiffrement différentes à l'aide du nom d'espaces Windows.Security.Cryptography :
Mise en réseau / Web Que vous vous connectiez au réseau via TCP à l'aide de la classe StreamSocket, via le protocole UDP (User Datagram Protocol) en utilisant la classe DatagramSocket, ou simplement que vous demandiez des informations de statut réseau pour vérifier si vous pouvez enregistrer des données d'application sur un service Web ou bien les enregistrer localement, vous trouverez tout ce dont vous avez besoin dans l'espace de noms Windows.Networking :
Bien évidemment, les fonctionnalités Windows Runtime ne s'arrêtent pas là. Bien d'autres sont à votre disposition en tant que développeur Windows et vous pouvez approfondir vos recherches sur le Centre de développement Windows à l'adresse bit.ly/yyJI2J.
Windows Runtime est rapide et fluide (Natif et asynchrone)
Windows Runtime est implémenté au niveau le plus bas en tant qu'objets natifs avec un contrat binaire, mais il est exposé au monde via des métadonnées, un système de type commun et des langages partagés. Les API WinRT fournissent toujours les performances rapides des API Windows précédentes, mais offrent une expérience de développement moderne, comme je l'ai expliqué ci-dessus.
Pour que les applications conservent fluidité et réactivité, le défi est tout autre. Nous, les êtres humains, effectuons plusieurs tâches instinctivement, ce qui influe directement sur nos attentes quant aux réactions des applications à notre contact. Nous attendons que les applications soient réactives dans toute interaction. Lorsque nous utilisons notre application de lecture d'informations préférée, nous souhaitons pouvoir ajouter des flux d'information, consulter et enregistrer de nouveaux articles, etc. Et nous devrions être en mesure de faire toutes ces choses même lorsque l'application est en train de récupérer les articles les plus récents sur Internet.
Cela devient particulièrement important lorsque nous interagissons avec des applications utilisant le tactile. On le remarque tout de suite lorsque l'application ne « colle » pas à notre doigt. Même des problèmes de performance mineurs parviennent à nuire à notre expérience et rompre la sensation de rapidité et de fluidité.
Plusieurs applications modernes se connectent à des sites Web sociaux, stockent des données dans le nuage, communiquent avec d'autres gadgets et périphériques, etc. Certaines de ces sources ont des latences imprévisibles, ce qui fait de la création d'applications rapides et fluides un véritable défi. À moins d'être construites correctement, les applications passent plus de temps à attendre des réponses de l'environnement extérieur qu'à répondre aux besoins de leur utilisateur.
Répondre aux difficultés de ce monde connecté est l'un des principes essentiels de Windows Runtime. Vous, le développeur, devez tomber dans la « Fosse du succès » (consulter bit.ly/NjYMXM) lorsque vous créez des applications connectées au monde. Pour parvenir à cela, les API potentiellement liées aux E/S ou de longue durée sont asynchrones dans Windows Runtime. Celles-ci sont les candidates les plus probables à une dégradation visible des performances lorsqu'elles sont écrites de manière synchrone (elles peuvent mettre par exemple plus de 50 ms pour s'exécuter). L'approche asynchrone en ce qui concerne les API vous permet d'écrire du code rapide et fluide par défaut, mettant en avant l'importance de la réactivité de l'application lorsque vous développez des applications du Windows Store.
Pour mieux comprendre la nature asynchrone de Windows Runtime, lisez le billet de blog « Maintenir la rapidité et la fluidité des applications avec l'asynchronie dans Windows Runtime », à l'adresse bit.ly/GBLQLr.
Windows Runtime permet les applications hybrides
Le fait que vous ne soyez pas limité par le langage de programmation que vous choisissez pour écrire votre application est une fonctionnalité puissante de Windows Runtime. Vous n'êtes pas limité à l'utilisation des bibliothèques et du code disponibles pour un environnement de langage de programmation donné. Vous pouvez utiliser le langage, la bibliothèque ou le composant le mieux adapté à la tâche qui se présente à vous. Il peut s'agir d'une bibliothèque open source par exemple.
Que se passe-t-il si vous écrivez un jeu avec JavaScript/HTML/CSS et que vous voulez une bibliothèque physique très rapide ? Vous pouvez utiliser Box2D en C++. Et si vous voulez écrire une application du Windows Store avec JavaScript et que vous souhaitez travailler sur des fichiers compressés ? Vous pouvez utiliser la fonctionnalité zip dans le .NET Framework d'une manière simple. Vous souhaitez créer une nouvelle application du Windows Store musicale en C# et faire de la programmation audio de niveau inférieur ? Aucun problème, utilisez simplement Xaudio ou WASAPI en C++. Ces capacités sont illustrées dans la figure 5.
Figure 5 Windows Runtime permet les applications hybrides
Examinons un exemple d'application de synthétiseur logiciel utilisant XAML écrit en C#. Je souhaite ajouter la prise en charge de filtres sympas, je vais donc exploiter Xaudio pour avoir un contrôle direct des tampons audio. J'utilise C++/CX pour générer les API qui seront exposées au projet C#.
Je commence par créer un simple wrapper WinRT autour de la fonctionnalité Xaudio que je veux exposer (voir la figure 6).
#pragma once
#include "mmreg.h"
#include <vector>
#include <memory>
namespace XAudioWrapper
{
public ref class XAudio2SoundPlayer sealed
{
public:
XAudio2SoundPlayer(uint32 sampleRate);
virtual ~XAudio2SoundPlayer();
void Initialize();
bool PlaySound(size_t index);
bool StopSound(size_t index);
bool IsSoundPlaying(size_t index);
size_t GetSoundCount();
void Suspend();
void Resume();
private:
interface IXAudio2* m_audioEngine;
interface IXAudio2MasteringVoice* m_masteringVoice;
std::vector<std::shared_ptr<ImplData>> m_soundList;
};
}
Tout d'abord, remarquez l'emploi des mots clés « public », « ref » et « sealed » dans la déclaration de classe. C'est simplement la façon de déclarer une classe WinRT publique en C++/CX. Cela vous permet d'utiliser cette classe à partir d'autres langages tels que JavaScript, C# ou Visual Basic. Il est important de noter que ce n'est pas du C++ ou du C++/Common Language Infrastructure (CLI) managé. Il ne s'agit pas d'une compilation vers un langage Microsoft intermédiaire, mais bien d'un composant natif pur et dur.
Vous remarquerez également que les fonctionnalités publiques (méthodes, propriétés, etc.) de la classe sont limitées aux types intégrés C++ ou aux types WinRT. Ce sont les seuls types autorisés à franchir la barrière de langage dans les composants WinRT. Cependant, vous pouvez utiliser des bibliothèques C++ existantes comme la Bibliothèque STL (Standard Template Library) autant que vous le voulez dans l'implémentation de vos composants WinRT.
Pour de plus amples précisions sur la création de composants WinRT en C++, vous pouvez lire la rubrique du Centre de développement Windows à ce sujet, « Création de composants Windows Runtime en C++ », à l'adresse bit.ly/TbgWz7.
À présent que j'ai défini l'interface basique pour ma classe, examinons certaines des méthodes implémentées (les détails ne sont pas importants), illustrées à la figure 7.
Figure 7 XAudioWrapper.cpp
XAudio2SoundPlayer::XAudio2SoundPlayer(uint32 sampleRate) :
m_soundList()
{
...
XAudio2Create(&m_audioEngine, flags);
// Create the mastering voice
m_audioEngine->CreateMasteringVoice(
&m_masteringVoice,
XAUDIO2_DEFAULT_CHANNELS,
sampleRate
);
}
bool XAudio2SoundPlayer::PlaySound(size_t index)
{
//
// Setup buffer
//
XAUDIO2_BUFFER playBuffer = { 0 };
std::shared_ptr<ImplData> soundData = m_soundList[index];
playBuffer.AudioBytes = soundData->playData->Length;
playBuffer.pAudioData = soundData->playData->Data;
playBuffer.Flags = XAUDIO2_END_OF_STREAM;
HRESULT hr = soundData->sourceVoice->Stop();
if (SUCCEEDED(hr))
{
...
}
...
}
Comme vous le remarquerez dans l'extrait de code de la figure 7, j'utilise les API COM Xaudio2 disponibles dans le Windows SDK pour les applications du Windows Store afin d'associer le moteur audio. De plus, j'utilise des structures et des types C++ dépassant les types WinRT pour implémenter les fonctionnalités nécessaires.
Une fois que j'ai défini et implémenté ma classe de base, je peux simplement ajouter une référence à mon projet C++ à partir de mon projet C#. En conséquence, la classe qui est exposée à partir de mon projet C++ devient disponible pour mon projet C# (voir la figure 8).
using XAudioWrapper;
namespace BasicSoundApp
{
public sealed partial class MainPage : Page
{
XAudio2SoundPlayer _audioPlayer = new XAudio2SoundPlayer(48000);
public MainPage()
{
this.InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
_audioPlayer.Initialize();
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
_audioPlayer.PlaySound(0);
}
}}
Vous remarquez que, bien que le XAudioWrapper ait été écrit en C++ natif, il peut être utilisé comme s'il était une classe .NET standard. Je référence son nom d'espaces, instancie le composant et commence à invoquer les diverses méthodes qu'il expose, et tout cela sans avoir besoin d'aucuns DllImports pour appeler le code natif !
Il n'y a aucune limite. En tant que développeur JavaScript, vous n'êtes pas limité aux seules bibliothèques JavaScript. En tant que développeur C#/Visual Basic, vous n'êtes pas limité aux seules bibliothèques .NET. Et en tant que développeur C++, vous n'êtes pas limité aux seules bibliothèques C/C++. Devrez-vous souvent créer vos propres composants ? Peut-être que non. Mais vous disposez de cette possibilité.
Pour résumer, Windows Runtime est au cœur de la création d'applications du Windows Store sur Windows 8. Il offre une plateforme puissante sur laquelle créer des applications du Windows Store. Windows Runtime fournit une surface de développement à la conception cohérente et bien pensée, et forte de nombreuses fonctionnalités. Que vous soyez développeur JavaScript, C#/Visual Basic ou C++, vous pouvez à présent devenir un développeur Windows qui crée de nouvelles applications du Windows Store pour Windows 8.
Forum aux questions
Q. Windows Runtime vient-il en remplacement du CLR ou du Microsoft .NET Framework ?
R. Non, Windows Runtime ne remplace pas le Microsoft .NET Framework, ni aucune autre infrastructure. Lorsque vous créez une application du Windows Store en C#, votre code s'exécute à l'aide du CLR. Non seulement ça, mais un sous-ensemble du .NET Framework (ainsi que Win32 et COM) est à votre disposition pour construire vos applications du Windows Store.
Q. Donc lorsque j'écris des applications du Windows Store en C++, j'utilise C++/CLI ?
R. Non, le code utilisant Windows Runtime pour les applications du Windows Store est écrit à l'aide de C++/CX. Bien qu'il puisse ressembler au C++/CLI de prime abord, il est vraiment natif. Vous n'allez pas introduire de garbage collection ni d'autres fonctionnalités C++/CLI dans votre application native.
Ressources
Pour plus d'informations, reportez-vous aux ressources suivantes :
- Exemples d'applications Windows Store : dev.windows.com
- « Maintenir la rapidité et la fluidité des applications avec l'asynchronie dans Windows Runtime » : bit.ly/GBLQLr
- « Création de composants Windows Runtime en C# et Visual Basic » : bit.ly/OWDe2A
- « Création de composants Windows Runtime en C++ » : bit.ly/TbgWz7
- Documentation API pour les applications du Windows Store : bit.ly/zdFRK2
Jason Olson est responsable de programme senior travaillant sur Windows Runtime chez Microsoft. Quand il ne travaille pas sur Windows, il joue du piano dans la région de Seattle et passe du temps avec son épouse et ses deux garçons.
Je remercie nos experts techniques d'avoir relu cet article : Noel Cross, Anantha Kancherla, Ines Khelifi, John Lam, Martyn Lovell, Harry Pierson, Mahesh Prakriya et Steve Rowe