Partager via


Déclenchement d'événements dans les composants Windows Runtime

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 vous souhaitez que JavaScript puisse recevoir l'événement, vous pouvez l'implémenter et/ou le déclencher de plusieurs manières :

  1. (Option 1) Déclencher l'événement via le CoreDispatcher pour marshaler l'événement au contexte de thread JavaScript. Bien que ce soit en général la meilleure option, dans certains cas elle peut ne pas fournir les performances les meilleures.

  2. (Option 2) Utiliser Windows.Foundation.EventHandler<Object> (mais perdre les informations sur les types d'événements). Si l'option 1 n'est pas réalisable ou que ses performances ne sont pas adéquates, ceci constitue la deuxième meilleure option si la perte des informations sur les types d'événements est acceptable.

  3. (Option 3) Créer vos propres objets COM proxy et stub pour le composant. Cette option est la plus difficile à implémenter, mais elle conserve les informations sur les types et peut offrir de meilleures performances que l'option 1 dans les scénarios exigeants.

Si vous déclenchez 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.

Arrière-plan

Tous les composants et applications Windows Runtime sont essentiellement des objets COM, quel que soit le langage utilisé pour les créer. Dans l'API Windows, la plupart des composants sont des objets COM agiles qui peuvent communiquer indifféremment avec les objets sur le thread d'arrière-plan et sur le thread d'interface utilisateur. Si un objet COM ne peut pas être rendu agile, il requiert des objets d'assistance appelés proxies et stubs pour communiquer avec d'autres objets COM via la limite thread d'interface utilisateur-thread d'arrière-plan. (En termes COM, ceci s'appelle la communication entre cloisonnements de threads.)

La plupart des objets dans l'API Windows sont agiles ou ont des proxies et des stubs incorporés. Toutefois, les proxies et les stubs ne peuvent pas être créés pour les types génériques comme Windows.Foundation.TypedEventHandler<TSender, TResult>, car ce ne sont pas des types complets jusqu'à ce que vous fournissiez l'argument de type. C'est uniquement avec les clients JavaScript que l'absence de proxies ou de stubs devient un problème, mais si vous souhaitez que votre composant puisse être utilisé à partir de JavaScript, aussi bien que de C++ ou d'un langage .NET, vous devez utiliser l'une des trois options suivantes.

(Option 1) Déclencher l'événement via le CoreDispatcher

Vous pouvez envoyer des événements de n'importe quel type délégué défini par l'utilisateur à l'aide de Windows.UI.Core.CoreDispatcher, et JavaScript sera en mesure de les recevoir. Si vous n'êtes pas certain de l'option à utiliser, essayez celle-ci en premier. Si la latence entre le déclenchement des événements et la gestion des événements devient un problème, essayez l'une des autres options.

L'exemple suivant indique la manière d'utiliser le CoreDispatcher pour déclencher un événement fortement typé. Notez que l'argument de type est Toast, pas 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 EventHandler<Object>, mais perdre les informations sur les types

Une autre méthode pour envoyer un événement à partir d'un thread d'arrière-plan consiste à utiliser Windows.Foundation.EventHandler<Object> comme type de l'événement. Windows fournit cette instanciation concrète du type générique, ainsi qu'un proxy et un stub. L'inconvénient est que les informations sur les types de vos arguments d'événements et de l'émetteur sont perdues. Les clients C++ et .NET doivent savoir via la documentation vers quel type effectuer un cast lorsque l'événement est reçu. Les clients JavaScript n'ont pas besoin des informations sur les types d'origine. Ils recherchent les propriétés des arguments, selon leurs noms dans les métadonnées.

Cet exemple montre comment utiliser Windows.Foundation.EventHandler<Object> dans 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 consommez cet événement du 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 vos propres proxy/stub

Pour améliorer les performances potentielles sur les types d'événements définis par l'utilisateur qui ont des informations entièrement préservées sur les types, vous devez créer vos propres objets proxy et stub et les inclure dans le package de votre application. En général, vous devez utiliser cette option uniquement dans les rares cas où aucune des deux autres options n'est adéquate. En outre, il n'y a aucune garantie que cette option offrira 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 explique comment utiliser C# pour créer un composant Windows Runtime de base, puis comment utiliser C++ pour créer une DLL pour le proxy et le stub qui permettra à JavaScript de consommer un événement Windows.Foundation.TypedEventHandler<TSender, 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 qui sont liées à la création des proxies et des stubs sont identiques.) Cette procédure pas à pas est basée sur l'article Création d'un exemple de composant in-process Windows Runtime (C++/CX) et permet d'expliquer ses objectifs.

Cette procédure pas à pas inclut les parties suivantes :

  1. Créer le composant Windows Runtime : 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 qui est retourné à JavaScript comme argument pour TValue. Ces classes ne peuvent pas communiquer avec JavaScript jusqu'à ce que vous ayez terminé les étapes suivantes.

  2. Programmer l'application JavaScript : cette application active l'objet de classe principal, appelle une méthode et gère un événement déclenché par le composant Windows Runtime.

  3. Générer les GUID des interfaces du composant: ceux-ci sont requis par les outils qui génèrent les classes proxy et stub.

  4. Générer un fichier IDL pour le composant : vous utilisez ensuite le fichier IDL pour générer le code source C pour le proxy et le stub.

  5. Compiler le code de proxy et de stub dans une DLL

  6. Enregistrer et utiliser la DLL de proxy-stub: enregistrez les objets proxy-stub afin que le runtime COM puisse les trouver, et référencez la DLL de proxy-stub dans le projet d'application.

Pour créer le composant Windows Runtime

  1. Dans Visual Studio, sur la barre de menus, sélectionnez Fichier > Nouveau projet. Dans la boîte de dialogue Nouveau projet, développez JavaScript > Windows Store, puis sélectionnez Application vide. Nommez le projet ToasterApplication, puis cliquez sur le bouton OK.

  2. Ajoutez un composant Windows Runtime C# à la solution : dans l'Explorateur de solutions, ouvrez le menu contextuel de la solution, puis sélectionnez Ajouter > Nouveau projet. Développez Visual C# > Windows Store, puis sélectionnez Composant Windows Runtime. Nommez le projet ToasterComponent, puis cliquez sur le bouton OK. ToasterComponent sera l'espace de noms racine pour les composants que vous créerez dans les étapes ultérieures.

    Dans l'Explorateur de solutions, ouvrez le menu contextuel de la solution, puis sélectionnez 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éboguer et Plateforme sur x86, x64 ou ARM. Cliquez sur le bouton OK.

    Important

    Plateforme = Any CPU ne fonctionnera pas, car cette option n'est pas valide pour la DLL Win32 de code natif que vous ajouterez à la solution ultérieurement.

  3. Dans l'Explorateur de solutions, remplacez le nom class1.cs par ToasterComponent.cs afin qu'il corresponde au nom du projet. Visual Studio renomme automatiquement la classe dans le fichier pour qu'elle corresponde au nouveau nom de fichier.

  4. Dans le fichier .cs, ajoutez une directive using pour l'espace de noms Windows.Foundation pour placer TypedEventHandler dans la portée.

  5. Lorsque vous avez besoin de proxies et de stubs, votre composant doit utiliser des interfaces pour exposer ses membres publics. Dans ToasterComponent.cs, définissez une interface pour le générateur de toasts, et une autre pour le toast que le générateur produit.

    Notes

    En C#, vous pouvez ignorer cette étape.À la place, créez d'abord une classe, puis ouvrez son menu contextuel et sélectionnez Refactoriser > Extraire l'interface.Dans le code généré, donnez manuellement aux interfaces une 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 dispose d'une méthode pour créer un toast, et d'un événement pour indiquer que le toast est créé. Comme cet événement retourne le type particulier du toast, il est appelé événement typé.

  6. Ensuite, nous avons besoin de classes qui implémentent ces interfaces, et qui soient publiques et verrouillées afin qu'elles soient accessibles depuis l'application JavaScript que vous programmerez 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 accélérons un élément de travail de pool de threads pour déclencher la notification. Bien que l'IDE puisse suggérer que vous appliquez le mot clé await à l'appel asynchrone, il n'est pas nécessaire dans ce cas, parce que la méthode n'effectue aucun travail dépendant des résultats de l'opération.

    Important

    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 indiqué dans l'exemple suivant, et elle s'exécutera correctement, car le planificateur de tâches .NET marshale automatiquement les appels asynchrones/d'attente 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 à présent, il doit être généré correctement.

Pour programmer l'application JavaScript

  1. Maintenant nous pouvons ajouter un bouton à l'application JavaScript pour qu'elle utilise la classe que nous venons de définir pour créer un toast. Avant de le faire, nous devons ajouter une référence au projet ToasterComponent que nous venons de créer. Dans l'Explorateur de solutions, ouvrez le menu contextuel pour le projet ToasterApplication, sélectionnez Ajouter > Références, puis sélectionnez 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 ToasterComponent. Cliquez sur le bouton OK.

  2. Dans l'Explorateur de solutions, ouvrez le menu contextuel du projet ToasterApplication, puis sélectionnez Définir comme projet de démarrage.

  3. À la fin du fichier default.js, ajoutez un espace de noms pour contenir les fonctions permettant d'appeler le composant et d'être rappelé par celui-ci. L'espace de noms possède deux fonctions, une pour créer un toast et une pour gérer l'événement de fin de toast. L'implémentation de makeToast crée un objet Toaster, inscrit le gestionnaire d'événements et crée le toast. Jusqu'à présent, le gestionnaire d'événements ne fait pas grand-chose, comme illustré ci-après :

    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 event in this case is a 
                // Toast class, with a toastType string.
                var toastType = event.toastType;
    
                document.getElementById("toasterOutput").innerHTML = "<p>Made " + toastType + " toast</p>";
            },
    
        }); 
    
  4. La fonction makeToast doit être rattachée à un bouton. Mettez à jour le fichier default.html pour inclure un bouton et un espace pour sortir le résultat de la création du 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 un TypedEventHandler, nous pourrions maintenant exécuter l'application sur l'ordinateur local et cliquer sur le bouton pour créer un toast. Mais dans notre application, rien ne se produit. Pour savoir pourquoi, déboguons le code managé qui déclenche l'événement ToastCompletedEvent. Arrêtez le projet, puis dans la barre de menus, sélectionnez Déboguer > Propriétés de l'application Toaster. Attribuez la valeur Managé uniquement à Type de débogueur. De nouveau sur la barre de menus, sélectionnez Déboguer > Exceptions, puis sélectionnez Exceptions Common Language Runtime.

    Maintenant, exécutez l'application et cliquez sur le bouton de création de toast. Le débogueur intercepte une exception de cast non valide. Bien que cela ne soit pas évident au vu de son message, cette exception se produit parce que les proxies sont manquants pour cette interface.

    Fenêtre d'erreur du débogueur indiquant qu'il manque un proxy

La première étape de la création d'un proxy et d'un stub pour un composant consiste à ajouter un identificateur unique ou GUID aux interfaces. Toutefois, le format de GUID à utiliser diffère selon que vous codez en C#, en Visual Basic ou autre langage .NET, ou en C++.

Pour générer des GUID pour les interfaces du composant

  • Pour C#, Visual Basic ou autres langages .NET :

    1. Dans la barre de menus, sélectionnez Outils > Créer un Guid. Dans la boîte de dialogue, sélectionnez 5. [Guid(“xxxxxxxx-xxxx...xxxx)]. Sélectionnez le bouton Nouveau GUID, puis cliquez sur le bouton Copier.

    2. Revenez à la définition d'interface, puis collez le nouveau GUID juste avant l'interface IToaster, comme indiqué dans l'exemple suivant. N'utilisez pas le GUID de l'exemple. Chaque interface unique doit avoir son propre GUID.)

      [Guid("FC198F74-A808-4E2A-9255-264746965B9F")]
          public interface IToaster...
      
    3. Ajoutez une directive using pour l'espace de noms System.Runtime.InteropServices.

    4. Répétez ces étapes pour l'interface IToast.

  • Pour C++ :

    1. Dans la barre de menus, sélectionnez Outils > Créer un Guid. Dans la boîte de dialogue, sélectionnez 3. GUID struct const static = { ... }. Sélectionnez le bouton Nouveau GUID, puis cliquez sur le bouton Copier.

      Générateur GUID dans Visual Studio

    2. Collez le GUID juste avant la définition d'interface IToaster. Une fois collé, le GUID doit ressembler à l'exemple suivant. N'utilisez pas le GUID de 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 } };
      
    3. Ajoutez une directive using pour Windows.Foundation.Metadata pour placer GuidAttribute dans la portée.

    4. Convertissez ensuite manuellement le GUID const en un GuidAttribute afin qu'il soit mis en forme comme illustré 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
          {...
      
    5. Répétez ces étapes pour l'interface IToast.

Maintenant que les interfaces ont des identificateurs uniques, nous pouvons créer un fichier IDL en acheminant le fichier .winmd dans l'outil de ligne de commande winmdidl, puis générer le code source C pour le proxy et le stub en acheminant ce fichier IDL dans l'outil de ligne de commande MIDL. Visual Studio le fait pour nous si nous créons des événements post-build comme indiqué dans les étapes suivantes.

Pour générer le code source du proxy et du stub

  1. Pour ajouter un événement post-build personnalisé, dans l'Explorateur de solutions, ouvrez le menu contextuel du projet ToasterComponent, puis sélectionnez Propriétés. Dans le volet gauche des pages de propriétés, sélectionnez Événements de build, puis sélectionnez le bouton Modifier post-build. Ajoutez les commandes suivantes à la ligne de commande post-build. (Le fichier batch doit être appelé en premier afin de 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 /env MIDL par x64 ou arm32.

  2. Pour vous assurer que le fichier IDL est régénéré chaque fois que le fichier .winmd est modifié, remplacez Exécuter l'événement post-build par Lorsque la build met à jour la sortie du projet.

    La page de propriétés Événements de build doit ressembler à ceci :

    Étapes post-build dans la page des propriétés Visual Studio

  3. Régénérez la solution pour générer et compiler le fichier IDL.

    Vous pouvez vérifier que MIDL a correctement compilé la solution en recherchant ToasterComponent.h, ToasterComponent_i.c, ToasterComponent_p.c et dlldata.c dans le répertoire du projet ToasterComponent.

Pour compiler le code de proxy et de stub dans une DLL

  1. Maintenant que vous avez les fichiers requis, vous pouvez les compiler pour produire une DLL, qui est un fichier C++. Pour rendre cette opération aussi simple que possible, ajoutez un nouveau projet pour prendre en charge la génération des proxies. Ouvrez le menu contextuel de la solution ToasterApplication, puis sélectionnez Ajouter > Nouveau projet. Dans le volet gauche de la boîte de dialogue Nouveau projet, développez Visual C++ > Windows Store, puis, dans le volet central, sélectionnez DLL (applications Windows Store). (Notez que ce n'est PAS un projet Windows Runtime Component C++.) Nommez le projet Proxies, puis cliquez sur le bouton OK. Ces fichiers sont mis à jour par les événements post-build lorsque quelque chose change dans la classe C#.

  2. Par défaut, le projet Proxies génère des fichiers d'en-tête .h et des fichiers C++ .cpp. Étant donné que la DLL est générée à partir des fichiers produits avec MIDL, les fichiers .h et .cpp ne sont pas requis. Dans l'Explorateur de solutions, ouvrez le menu contextuel correspondant, cliquez sur Supprimer, puis confirmez la suppression.

  3. Maintenant que le projet est vide, vous pouvez ajouter à nouveau les fichiers générés par MIDL. Ouvrez le menu contextuel du projet Proxies, puis sélectionnez Ajouter > Élément existant. Dans la boîte de dialogue, naviguez jusqu'au répertoire du projet ToasterComponent et sélectionnez les fichiers suivants : ToasterComponent.h, ToasterComponent_i.c, ToasterComponent_p.c et dlldata.c. Cliquez sur le bouton Ajouter.

  4. Dans le projet Proxies, créez un fichier .def pour définir les exportations de DLL décrites dans dlldata.c. Ouvrez le menu contextuel du projet, puis sélectionnez Ajouter > 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 fichier proxies.def, puis cliquez sur le bouton Ajouter. Ouvrez ce fichier .def et modifiez-le pour inclure les EXPORTATIONS définies dans dlldata.c :

    EXPORTS
        DllCanUnloadNow         PRIVATE
        DllGetClassObject       PRIVATE
    
  5. Si vous générez le projet maintenant, il échouera. Pour compiler correctement ce projet, vous devez modifier la façon dont le projet est compilé et lié. Dans l'Explorateur de solutions, ouvrez le menu contextuel du projet Proxies, puis sélectionnez Propriétés. Modifiez les pages de propriétés comme suit :

    • Dans le volet gauche, sélectionnez C/C++ > Préprocesseur, puis, dans le volet droit, sélectionnez Définitions de préprocesseur, cliquez sur le bouton de flèche vers le bas, puis sélectionnez Edition. Ajoutez ces définitions dans la zone :

      WIN32;_WINDOWS
      
    • Sous C/C++ > En-têtes précompilés, modifiez En-tête précompilé sur Sans utiliser les en-têtes précompilés, puis cliquez sur le bouton Appliquer.

    • Sous Éditeur de liens > Général, affectez la valeur Oui à Bibliothèque d'importation ignorée, puis cliquez sur le bouton Appliquer.

    • Sous Éditeur de liens > Entrée, sélectionnez Dépendances supplémentaires,, cliquez sur le bouton de flèche vers le bas, puis sélectionnez Edition. Ajoutez ce texte dans la zone :

      rpcrt4.lib;runtimeobject.lib
      

      Ne collez pas ces bibliothèques directement dans la ligne de liste. Utilisez la zone d'édition pour vous assurer que MSBuild dans Visual Studio met à jour les dépendances supplémentaires appropriées.

    Lorsque vous avez apporté ces modifications, cliquez sur le bouton OK dans la boîte de dialogue Pages de propriétés.

  6. Ensuite, prenez une dépendance sur le projet ToasterComponent. Cela garantit que le générateur de toasts sera généré avant le projet de proxy. Ceci est obligatoire, parce que le projet de générateur de toasts est chargé de générer les fichiers permettant de générer le proxy.

    Ouvrez le menu contextuel du projet Proxies, puis sélectionnez Dépendances du projet. Activez les cases à cocher pour indiquer que le projet Proxies dépend du projet ToasterComponent, afin de vous assurer que Visual Studio les génère dans l'ordre adéquat.

  7. Vérifiez que la solution est correctement générée en sélectionnant Générer > Régénérer la solution dans la barre de menus de Visual Studio.

Pour enregistrer le proxy et le stub

  1. Dans le projet ToasterApplication, ouvrez le menu contextuel de package.appxmanifest, puis sélectionnez Ouvrir avec. Dans la boîte de dialogue Ouvrir avec, sélectionnez Éditeur XML (Texte), puis cliquez sur le bouton OK. Nous allons coller du code XML qui fournit une inscription de l'extension windows.activatableClass.proxyStub et est basé 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 de IToast, IToaster, et une troisième interface : un gestionnaire d'événements typés possédant deux paramètres : Toaster et Toast. Cela correspond à l'événement défini dans la classe Toaster. Notez que les GUID de IToast et IToaster correspondent aux GUID définis sur les interfaces dans le fichier C#. Étant donné que l'interface de gestionnaire d'événements typés est créée automatiquement, le GUID de cette interface l'est également.

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

    Maintenant, nous copions les GUID, nous les collons dans package.appxmanifest dans un nœud que nous ajoutons et nommons Extensions, puis nous les reformatons. 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 fichier XML est identique à ITypedEventHandler2. C'est parce 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 de IToast et IToaster, vous pouvez retourner 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 le 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 en tant qu'homologue du nœud Resources, par exemple.

  2. Avant de continuer, il est important de vérifier que :

    • Le ClassId ProxyStub a pour valeur le premier GUID dans le fichier ToasterComponent_i.c. Utilisez le premier GUID défini dans ce fichier pour le classId. (Cela peut être le même que le GUID pour ITypedEventHandler2.)

    • Le Path est le chemin d'accès relatif du package du fichier binaire de proxy. (Dans cette procédure pas à pas, proxies.dll se trouve dans le même dossier que ToasterApplication.winmd.)

    • Les GUID ont le format correct. (Il est facile de se tromper.)

    • Les ID d'interface dans le manifeste correspondent aux IID dans le fichier ToasterComponent_i.c.

    • Les noms d'interface sont uniques dans le manifeste. Étant donné que ceux-ci ne sont pas utilisés par le système, vous pouvez choisir les valeurs. Il est conseillé de choisir des noms d'interface qui correspondent clairement aux interfaces que vous avez définies. Pour des interfaces générées, les noms doivent évoquer les interfaces générées. Vous pouvez utiliser le fichier ToasterComponent_i.c pour vous aider à générer des noms d'interface.

  3. Si vous essayez à présent d'exécuter la solution, vous obtiendrez 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 ToasterApplication, puis sélectionnez Ajouter une référence. Activez la case à cocher en regard du projet Proxies. En outre, assurez-vous que la case à cocher en regard de ToasterComponent est également cochée. Cliquez sur le bouton OK.

    À présent, le projet doit se générer. Exécutez le projet et vérifiez que vous pouvez créer un toast.