Partager via


Comment : gérer les événements à l'aide de WRL

Ce document montre comment utiliser Bibliothèque de modèles Windows Runtime C++ (WRL) pour s'abonner à et pour gérer les événements d'un objet d' Windows Runtime .

Pour un exemple plus fondamental qui crée une instance de ce composant et récupère une valeur de propriété, consultez Comment : activer et utiliser un composant Windows Runtime Component à l'aide de WRL.

Abonner à et gérer des événements

Les étapes suivantes démarrent un objet d' ABI::Windows::System::Threading::IDeviceWatcher et les gestionnaires d'événements d'utilisation du moniteur progression.L'interface d' IDeviceWatcher vous permet d'énumérer des périphériques de façon asynchrone, ou en arrière-plan, et reçoit une notification lorsque les appareils sont ajoutés, déplacés, ou modifiés.La fonction d' Rappel est une partie importante de cet exemple car elle lui permet de spécifier les gestionnaires d'événements qui gèrent les résultats de l'opération d'arrière-plan.Voici un exemple de code complet :

Mise en gardeAttention

Bien que vous utilisez en général WRL dans une application d' Windows Store, cet exemple utilise une application console pour l'illustration.Les fonctions telles qu' wprintf_s sont pas disponibles d'une application d' Windows Store .Pour plus d'informations sur les types et les fonctions que vous pouvez utiliser dans une application d' Windows Store, consultez Fonctions CRT non prises en charge avec /ZW et Win32 et COM pour les applications de mémoire windows.

  1. Incluez (#include) tous les Windows Runtimerequis, WRL, ou en-tête standard de bibliothèque C++.

    #include <Windows.Devices.Enumeration.h>
    #include <wrl/event.h>
    #include <stdio.h>
    
    using namespace ABI::Windows::Devices::Enumeration;
    using namespace ABI::Windows::Foundation;
    using namespace Microsoft::WRL;
    using namespace Microsoft::WRL::Wrappers;
    

    Windows.Devices.Enumeration.h déclare les types requis pour énumérer des périphériques.

    Nous vous recommandons d'utiliser la directive d' using namespace dans votre fichier .cpp pour rendre le code plus lisible.

  2. Déclarez les variables locales pour l'application.Cet exemple contient le nombre du nombre d'appareils énumérés et de jetons d'alignement qui lui permettent d'annuler un abonnement ultérieurement des événements.

    // Counts the number of enumerated devices.
    unsigned int deviceCount = 0;
    
    // Event registration tokens that enable us to later unsubscribe from events.
    EventRegistrationToken addedToken;
    EventRegistrationToken stoppedToken;
    EventRegistrationToken enumCompletedToken;
    
  3. Initialisez Windows Runtime.

    // Initialize the Windows Runtime.
    RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);
    if (FAILED(initialize))
    {
        return PrintError(__LINE__, initialize);
    }
    
  4. Créez un objet d' Événement qui synchronise l'achèvement du processus d'énumération à l'application principale.

    // Create an event that is set after device enumeration completes. We later use this event to wait for the timer to complete. 
    // This event is for demonstration only in a console app. In most apps, you typically don't wait for async operations to complete.
    Event enumerationCompleted(CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, WRITE_OWNER | EVENT_ALL_ACCESS));
    hr = threadCompleted.IsValid() ? S_OK : HRESULT_FROM_WIN32(GetLastError());
    if (FAILED(hr))
    {
        return PrintError(__LINE__, hr);
    }
    

    [!REMARQUE]

    Cet événement est pour une démonstration uniquement dans le cadre d'une application de console.Cet exemple utilise l'événement pour vérifier qu'une opération async se termine avant les sorties d'application.Dans la plupart des applications, vous devez généralement n'attendez pas d'opérations async se termine.

  5. Créez une fabrique de lancement pour l'interface d' IDeviceWatcher .

    // Get the activation factory for the IDeviceWatcher interface.
    ComPtr<IDeviceInformationStatics> watcherFactory;
    HRESULT hr = ABI::Windows::Foundation::GetActivationFactory(HStringReference(RuntimeClass_Windows_Devices_Enumeration_DeviceInformation).Get(), &watcherFactory);
    if (FAILED(hr))
    {
        return PrintError(__LINE__, hr);
    }
    

    Les noms complets des utilisations d' Windows Runtime pour identifier des types.Le paramètre d' RuntimeClass_Windows_Devices_Enumeration_DeviceInformation est une chaîne fournie par Windows Runtime et contient le nom de classe d'exécution obligatoire.

  6. Créez l'objet d' IDeviceWatcher .

    // Create a IDeviceWatcher object from the factory.
    ComPtr<IDeviceWatcher> watcher;
    hr = watcherFactory->CreateWatcher(&watcher);
    if (FAILED(hr))
    {
        return PrintError(__LINE__, hr);
    }
    
  7. Utilisez la fonction d' Callback pour s'abonner à Added, à EnumerationCompleted, et aux événements d' Stopped .

    // Subscribe to the Added event.
    hr = watcher->add_Added(Callback<AddedHandler>([&deviceCount](IDeviceWatcher* watcher, IDeviceInformation*) -> HRESULT
    {
        // Print a message and increment the device count.
        // When we reach 10 devices, stop enumerating devices.
        wprintf_s(L"Added device...\n");
        deviceCount++;
        if (deviceCount == 10)
        {
            return watcher->Stop();
        }
        return S_OK;
    
    }).Get(), &addedToken);
    if (FAILED(hr))
    {
        return PrintError(__LINE__, hr);
    }
    
    hr = watcher->add_Stopped(Callback<StoppedHandler>([=, &enumerationCompleted](IDeviceWatcher* watcher, IInspectable*) -> HRESULT
    {
        wprintf_s(L"Device enumeration stopped.\nRemoving event handlers...");
    
        // Unsubscribe from the events. This is shown for demonstration.
        // The need to remove event handlers depends on the requirements of 
        // your app. For instance, if you only need to handle an event for 
        // a short period of time, you might remove the event handler when you
        // no longer need it. If you handle an event for the duration of the app,
        // you might not need to explicitly remove it.
        HRESULT hr1 = watcher->remove_Added(addedToken);
        HRESULT hr2 = watcher->remove_Stopped(stoppedToken);
        HRESULT hr3 = watcher->remove_EnumerationCompleted(enumCompletedToken);
    
        // Set the completion event and return.
        SetEvent(enumerationCompleted.Get());
    
        return FAILED(hr1) ? hr1 : FAILED(hr2) ? hr2 : hr3;
    
    }).Get(), &stoppedToken);
    if (FAILED(hr))
    {
        return PrintError(__LINE__, hr);
    }
    
    // Subscribe to the EnumerationCompleted event.
    hr = watcher->add_EnumerationCompleted(Callback<EnumerationCompletedHandler>([](IDeviceWatcher* watcher, IInspectable*) -> HRESULT
    {
        wprintf_s(L"Enumeration completed.\n");
    
        return watcher->Stop();
    
    }).Get(), &enumCompletedToken);
    if (FAILED(hr))
    {
        return PrintError(__LINE__, hr);
    }
    

    Le gestionnaire d'événements d' Added incrémente le nombre d'appareils énumérés.Arrête le processus d'énumération une fois dix appareils sont trouvés.

    Le gestionnaire d'événements d' Stopped supprime les gestionnaires d'événements et définit l'événement d'achèvement.

    Le gestionnaire d'événements d' EnumerationCompleted arrête le processus d'énumération.Nous gérons cet événement au cas où il y aurait moins de dix appareils.

    ConseilConseil

    Cet exemple utilise une expression lambda pour définir les rappels.Vous pouvez également utiliser des objets de fonction (functors), les pointeurs fonction, les objets ou d' std::function .Pour plus d'informations sur les expressions lambda, consultez Expressions lambda en C++.

  8. Démarrez le processus d'énumération.

    wprintf_s(L"Starting device enumeration...\n");
    hr = watcher->Start();
    if (FAILED(hr))
    {
        return PrintError(__LINE__, hr);
    }
    
  9. Attendez le processus d'énumération pour terminer puis imprimer un message.Tous les ComPtr et les objets RAII de la portée et est libéré automatiquement.

    // Wait for the operation to complete.
    WaitForSingleObjectEx(enumerationCompleted.Get(), INFINITE, FALSE);
    
    wprintf_s(L"Enumerated %u devices.\n", deviceCount);
    
    // All smart pointers and RAII objects go out of scope here.
    

Voici l'exemple complet :

// wrl-consume-events.cpp
// compile with: runtimeobject.lib
#include <Windows.Devices.Enumeration.h>
#include <wrl/event.h>
#include <stdio.h>

using namespace ABI::Windows::Devices::Enumeration;
using namespace ABI::Windows::Foundation;
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;

// Prints an error string for the provided source code line and HRESULT
// value and returns the HRESULT value as an int.
int PrintError(unsigned int line, HRESULT hr)
{
    wprintf_s(L"ERROR: Line:%d HRESULT: 0x%X\n", line, hr);
    return hr;
}

int wmain()
{
    // Type define the event handler types to make the code more readable.
    typedef __FITypedEventHandler_2_Windows__CDevices__CEnumeration__CDeviceWatcher_Windows__CDevices__CEnumeration__CDeviceInformation AddedHandler;
    typedef __FITypedEventHandler_2_Windows__CDevices__CEnumeration__CDeviceWatcher_IInspectable EnumerationCompletedHandler;
    typedef __FITypedEventHandler_2_Windows__CDevices__CEnumeration__CDeviceWatcher_IInspectable StoppedHandler;

    // Counts the number of enumerated devices.
    unsigned int deviceCount = 0;

    // Event registration tokens that enable us to later unsubscribe from events.
    EventRegistrationToken addedToken;
    EventRegistrationToken stoppedToken;
    EventRegistrationToken enumCompletedToken;

    // Initialize the Windows Runtime.
    RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);
    if (FAILED(initialize))
    {
        return PrintError(__LINE__, initialize);
    }

    // Create an event that is set after device enumeration completes. We later use this event to wait for the timer to complete. 
    // This event is for demonstration only in a console app. In most apps, you typically don't wait for async operations to complete.
    Event enumerationCompleted(CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, WRITE_OWNER | EVENT_ALL_ACCESS));
    hr = threadCompleted.IsValid() ? S_OK : HRESULT_FROM_WIN32(GetLastError());
    if (FAILED(hr))
    {
        return PrintError(__LINE__, hr);
    }

    // Get the activation factory for the IDeviceWatcher interface.
    ComPtr<IDeviceInformationStatics> watcherFactory;
    HRESULT hr = ABI::Windows::Foundation::GetActivationFactory(HStringReference(RuntimeClass_Windows_Devices_Enumeration_DeviceInformation).Get(), &watcherFactory);
    if (FAILED(hr))
    {
        return PrintError(__LINE__, hr);
    }

    // Create a IDeviceWatcher object from the factory.
    ComPtr<IDeviceWatcher> watcher;
    hr = watcherFactory->CreateWatcher(&watcher);
    if (FAILED(hr))
    {
        return PrintError(__LINE__, hr);
    }

    // Subscribe to the Added event.
    hr = watcher->add_Added(Callback<AddedHandler>([&deviceCount](IDeviceWatcher* watcher, IDeviceInformation*) -> HRESULT
    {
        // Print a message and increment the device count.
        // When we reach 10 devices, stop enumerating devices.
        wprintf_s(L"Added device...\n");
        deviceCount++;
        if (deviceCount == 10)
        {
            return watcher->Stop();
        }
        return S_OK;

    }).Get(), &addedToken);
    if (FAILED(hr))
    {
        return PrintError(__LINE__, hr);
    }

    hr = watcher->add_Stopped(Callback<StoppedHandler>([=, &enumerationCompleted](IDeviceWatcher* watcher, IInspectable*) -> HRESULT
    {
        wprintf_s(L"Device enumeration stopped.\nRemoving event handlers...");

        // Unsubscribe from the events. This is shown for demonstration.
        // The need to remove event handlers depends on the requirements of 
        // your app. For instance, if you only need to handle an event for 
        // a short period of time, you might remove the event handler when you
        // no longer need it. If you handle an event for the duration of the app,
        // you might not need to explicitly remove it.
        HRESULT hr1 = watcher->remove_Added(addedToken);
        HRESULT hr2 = watcher->remove_Stopped(stoppedToken);
        HRESULT hr3 = watcher->remove_EnumerationCompleted(enumCompletedToken);

        // Set the completion event and return.
        SetEvent(enumerationCompleted.Get());

        return FAILED(hr1) ? hr1 : FAILED(hr2) ? hr2 : hr3;

    }).Get(), &stoppedToken);
    if (FAILED(hr))
    {
        return PrintError(__LINE__, hr);
    }

    // Subscribe to the EnumerationCompleted event.
    hr = watcher->add_EnumerationCompleted(Callback<EnumerationCompletedHandler>([](IDeviceWatcher* watcher, IInspectable*) -> HRESULT
    {
        wprintf_s(L"Enumeration completed.\n");

        return watcher->Stop();

    }).Get(), &enumCompletedToken);
    if (FAILED(hr))
    {
        return PrintError(__LINE__, hr);
    }

    wprintf_s(L"Starting device enumeration...\n");
    hr = watcher->Start();
    if (FAILED(hr))
    {
        return PrintError(__LINE__, hr);
    }

    // Wait for the operation to complete.
    WaitForSingleObjectEx(enumerationCompleted.Get(), INFINITE, FALSE);

    wprintf_s(L"Enumerated %u devices.\n", deviceCount);

    // All smart pointers and RAII objects go out of scope here.
}
/*
Sample output:
Starting device enumeration...
Added device...
Added device...
Added device...
Added device...
Added device...
Added device...
Added device...
Added device...
Added device...
Added device...
Device enumeration stopped.
Removing event handlers...
Enumerated 10 devices.
*/

Compilation du code

Pour compiler le code, copiez-le puis collez-le dans un projet Visual Studio, ou collez-le dans un fichier nommé wrl-consume-events.cpp puis exécutez la commande suivante dans une fenêtre d'invite de commandes de Visual Studio.

cl.exe wrl-consume-events.cpp runtimeobject.lib

Voir aussi

Concepts

Bibliothèque de modèles Windows Runtime C++ (WRL)