Créez vos propres composants Windows Runtime pour concevoir de formidables applications de style Metro

Blog des développeurs d'applications Windows 8

Indications sur la conception d'applications de style Metro pour Windows 8, par l'équipe d'ingénierie de Windows 8

Créez vos propres composants Windows Runtime pour concevoir de formidables applications de style Metro

  • Comments 0

Pour Windows 8, nous avons entièrement réinventé la plateforme, vous permettant ainsi de choisir le langage de programmation et les technologies que vous connaissez déjà pour concevoir des applications adaptées au périphérique et au terminal. Avec Windows Runtime, vous pouvez même facilement utiliser plusieurs langages au sein d'une seule application. Vous pouvez concevoir une formidable application de style Metro avec HTML et JavaScript pouvant interagir avec le contrôleur Xbox 360 en créant votre propre composant Windows Runtime en C++. Vous pouvez créer des contrôles XAML réutilisables exposés au moyen des composants Windows Runtime, que les applications de style Metro écrites à la fois en C++ et en C# peuvent immédiatement utiliser. Vous pouvez concevoir des applications sur la plateforme Windows 8 à l'aide des langages de votre choix, sans compromis.

Ce billet de blog explique ce que vous devez savoir pour créer vos propres composants Windows Runtime.

Principes de base

Windows Runtime se trouve au cœur du choix du langage de programmation. Il expose les contrôles de façon à ce que vous puissiez les appeler depuis JavaScript, C++, C# et Visual Basic d'une façon naturelle et familière. Ce principe est le même lorsque vous créez vos propres API.

Un composant Windows Runtime que vous concevez et intégrez à votre application est généralement désigné sous le nom de composant Windows Runtime tiers. Un composant tiers est différent d'un composant interne qui fait déjà partie de la plateforme Windows 8. Vous pouvez écrire ces composants Windows Runtime tiers en C++, C# ou Visual Basic. Vous pouvez appeler les API qu'ils exposent depuis n'importe où, notamment depuis d'autres composants Windows Runtime intégrés à votre application. Vous pouvez également appeler les API exposées via des composants Windows Runtime dans n'importe quel langage.

Les composants Windows Runtime que vous écrivez pour votre application peuvent utiliser des API Windows Runtime, des API Win32, COM, .NET ou des bibliothèques tierces tant qu'elles sont prises en charge pour le développement d'applications de style Metro. Notez que les composants Windows Runtime que vous concevez sont différents de ce que vous connaissez traditionnellement sous le nom de DLL C++ ou d'assemblies .NET qui exposent des API. La création d'une bibliothèque de classes en .Net ou d'une bibliothèque DLL autonome en C++ est différente de la création d'un composant Windows Runtime. Les composants Windows Runtime sont déclarés sous la forme de fichiers .wnmd qui exposent des métadonnées Windows Runtime et qui permettent aux langages, tels que JavaScript, d'utiliser naturellement les API Windows Runtime (par exemple, pascalCasedNames prend en charge les API exposées dans JavaScript). Les métadonnées Windows Runtime permettent en outre à Visual Studio de fournir de formidables outils, tels que la prise en charge IntelliSense.

Pourquoi créer vos propres composants Windows Runtime

La création de composants Windows Runtime peut vous aider à architecturer la réutilisabilité et l'interopérabilité des langages. Examinons certains cas d'applications illustrant comment vous pouvez utiliser des composants Windows Runtime tiers pour optimiser les expériences.

Vous pouvez intégrer votre application de style Metro au contrôleur Xbox 360 pour Windows
Figure 1 : contrôleur Xbox 360

Utilisation des API Win32 et COM dans votre application de style Metro

La plateforme fournie par Internet Explorer 10 vous permet de créer de formidables applications de style Metro avec HTML, CSS et JavaScript. Mais que faire si vous avez conçu un jeu avec l'élément HTML5 Canvas et que vous souhaitez l'intégrer au contrôleur Xbox 360 pour Windows ? L'API XInput, qui permet aux applications de recevoir les entrées du contrôleur, expose les API Win32 qui ne sont pas directement disponibles dans JavaScript.

Dans cet exemple, la création d'un composant Windows Runtime peut résoudre ce problème et vous permettre d'utiliser les API XInput dans votre application de style Metro HTML. L'exemple de contrôleur XInput et JavaScript l'illustre parfaitement. L'application d'exemple contient un composant Windows Runtime de contrôleur de jeu écrit en C++, qui englobe les fonctionnalités exposées par les API XInput. L'application HTML d'exemple du contrôleur utilise le composant Windows Runtime C++ du contrôleur de jeu pour permettre l'interaction avec le contrôleur Xbox 360.

Ce scénario, impossible à réaliser avec HTML et JavaScript seuls, illustre parfaitement en quoi la création d'un composant Windows Runtime tiers vous permet de réaliser des scénarios plus complexes que vous ne pourriez sinon pas mener à bien.

Opérations consommant beaucoup de ressources de calcul

Les applications créées pour des domaines tels que les sciences, l'ingénierie et la cartographie/géographie, intègrent souvent des opérations consommant beaucoup de ressources de calcul. Ces opérations intensives nécessitent généralement un traitement parallèle puissant et sont parfaitement adaptées à C++ pour obtenir des performances optimales. Dans Développement de Bing Maps Trip Optimizer, une application de style Metro en JavaScript et C++, nous voyons un autre cas où la création d'un composant Windows Runtime en C++ nous permet d'optimiser notre application.

Vous vous demandez sans doute pourquoi calculer un itinéraire sur des données locales alors que nous pourrions réaliser cette tâche consommant beaucoup de ressources de calcul sur des serveurs Bing qui se trouvent dans le cloud. Pour ce faire, Bing Maps expose les API JavaScript, mais il peut arriver qu'une application doive s'exécuter hors connexion. De plus, nous voulons que l'utilisateur fasse glisser et modifie l'itinéraire en temps réel de manière tactile. Si nous exécutons ces opérations intenses en local, nous améliorons encore l'expérience.

En écrivant notre opération qui consomme beaucoup de ressources de calcul en C++ à l'aide de la bibliothèque des tâches parallèles, nous pouvons tirer parti de toute la puissance du client pour optimiser l'expérience utilisateur. Windows Runtime convient parfaitement à ce cas, car il nous permet de créer notre interface utilisateur cliente sophistiquée en HTML et JavaScript avec le contrôle AJAX de Bing Maps tout en exécutant toutes nos opérations de calcul d'itinéraires intensives avec du code C++ qui procède rapidement à l'aide de la mise en parallèle.

Bibliothèques

La communauté propose un nombre incroyable de bibliothèques formidables que les développeurs élaborent et partagent avec tout le monde. Dans le passé, vous avez pu éprouver des difficultés à réutiliser certaines de ces bibliothèques, si elles ne correspondaient pas au langage de programmation dans lequel votre application était implémentée. Par exemple, si vous aviez créé une application .NET, vous ne pouviez pas utiliser une bibliothèque écrite en C++ sans passer par de complexes opérations de codage d'interopérabilité, telles que PInvoke.

Windows Runtime efface les différences de langages dans Windows 8, permettant à une seule bibliothèque de composants Windows Runtime dotée d'une seule base de code, d'être accessible à un plus grand nombre de développeurs, quel que soit le langage du composant ou le langage de programmation principal de l'application.

Vous pouvez maintenant créer une seule bibliothèque XAML de contrôles personnalisés, exposée par Windows Runtime, que les développeurs d'applications C++ et C# peuvent utiliser. Vous pouvez en outre utiliser différentes bibliothèques Windows Runtime de stockage de données partagées par les développeurs dans vos applications de style Metro XAML ou HTML. Tous ces scénarios sont possibles sans avoir à écrire de code d'interopérabilité.

Nous pensons que Windows Runtime représentera un avantage sans précédent pour les bibliothèques que les développeurs créent et partagent largement dans la communauté des développeurs d'applications de style Metro. Penchons-nous maintenant sur deux exemples concrets qui illustrent les principes de base de la création d'un composant Windows Runtime tiers en C++/CX et en C#.

Scénario 1 : optimisation de l'application avec des données audio natives

Imaginons que nous souhaitions créer une application de synthétiseur logiciel à l'aide de XAML et d'une logique d'application écrite en C#. Pour ajouter des filtres à notre application musicale, nous voulons utiliser XAudio afin de contrôler directement les tampons audio.

Ajout du composant Windows Runtime à notre solution

À l'aide de Visual Studio, nous ajoutons un nouveau projet de composant Windows Runtime C++ à notre solution existante. Ce composant Windows Runtime englobe la fonctionnalité de traitement de musique :

Utilisation de Visual Studio pour ajouter un nouveau composant Windows Runtime C++ à notre application musicale
Figure 2 : ajout d'un nouveau composant Windows Runtime C++

Visual Studio a créé un projet C++ pour que nous exposions les API pour lesquelles l'implémentation sera intégrée dans un fichier DLL et les métadonnées Windows Runtime dans un fichier winmd. Ils sont tous les deux disponibles dans notre projet C#.

Définition de la classe exposée dans notre projet C# XAML

Nous utilisons C++/CX pour créer les API qui seront exposées dans notre projet C#, mais vous pouvez également utiliser la bibliothèque de modèles C++ Windows Runtime. Nous commençons par définir une classe assez basique pour encapsuler la fonctionnalité XAudio :

XAudioWrapper.h

#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;
};
}

Vous pouvez d'abord remarquer l'utilisation des mots clés public, ref et sealed dans la déclaration de la classe. Pour qu'une classe soit instanciée depuis un autre langage, tel que JavaScript ou C# dans une application de style Metro, la classe doit être déclarée en tant que « public ref class sealed ».

Les fonctionnalités publiques (méthodes, propriétés …) de la classe sont limitées aux types C++ intégrés ou aux types Windows Runtime. Ce sont les seuls types autorisés à franchir la frontière des langages dans les composants Windows Runtime. Cela étant dit, vous pouvez utiliser la bibliothèque C++ classique (c'est-à-dire : collections Bibliothèque de types standard) pour les membres des données privées de votre classe, comme illustré dans cet extrait de code. Ces membres des données privées n'ont pas à suivre les règles associées au franchissement de la frontière des langages. Le compilateur Visual Studio émet des messages d'erreur et vous guide si vous utilisez des constructions non prises en charge.

Implémentation de la classe exposée dans notre composant Windows Runtime

Maintenant que nous avons défini l'interface de base de notre classe, regardons certaines des méthodes implémentées :

XAudioWrapper.cpp

XAudio2SoundPlayer::XAudio2SoundPlayer(uint32 sampleRate) :
m_soundList()
{
// Create the XAudio2 engine
UINT32 flags = 0;

XAudio2Create(&m_audioEngine, flags);

// Create the mastering voice
m_audioEngine->CreateMasteringVoice(
&m_masteringVoice,
XAUDIO2_DEFAULT_CHANNELS,
sampleRate
);
}

void XAudio2SoundPlayer::Resume()
{
m_audioEngine->StartEngine();
}

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))
{
hr = soundData->sourceVoice->FlushSourceBuffers();
}

//
// Submit the sound buffer and (re)start (ignore any 'stop' failures)
//
hr = soundData->sourceVoice->SubmitSourceBuffer(&playBuffer);
if (SUCCEEDED(hr))
{
hr = soundData->sourceVoice->Start(0, XAUDIO2_COMMIT_NOW);
}

return SUCCEEDED(hr);
}

Dans cet extrait de code, nous utilisons simplement les API COM XAudio2 disponibles pour le développement d'applications de style Metro pour raccorder notre moteur audio, lire du son et reprendre le moteur. Nous pouvons en outre utiliser les types et les constructions C++ parallèlement aux types Windows Runtime pour implémenter les fonctionnalités requises.

Ajout et utilisation du composant Windows Runtime à notre solution

Une fois notre classe de base définie et implémentée, nous utilisons Visual Studio pour ajouter le composant Windows Runtime XAudioWrapper à notre projet C++ depuis notre projet C# :

Utilisation de Visual Studio pour ajouter une référence au composant Windows Runtime XAudioWrapper dans notre application musicale

Figure 3 : ajout du composant Windows Runtime XAudioWrapper à notre application musicale

La classe que nous exposons depuis notre projet C++ devient ainsi disponible dans notre projet C# :

MainPage.cs

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);
}
}
}

Comme illustré dans l'extrait de code, nous pouvons interagir avec notre wrapper XAudio dans C# tout comme s'il s'agissait d'un composant .NET standard. Nous référençons son espace de noms, instancions le composant et commençons à appeler les différentes méthodes qu'il expose. Tout cela sans avoir besoin d'importer des DLL pour appeler du code natif !

Scénario 2 : utilisation des API intégrées pour ouvrir un fichier zip dans votre application

Supposons que nous voulions également créer une application de visionneuse de fichiers à l'aide de HTML et que nous souhaitions ajouter la fonctionnalité permettant aux utilisateurs de cette application de sélectionner des fichiers zip. Nous voulons utiliser les API déjà intégrées à Windows et exposées dans la plateforme .NET pour gérer les fichiers zip.

Ajout du composant Windows Runtime à notre solution

Cette étape est la même que celle déjà décrite pour notre application musicale, mais nous choisissons maintenant le composant Windows Runtime C# pour englober la fonctionnalité de traitement des fichiers zip :

Utilisation de Visual Studio pour ajouter un nouveau composant Windows Runtime C# à notre application de visionneuse de fichiers
Figure 4 : ajout d'un nouveau composant Windows Runtime C# 

Visual Studio a créé un projet C# pour que nous exposions les API pour lesquelles l'implémentation et les métadonnées Windows Runtime seront intégrées à un fichier .winmd et rendues disponibles dans notre projet Web.

Implémentation de la classe exposée dans notre composant Windows Runtime

Nous utilisons C# pour créer les API qui seront exposées dans notre projet Web, mais vous pouvez également utiliser Visual Basic. Nous commençons par définir une classe C# simple pour encapsuler la fonctionnalité zip :

ZipWrapper.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.Storage;

public sealed class ZipWrapper
{
public static IAsyncOperationWithProgress<IList<string>, double> EnumerateZipFileAsync(StorageFile file)
{
return AsyncInfo.Run(async delegate(
System.Threading.CancellationToken cancellationToken, IProgress<double> progress)
{
IList<string> fileList = new List<string>();
progress.Report(0);

using (var stream = await file.OpenStreamForReadAsync())
{
using (var archive = new ZipArchive(stream))
{
for (int i = 0; i < archive.Entries.Count; i++)
{
// add code for processing/analysis on the file
// content here

// add to our list and report progress
fileList.Add(archive.Entries[i].FullName);
double progressUpdate = ((i + 1) / ((double)archive.Entries.Count)) * 100; // percentage
progress.Report(progressUpdate);
}
}
}

progress.Report(100.0);
return fileList;
});
}
}

Cette classe est de type « public » et « sealed ». Tout comme la création de composants Windows Runtime C++, cela est nécessaire pour que d'autres langages puissent instancier la classe. La méthode statique exposée dans la classe utilise un mélange de types Windows Runtime (tels que StorageFile) et de types .NET (tels que IList) dans la signature de la méthode. La règle de base consiste à utiliser les types Windows Runtime pour définir les champs publics, les paramètres et les types de retour qui seront exposés aux autres langages. Cela étant dit, vous pouvez utiliser certains fondamentaux .NET (c'est-à-dire : DateTimeOffset et Uri) et des primitives (c'est-à-dire : IList) tels quels.

Vous noterez également que la méthode ci-dessus exploite l'infrastructure Windows Runtime de prise en charge de l'asynchronisme et de la progression que vous pouvez (et devez) utiliser lorsque vous définissez vos composants Windows Runtime. En ce qui concerne l'implémentation du composant Windows Runtime ou des fonctionnalités privées de la classe, vous n'êtes pas limité à la seule utilisation des API et types Windows Runtime : vous pouvez utiliser n'importe quelle surface d'API .NET exposée pour le développement d'applications de style Metro, comme l'illustrent les API ZipArchive de l'extrait de code.

Ajout et utilisation du composant Windows Runtime à notre solution

Maintenant que nous avons implémenté notre wrapper de l'outil de compression (zip), nous utilisons Visual Studio pour ajouter une référence à notre projet C# depuis notre projet JavaScript :

Utilisation de Visual Studio pour ajouter une référence au composant Windows Runtime ZipUtil dans notre application de visionneuse de fichiers
Figure 5 : ajout du composant Windows Runtime ZipUtil à notre application de visionneuse de fichiers

La classe que nous avons exposée depuis notre projet C# devient ainsi disponible dans notre projet Web :

program.js

function pickSinglePhoto() {

// Create the picker object for picking zip files
var openPicker = new Windows.Storage.Pickers.FileOpenPicker();
openPicker.viewMode = Windows.Storage.Pickers.PickerViewMode.thumbnail;
openPicker.suggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.picturesLibrary;
openPicker.fileTypeFilter.replaceAll([".zip"]);

// Open the picker for the user to pick a file
openPicker.pickSingleFileAsync().then(function (file) {
if (file) {
ZipUtil.ZipWrapper.enumerateZipFileAsync(file).then(
function (fileList) {
for (var i = 0; i < fileList.length; i++)
document.getElementById('output').innerHTML += " " + fileList[i];
},
function (prog) {
document.getElementById('zipProgress').value = prog;
}
);
} else {
document.getElementById('output').innerHTML = "an error occurred";
}
});
};

Comme vous pouvez le voir, nous pouvons interagir avec notre wrapper de l'outil de compression (zip) dans JavaScript tout comme s'il s'agissait d'un objet JavaScript standard. Nous pouvons appeler la méthode statique exposée dans notre composant Windows Runtime et pour ce faire, nous pouvons utiliser les constructions du langage asynchrone de JavaScript, telles que .then().

Conseils généraux

Toutes les API que vous écrivez pour votre application de style Metro ne doivent pas être exposées en tant que composant Windows Runtime tiers. En règle générale, utilisez les types Windows Runtime lorsque vous communiquez entre plusieurs langages de programmation et utilisez des types et constructions qui sont intégrés dans le langage que vous utilisez pour les fonctionnalités qui ne sont pas publiquement exposées via un composant Windows Runtime. Lorsque vous créez votre composant Windows Runtime, vous devez en outre prendre en considération différentes fonctionnalités et règles propres aux langages concernant le franchissement des frontières des langages. Cela inclut les délégués et les événements, les opérations asynchrones, la surcharge de méthode, la gestion de types de données spécifiques (par exemple les collections), la gestion des exceptions et des conseils de débogage. Vous pouvez approfondir ces sujets en accédant à la section consacrée à la création de composants Windows Runtime pour votre langage de développement.

Pour conclure

Grâce aux composants Windows Runtime, vous pouvez maintenant mélanger les langages de programmation et les technologies d'API pour concevoir les applications que vous voulez. Windows 8 ignore les compromis. Même le développement se fait sans compromis, ce qui vous permet de mélanger et d'utiliser les langages de programmation qui correspondent le mieux à votre scénario. Nous espérons que vous passerez ainsi plus de temps à innover et moins de temps à devoir maîtriser un langage de programmation entièrement nouveau.

Bon codage à tous !

-- Ines Khelifi, chef de projet, Windows

Références

Dans ce billet, nous avons simplement survolé ce qu'il est possible de faire en créant des composants Windows Runtime. Voici des ressources supplémentaires qui vous aideront à en savoir plus pour développer votre application :

  • Loading...
Leave a Comment
  • Please add 4 and 7 and type the answer here:
  • Post