Déclenchement d’événements dans les composants Windows Runtime
Remarque
Pour plus d’informations sur la déclenchement d’événements dans un composant Windows Runtime C++/WinRT , consultez Créer des événements en C++/WinRT.
Si votre composant Windows Runtime déclenche un événement d’un type délégué défini par l’utilisateur sur un thread d’arrière-plan (thread de travail) et que vous souhaitez que JavaScript puisse recevoir l’événement, vous pouvez implémenter et/ou le déclencher de l’une de ces manières.
- (Option 1) Déclenchez l’événement via Windows.UI.Core.CoreDispatcher pour marshaler l’événement dans le contexte de thread JavaScript. Bien qu’il s’agit généralement de la meilleure option, dans certains scénarios, il peut ne pas fournir les performances les plus rapides.
- (Option 2) Utilisez l’objet >Windows.Foundation.EventHandler<(mais perdez les informations de type d’événement). Si l’option 1 n’est pas réalisable ou si ses performances ne sont pas adéquates, il s’agit d’un bon deuxième choix, à condition que la perte d’informations de type soit acceptable. Si vous créez un composant Windows Runtime C#, le type d’objet> Windows.Foundation.EventHandler n’est pas disponible ; au lieu de cela, ce type est projeté sur System.EventHandler<. Vous devez donc l’utiliser à la place.
- (Option 3) Créez votre propre proxy et stub pour le composant. Cette option est la plus difficile à implémenter, mais elle conserve les informations de type et peut fournir de meilleures performances par rapport à l’option 1 dans les scénarios exigeants.
Si vous déclenchez simplement un événement sur un thread d’arrière-plan sans utiliser l’une de ces options, un client JavaScript ne recevra pas l’événement.
Background
Tous les composants et applications Windows Runtime sont essentiellement des objets COM, quel que soit le langage que vous utilisez pour les créer. Dans l’API Windows, la plupart des composants sont des objets COM agiles qui peuvent communiquer de manière égale avec des objets sur le thread d’arrière-plan et sur le thread d’interface utilisateur. Si un objet COM ne peut pas être agile, il nécessite des objets d’assistance appelés proxys et stubs pour communiquer avec d’autres objets COM sur la limite de thread d’arrière-plan de l’interface utilisateur. (En termes COM, il s’agit de la communication entre les appartements de threads.)
La plupart des objets de l’API Windows sont agiles ou ont des proxys et des stubs intégrés. Toutefois, les proxys et les stubs ne peuvent pas être créés pour des types génériques tels que Windows.Foundation.TypedEventHandler<TSender, TResult> , car ils ne sont pas complets tant que vous n’avez pas fourni l’argument de type. Ce n’est qu’avec les clients JavaScript que l’absence de proxys ou de stubs devient un problème, mais si vous souhaitez que votre composant soit utilisable à partir de JavaScript ainsi qu’à partir de C++ ou d’un langage .NET, vous devez utiliser l’une des trois options suivantes.
(Option 1) Déclencher l’événement via CoreDispatcher
Vous pouvez envoyer des événements de n’importe quel type de délégué défini par l’utilisateur à l’aide de Windows.UI.Core.CoreDispatcher, et JavaScript pourra les recevoir. Si vous ne savez pas quelle option utiliser, essayez d’abord celle-ci. Si la latence entre le déclenchement de l’événement et la gestion des événements devient un problème, essayez l’une des autres options.
L’exemple suivant montre comment utiliser CoreDispatcher pour déclencher un événement fortement typé. Notez que l’argument de type est Toast, et non Object.
public event EventHandler<Toast> ToastCompletedEvent;
private void OnToastCompleted(Toast args)
{
var completedEvent = ToastCompletedEvent;
if (completedEvent != null)
{
completedEvent(this, args);
}
}
public void MakeToastWithDispatcher(string message)
{
Toast toast = new Toast(message);
// Assume you have a CoreDispatcher at class scope.
// Initialize it here, then use it from the background thread.
var window = Windows.UI.Core.CoreWindow.GetForCurrentThread();
m_dispatcher = window.Dispatcher;
Task.Run( () =>
{
if (ToastCompletedEvent != null)
{
m_dispatcher.RunAsync(CoreDispatcherPriority.Normal,
new DispatchedHandler(() =>
{
this.OnToastCompleted(toast);
})); // end m_dispatcher.RunAsync
}
}); // end Task.Run
}
(Option 2) Utiliser l’objet> EventHandler<, mais perdre des informations de type
Remarque
Si vous créez un composant Windows Runtime C#, le type d’objet> Windows.Foundation.EventHandler n’est pas disponible ; au lieu de cela, ce type est projeté sur System.EventHandler<. Vous devez donc l’utiliser à la place.
Une autre façon d’envoyer un événement à partir d’un thread d’arrière-plan consiste à utiliser l’objet> Windows.Foundation.EventHandler<comme type de l’événement. Windows fournit cette instanciation concrète du type générique et fournit un proxy et un stub pour celui-ci. L’inconvénient est que les informations de type de vos arguments d’événement et l’expéditeur sont perdues. Les clients C++ et .NET doivent savoir par le biais de la documentation sur quel type effectuer la conversion en cas de réception de l’événement. Les clients JavaScript n’ont pas besoin des informations de type d’origine. Ils trouvent les propriétés d’argument, en fonction de leurs noms dans les métadonnées.
Cet exemple montre comment utiliser l’objet> Windows.Foundation.EventHandler<en C# :
public sealed Class1
{
// Declare the event
public event EventHandler<Object> ToastCompletedEvent;
// Raise the event
public async void MakeToast(string message)
{
Toast toast = new Toast(message);
// Fire the event from a background thread to allow this thread to continue
Task.Run(() =>
{
if (ToastCompletedEvent != null)
{
OnToastCompleted(toast);
}
});
}
private void OnToastCompleted(Toast args)
{
var completedEvent = ToastCompletedEvent;
if (completedEvent != null)
{
completedEvent(this, args);
}
}
}
Vous utilisez cet événement côté JavaScript comme suit :
toastCompletedEventHandler: function (event) {
var toastType = event.toast.toastType;
document.getElementById("toasterOutput").innerHTML = "<p>Made " + toastType + " toast</p>";
}
(Option 3) Créer votre propre proxy et stub
Pour obtenir des gains de performances potentiels sur les types d’événements définis par l’utilisateur qui ont des informations de type entièrement conservées, vous devez créer vos propres objets proxy et stub et les incorporer dans votre package d’application. En règle générale, vous devez utiliser cette option uniquement dans des situations rares où aucune des deux autres options n’est adéquate. En outre, il n’existe aucune garantie que cette option fournira de meilleures performances que les deux autres options. Les performances réelles dépendent de nombreux facteurs. Utilisez le profileur Visual Studio ou d’autres outils de profilage pour mesurer les performances réelles dans votre application et déterminer si l’événement est en fait un goulot d’étranglement.
Le reste de cet article montre comment utiliser C# pour créer un composant Windows Runtime de base, puis utiliser C++ pour créer une DLL pour le proxy et le stub qui permettra à JavaScript de consommer un TSender Windows.Foundation.TypedEventHandler<, événement TResult> déclenché par le composant dans une opération asynchrone. (Vous pouvez également utiliser C++ ou Visual Basic pour créer le composant. Les étapes liées à la création des proxys et stubs sont identiques.) Cette procédure pas à pas est basée sur la création d’un exemple de composant in-process Windows Runtime (C++/CX) et permet d’expliquer ses objectifs.
Cette procédure pas à pas comporte ces parties.
- Ici, vous allez créer deux classes Windows Runtime de base. Une classe expose un événement de type Windows.Foundation.TypedEventHandler<TSender, TResult> et l’autre classe est le type retourné à JavaScript comme argument pour TValue. Ces classes ne peuvent pas communiquer avec JavaScript tant que vous n’avez pas effectué les étapes ultérieures.
- Cette application active l’objet de classe principale, appelle une méthode et gère un événement déclenché par le composant Windows Runtime.
- Celles-ci sont requises par les outils qui génèrent les classes proxy et stub.
- Vous utilisez ensuite le fichier IDL pour générer le code source C pour le proxy et le stub.
- Inscrivez les objets proxy-stub afin que le runtime COM puisse les trouver et référencer la DLL proxy-stub dans le projet d’application.
Pour créer le composant Windows Runtime
Dans Visual Studio, dans la barre de menus, choisissez Fichier > nouveau projet. Dans la boîte de dialogue Nouveau projet, développez Windows universel JavaScript>, puis sélectionnez Application vide. Nommez le projet Grille-painApplication, puis choisissez le bouton OK .
Ajoutez un composant Windows Runtime C# à la solution : dans Explorateur de solutions, ouvrez le menu contextuel de la solution, puis choisissez Ajouter > un nouveau projet. Développez Visual C# > Microsoft Store , puis sélectionnez Composant Windows Runtime. Nommez le projet Grille-painComponent, puis choisissez le bouton OK . Grille-painComponent sera l’espace de noms racine pour les composants que vous allez créer dans les étapes ultérieures.
Dans Explorateur de solutions, ouvrez le menu contextuel de la solution, puis choisissez Propriétés. Dans la boîte de dialogue Pages de propriétés, sélectionnez Propriétés de configuration dans le volet gauche, puis, en haut de la boîte de dialogue, définissez Configuration sur Débogage et Plateforme sur x86, x64 ou ARM. Cliquez sur le bouton OK.
Plateforme importante = Tout processeur ne fonctionnera pas, car il n’est pas valide pour la DLL Win32 de code natif que vous allez ajouter à la solution ultérieurement.
Dans Explorateur de solutions, renommez class1.cs pour ToasterComponent.cs afin qu’elle corresponde au nom du projet. Visual Studio renomme automatiquement la classe dans le fichier pour qu’elle corresponde au nouveau nom de fichier.
Dans le fichier .cs, ajoutez une directive using pour l’espace de noms Windows.Foundation pour placer TypedEventHandler dans l’étendue.
Lorsque vous avez besoin de proxys et de stubs, votre composant doit utiliser des interfaces pour exposer ses membres publics. Dans ToasterComponent.cs, définissez une interface pour le grille-pain, et une autre pour le toast produit par le grille-pain.
Notez en C# que vous pouvez ignorer cette étape. Au lieu de cela, créez d’abord une classe, puis ouvrez son menu contextuel et choisissez Refactoriser > l’interface d’extraction. Dans le code généré, donnez manuellement aux interfaces l’accessibilité publique.
public interface IToaster
{
void MakeToast(String message);
event TypedEventHandler<Toaster, Toast> ToastCompletedEvent;
}
public interface IToast
{
String ToastType { get; }
}
L’interface IToast a une chaîne qui peut être récupérée pour décrire le type de toast. L’interface IToaster a une méthode pour rendre toast et un événement pour indiquer que le toast est effectué. Étant donné que cet événement retourne l’élément particulier (autrement dit, type) de toast, il est appelé événement typé.
Ensuite, nous avons besoin de classes qui implémentent ces interfaces et sont publiques et scellées afin qu’elles soient accessibles à partir de l’application JavaScript que vous allez programmer ultérieurement.
public sealed class Toast : IToast
{
private string _toastType;
public string ToastType
{
get
{
return _toastType;
}
}
internal Toast(String toastType)
{
_toastType = toastType;
}
}
public sealed class Toaster : IToaster
{
public event TypedEventHandler<Toaster, Toast> ToastCompletedEvent;
private void OnToastCompleted(Toast args)
{
var completedEvent = ToastCompletedEvent;
if (completedEvent != null)
{
completedEvent(this, args);
}
}
public void MakeToast(string message)
{
Toast toast = new Toast(message);
// Fire the event from a thread-pool thread to enable this thread to continue
Windows.System.Threading.ThreadPool.RunAsync(
(IAsyncAction action) =>
{
if (ToastCompletedEvent != null)
{
OnToastCompleted(toast);
}
});
}
}
Dans le code précédent, nous créons le toast, puis nous filons un élément de travail de pool de threads pour déclencher la notification. Bien que l’IDE suggère d’appliquer le mot clé await à l’appel asynchrone, il n’est pas nécessaire dans ce cas, car la méthode ne fait aucun travail qui dépend des résultats de l’opération.
Notez que l’appel asynchrone dans le code précédent utilise ThreadPool.RunAsync uniquement pour illustrer un moyen simple de déclencher l’événement sur un thread d’arrière-plan. Vous pouvez écrire cette méthode particulière, comme illustré dans l’exemple suivant, et cela fonctionne correctement, car le planificateur de tâches .NET marshale automatiquement les appels asynchrones/await vers le thread d’interface utilisateur.
public async void MakeToast(string message)
{
Toast toast = new Toast(message)
await Task.Delay(new Random().Next(1000));
OnToastCompleted(toast);
}
Si vous générez le projet maintenant, il doit être généré correctement.
Pour programmer l’application JavaScript
Maintenant, nous pouvons ajouter un bouton à l’application JavaScript pour qu’elle utilise la classe que nous venons de définir pour rendre toast. Avant cela, nous devons ajouter une référence au projet Grille-painComponent que nous venons de créer. Dans Explorateur de solutions, ouvrez le menu contextuel du projet Grille-painApplication, choisissez Ajouter > des références, puis choisissez le bouton Ajouter une nouvelle référence. Dans la boîte de dialogue Ajouter une référence, dans le volet gauche sous Solution, sélectionnez le projet de composant, puis dans le volet central, sélectionnez Grille-painComponent. Cliquez sur le bouton OK.
Dans Explorateur de solutions, ouvrez le menu contextuel du projet Grille-painApplication, puis choisissez Définir comme projet de démarrage.
À la fin du fichier default.js, ajoutez un espace de noms pour contenir les fonctions permettant d’appeler le composant et de les appeler. L’espace de noms aura deux fonctions, une pour rendre toast et une pour gérer l’événement toast-complete. L’implémentation de makeToast crée un objet Grille-pain, inscrit le gestionnaire d’événements et rend le toast. Jusqu’à présent, le gestionnaire d’événements ne fait pas beaucoup, comme illustré ici :
WinJS.Namespace.define("ToasterApplication"), {
makeToast: function () {
var toaster = new ToasterComponent.Toaster();
//toaster.addEventListener("ontoastcompletedevent", ToasterApplication.toastCompletedEventHandler);
toaster.ontoastcompletedevent = ToasterApplication.toastCompletedEventHandler;
toaster.makeToast("Peanut Butter");
},
toastCompletedEventHandler: function(event) {
// The sender of the event (the delegate's first type parameter)
// is mapped to event.target. The second argument of the delegate
// is contained in event, which means in this case event is a
// Toast class, with a toastType string.
var toastType = event.toastType;
document.getElementById('toastOutput').innerHTML = "<p>Made " + toastType + " toast</p>";
},
});
La fonction makeToast doit être connectée à un bouton. Mettez à jour default.html pour inclure un bouton et un espace pour générer le résultat de la création d’un toast :
<body>
<h1>Click the button to make toast</h1>
<button onclick="ToasterApplication.makeToast()">Make Toast!</button>
<div id="toasterOutput">
<p>No Toast Yet...</p>
</div>
</body>
Si nous n’utilisions pas de TypedEventHandler, nous pourrions maintenant exécuter l’application sur l’ordinateur local, puis cliquer sur le bouton pour effectuer un toast. Mais dans notre application, rien ne se passe. Pour savoir pourquoi, déboguez le code managé qui déclenche ToastCompletedEvent. Arrêtez le projet, puis, dans la barre de menus, choisissez Déboguer > les propriétés de l’application Grille-pain. Remplacez le type de débogueur par Géré uniquement. Là encore, dans la barre de menus, choisissez Déboguer > des exceptions, puis sélectionnez Exceptions Common Language Runtime.
Exécutez maintenant l’application et cliquez sur le bouton make-toast. Le débogueur intercepte une exception de cast non valide. Bien qu’il ne soit pas évident de son message, cette exception se produit, car les proxys sont manquants pour cette interface.
La première étape de la création d’un proxy et d’un stub pour un composant consiste à ajouter un ID unique ou un GUID aux interfaces. Toutefois, le format GUID à utiliser diffère selon que vous codez en C#, Visual Basic ou un autre langage .NET, ou en C++.
Pour générer des GUID pour les interfaces du composant (C# et d’autres langages .NET)
Dans la barre de menus, choisissez Outils > créer un GUID. Dans la boîte de dialogue, sélectionnez 5. [Guid("xxxxxxxx-xxxx... xxxx")]. Choisissez le bouton Nouveau GUID, puis cliquez sur le bouton Copier.
Revenez à la définition de l’interface, puis collez le nouveau GUID juste avant l’interface IToaster, comme illustré dans l’exemple suivant. (N’utilisez pas le GUID dans l’exemple. Chaque interface unique doit avoir son propre GUID.)
[Guid("FC198F74-A808-4E2A-9255-264746965B9F")]
public interface IToaster...
Ajoutez une directive using pour l’espace de noms System.Runtime.InteropServices.
Répétez ces étapes pour l’interface IToast.
Pour générer des GUID pour les interfaces du composant (C++)
Dans la barre de menus, choisissez Outils > créer un GUID. Dans la boîte de dialogue, sélectionnez 3. STATIC const struct GUID = {...}. Choisissez le bouton Nouveau GUID, puis cliquez sur le bouton Copier.
Collez le GUID juste avant la définition de l’interface IToaster. Une fois que vous avez collé, le GUID doit ressembler à l’exemple suivant. (N’utilisez pas le GUID dans l’exemple. Chaque interface unique doit avoir son propre GUID.)
// {F8D30778-9EAF-409C-BCCD-C8B24442B09B}
static const GUID <<name>> = { 0xf8d30778, 0x9eaf, 0x409c, { 0xbc, 0xcd, 0xc8, 0xb2, 0x44, 0x42, 0xb0, 0x9b } };
Ajoutez une directive using pour Windows.Foundation.Metadata pour placer GuidAttribute dans l’étendue.
À présent, convertissez manuellement le GUID const en GuidAttribute afin qu’il soit mis en forme comme indiqué dans l’exemple suivant. Notez que les accolades sont remplacées par des crochets et des parenthèses, et que le point-virgule de fin est supprimé.
// {E976784C-AADE-4EA4-A4C0-B0C2FD1307C3}
[GuidAttribute(0xe976784c, 0xaade, 0x4ea4, 0xa4, 0xc0, 0xb0, 0xc2, 0xfd, 0x13, 0x7, 0xc3)]
public interface IToaster
{...
Répétez ces étapes pour l’interface IToast.
Maintenant que les interfaces ont des ID uniques, nous pouvons créer un fichier IDL en alimentant le fichier .winmd dans l’outil en ligne de commande winmdidl, puis en générant le code source C pour le proxy et le stub en alimentant ce fichier IDL dans l’outil en ligne de commande MIDL. Visual Studio effectue cette opération pour nous si nous créons des événements post-build, comme indiqué dans les étapes suivantes.
Pour générer le code source proxy et stub
Pour ajouter un événement post-build personnalisé, dans Explorateur de solutions, ouvrez le menu contextuel du projet GridComponent, puis choisissez Propriétés. Dans le volet gauche des pages de propriétés, sélectionnez Événements de génération, puis choisissez le bouton Modifier la post-génération. Ajoutez les commandes suivantes à la ligne de commande post-build. (Le fichier batch doit d’abord être appelé pour définir les variables d’environnement pour rechercher l’outil winmdidl.)
call "$(DevEnvDir)..\..\vc\vcvarsall.bat" $(PlatformName)
winmdidl /outdir:output "$(TargetPath)"
midl /metadata_dir "%WindowsSdkDir%References\CommonConfiguration\Neutral" /iid "$(ProjectDir)$(TargetName)_i.c" /env win32 /h "$(ProjectDir)$(TargetName).h" /winmd "Output\$(TargetName).winmd" /W1 /char signed /nologo /winrt /dlldata "$(ProjectDir)dlldata.c" /proxy "$(ProjectDir)$(TargetName)_p.c" "Output\$(TargetName).idl"
Important pour une configuration de projet ARM ou x64, remplacez le paramètre MIDL /env par x64 ou arm32.
Pour vous assurer que le fichier IDL est régénéré chaque fois que le fichier .winmd est modifié, modifiez l’événement de post-build sur Lorsque la build met à jour la sortie du projet. La page de propriétés Événements de génération doit ressembler à ceci :
Regénérer la solution pour générer et compiler l’IDL.
Vous pouvez vérifier que MIDL a correctement compilé la solution en recherchant Grille-painComponent.h, ToasterComponent_i.c, ToasterComponent_p.c et dlldata.c dans le répertoire du projet Grille-painComponent.
Pour compiler le code proxy et stub dans une DLL
Maintenant que vous disposez des fichiers requis, vous pouvez les compiler pour produire une DLL, qui est un fichier C++. Pour faciliter ce processus, ajoutez un nouveau projet pour prendre en charge la création des proxys. Ouvrez le menu contextuel de la solution Grille-painApplication, puis choisissez Ajouter > un nouveau projet. Dans le volet gauche de la boîte de dialogue Nouveau projet, développez Windows universel Visual >C++>, puis, dans le volet central, sélectionnez DLL (applications UWP). (Notez qu’il ne s’agit pas d’un projet de composant Windows Runtime C++.) Nommez les proxys du projet, puis choisissez le bouton OK . Ces fichiers seront mis à jour par les événements post-build lorsque quelque chose change dans la classe C#.
Par défaut, le projet proxy génère des fichiers .h d’en-tête et des fichiers .cpp C++. Étant donné que la DLL est générée à partir des fichiers générés à partir de MIDL, les fichiers .h et .cpp ne sont pas obligatoires. Dans Explorateur de solutions, ouvrez le menu contextuel pour eux, choisissez Supprimer, puis confirmez la suppression.
Maintenant que le projet est vide, vous pouvez ajouter les fichiers générés par MIDL. Ouvrez le menu contextuel du projet Proxys, puis choisissez Ajouter un > élément existant. Dans la boîte de dialogue, accédez au répertoire du projet ToasterComponent et sélectionnez les fichiers suivants : Grille-painComponent.h, ToasterComponent_i.c, ToasterComponent_p.c et fichiers dlldata.c. Choisissez le bouton Ajouter.
Dans le projet Proxys, créez un fichier .def pour définir les exportations DLL décrites dans dlldata.c. Ouvrez le menu contextuel du projet, puis choisissez Ajouter > un nouvel élément. Dans le volet gauche de la boîte de dialogue, sélectionnez Code, puis dans le volet central, sélectionnez Fichier de définition de module. Nommez le proxy de fichier.def, puis choisissez le bouton Ajouter . Ouvrez ce fichier .def et modifiez-le pour inclure les EXPORTATIONS définies dans dlldata.c :
EXPORTS
DllCanUnloadNow PRIVATE
DllGetClassObject PRIVATE
Si vous générez le projet maintenant, il échoue. Pour compiler correctement ce projet, vous devez modifier la façon dont le projet est compilé et lié. Dans Explorateur de solutions, ouvrez le menu contextuel du projet Proxys, puis choisissez Propriétés. Modifiez les pages de propriétés comme suit.
Dans le volet gauche, sélectionnez Préprocesseur C/C++>, puis, dans le volet droit, sélectionnez Définitions de préprocesseur, choisissez le bouton flèche vers le bas, puis sélectionnez Modifier. Ajoutez ces définitions dans la zone :
WIN32;_WINDOWS
Sous En-têtes précompilés C/C++>, remplacez l’en-tête précompilé par ne pas utiliser d’en-têtes précompilés, puis choisissez le bouton Appliquer.
Sous Linker > General, modifiez La bibliothèque d’importation sur Yes, puis choisissez le bouton Appliquer .
Sous Entrée de l’éditeur > de liens, sélectionnez Dépendances supplémentaires, cliquez sur le bouton flèche vers le bas, puis sélectionnez Modifier. Ajoutez ce texte dans la zone :
rpcrt4.lib;runtimeobject.lib
Ne collez pas ces libs directement dans la ligne de liste. Utilisez la zone d’édition pour vous assurer que MSBuild dans Visual Studio conserve les dépendances supplémentaires appropriées.
Lorsque vous avez apporté ces modifications, choisissez le bouton OK dans la boîte de dialogue Pages de propriétés.
Ensuite, prenez une dépendance sur le projet Grille-painComponent. Cela garantit que le Grille-pain sera généré avant la génération du projet proxy. Cela est nécessaire, car le projet Grille-pain est chargé de générer les fichiers pour générer le proxy.
Ouvrez le menu contextuel du projet Proxys, puis choisissez Dépendances de projet. Activez les cases à cocher pour indiquer que le projet Proxies dépend du projet Grille-painComponent, pour vous assurer que Visual Studio les génère dans l’ordre approprié.
Vérifiez que la solution s’appuie correctement en choisissant Build > Rebuild Solution dans la barre de menus de Visual Studio.
Pour inscrire le proxy et le stub
Dans le projet Grille-painApplication, ouvrez le menu contextuel de package.appxmanifest, puis choisissez Ouvrir avec. Dans la boîte de dialogue Ouvrir avec, sélectionnez Éditeur de texte XML, puis choisissez le bouton OK . Nous allons coller dans un code XML qui fournit une inscription d’extension windows.activateableClass.proxyStub et qui sont basées sur les GUID dans le proxy. Pour rechercher les GUID à utiliser dans le fichier .appxmanifest, ouvrez ToasterComponent_i.c. Recherchez les entrées qui ressemblent à celles de l’exemple suivant. Notez également les définitions pour IToast, IToaster et une troisième interface : un gestionnaire d’événements typé qui a deux paramètres : un grille-pain et un toast. Cela correspond à l’événement défini dans la classe Grille-pain. Notez que les GUID pour IToast et IToaster correspondent aux GUID définis sur les interfaces du fichier C#. Étant donné que l’interface du gestionnaire d’événements typé est générée automatiquement, le GUID de cette interface est également généré automatiquement.
MIDL_DEFINE_GUID(IID, IID___FITypedEventHandler_2_ToasterComponent__CToaster_ToasterComponent__CToast,0x1ecafeff,0x1ee1,0x504a,0x9a,0xf5,0xa6,0x8c,0x6f,0xb2,0xb4,0x7d);
MIDL_DEFINE_GUID(IID, IID___x_ToasterComponent_CIToast,0xF8D30778,0x9EAF,0x409C,0xBC,0xCD,0xC8,0xB2,0x44,0x42,0xB0,0x9B);
MIDL_DEFINE_GUID(IID, IID___x_ToasterComponent_CIToaster,0xE976784C,0xAADE,0x4EA4,0xA4,0xC0,0xB0,0xC2,0xFD,0x13,0x07,0xC3);
À présent, nous copiez les GUID, collez-les dans package.appxmanifest dans un nœud que nous ajoutons et nommeons extensions, puis reformatons-les. L’entrée de manifeste ressemble à l’exemple suivant, mais encore une fois, n’oubliez pas d’utiliser vos propres GUID. Notez que le GUID ClassId dans le code XML est identique à ITypedEventHandler2. Cela est dû au fait que ce GUID est le premier répertorié dans ToasterComponent_i.c. Les GUID ici ne respectent pas la casse. Au lieu de reformater manuellement les GUID pour IToast et IToaster, vous pouvez revenir en arrière dans les définitions d’interface et obtenir la valeur GuidAttribute, qui a le format correct. En C++, il existe un GUID correctement mis en forme dans le commentaire. Dans tous les cas, vous devez reformater manuellement le GUID utilisé pour classId et le gestionnaire d’événements.
<Extensions> <!--Use your own GUIDs!!!-->
<Extension Category="windows.activatableClass.proxyStub">
<ProxyStub ClassId="1ecafeff-1ee1-504a-9af5-a68c6fb2b47d">
<Path>Proxies.dll</Path>
<Interface Name="IToast" InterfaceId="F8D30778-9EAF-409C-BCCD-C8B24442B09B"/>
<Interface Name="IToaster" InterfaceId="E976784C-AADE-4EA4-A4C0-B0C2FD1307C3"/>
<Interface Name="ITypedEventHandler_2_ToasterComponent__CToaster_ToasterComponent__CToast" InterfaceId="1ecafeff-1ee1-504a-9af5-a68c6fb2b47d"/>
</ProxyStub>
</Extension>
</Extensions>
Collez le nœud XML Extensions en tant qu’enfant direct du nœud Package et un homologue de, par exemple, le nœud Ressources.
Avant de continuer, il est important de s’assurer que :
- ProxyStub ClassId est défini sur le premier GUID du fichier ToasterComponent_i.c. Utilisez le premier GUID défini dans ce fichier pour classId. (Il peut s’agir de la même chose que le GUID pour ITypedEventHandler2.)
- Le chemin d’accès est le chemin relatif du package du fichier binaire proxy. (Dans cette procédure pas à pas, proxies.dll se trouve dans le même dossier que ToasterApplication.winmd.)
- Les GUID sont au format correct. (Il est facile de se tromper.)
- Les ID d’interface du manifeste correspondent aux ID d’interface du fichier ToasterComponent_i.c.
- Les noms d’interface sont uniques dans le manifeste. Comme ces valeurs ne sont pas utilisées par le système, vous pouvez choisir les valeurs. Il est recommandé de choisir des noms d’interface qui correspondent clairement aux interfaces que vous avez définies. Pour les interfaces générées, les noms doivent être indicatifs des interfaces générées. Vous pouvez utiliser le fichier ToasterComponent_i.c pour vous aider à générer des noms d’interface.
Si vous essayez d’exécuter la solution maintenant, vous obtenez une erreur indiquant que proxies.dll ne fait pas partie de la charge utile. Ouvrez le menu contextuel du dossier Références dans le projet Grille-painApplication, puis choisissez Ajouter une référence. Cochez la case en regard du projet Proxys. Vérifiez également que la case à cocher en regard de Grille-painComponent est également activée. Cliquez sur le bouton OK.
Le projet doit maintenant être généré. Exécutez le projet et vérifiez que vous pouvez effectuer un toast.