Gewusst wie: Behandeln von Ereignissen mit WRL

Dieses Dokument, wie Windows Runtime C++ Template Library (WRL) zum abonnieren und die Ereignisse von Windows-Runtime zu behandeln Objekts.

Ein grundlegenderes Beispiel, das eine Instanz dieser Komponente erstellt und einen Eigenschaftswert abruft, finden Sie unter Gewusst wie: Aktivieren und Verwenden einer Windows-Runtime-Komponente mit WRL.

Abonnieren und Behandeln von Ereignissen

Die folgenden Schritte starten ABI::Windows::System::Threading::IDeviceWatcher ein - Objekt und Verwendungsereignishandler auf dem Bildschirm stammen weiter.Die IDeviceWatcher-Schnittstelle ermöglicht es Ihnen, Geräte oder im Hintergrund asynchron aufzulisten und Benachrichtigung empfängt, wenn Geräte hinzugefügt, entfernt oder geändert werden.Die Callback-Funktion ist ein wichtiger Teil dieses Beispiels, da sie sie aktiviert, um Ereignishandler anzugeben, die die Ergebnisse des Hintergrundvorgangs verarbeiten.Im Folgenden finden Sie das vollständige Beispiel.

WarnhinweisVorsicht

Obwohl Sie in der Regel WRL in einer Windows Store-App, verwenden Sie dieses Beispiels eine Konsolen-App zur Veranschaulichung.Funktionen wie wprintf_s sind nicht von einer Windows Store-App verfügbar.Weitere Informationen zu den Typen und Funktionen, die Sie in einer Windows Store-App verwenden können, finden Sie unter CRT-Funktionen unterstützt nicht mit /ZW und Win32 und COM für Windows Store-Apps.

  1. Schließen Sie (#include) jede erforderliche Windows-Runtime, WRL oder Standard-C++-Bibliotheksheader ein.

    #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 deklariert die Typen, die erforderlich sind, Geräte aufzulisten.

    Es wird empfohlen, die using namespace-Direktiven in der CPP-Datei verwenden, um den Code verständlicher zu gestalten.

  2. Deklarieren Sie die Variablen für die Anwendung.In diesem Beispiel enthält die Anzahl der aufgelisteten Geräten und Registrierungstoken an, die sie aktivieren, um von den Ereignissen später zu kündigen.

    // 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. Initialisieren Sie Windows-Runtime.

    // Initialize the Windows Runtime.
    RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);
    if (FAILED(initialize))
    {
        return PrintError(__LINE__, initialize);
    }
    
  4. Erstellen Sie ein Event-Objekt, das den Abschluss des Enumerationsprozesses der wichtigsten App synchronisiert.

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

    Dieses Ereignis ist für Demonstration nur als Teil einer Konsolen-App.In diesem Beispiel wird das - Ereignis, um sicherzustellen, dass eine asynchrone Operation vor der App-Beendigungen abgeschlossen hat.In den meisten App warten Sie normalerweise nicht auf asynchrone Vorgänge, um abzuschließen.

  5. Erstellen Sie eine Aktivierungsfactory für die IDeviceWatcher-Schnittstelle erstellt.

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

    Die Windows-Runtime Verwendungsvollqualifizierten namen, von Typen identifizieren.Der RuntimeClass_Windows_Devices_Enumeration_DeviceInformation-Parameter ist eine Zeichenfolge, die von Windows-Runtime bereitgestellt und den erforderlichen Ablaufklassennamen enthält.

  6. Erstellen Sie das IDeviceWatcher-Objekt.

    // Create a IDeviceWatcher object from the factory.
    ComPtr<IDeviceWatcher> watcher;
    hr = watcherFactory->CreateWatcher(&watcher);
    if (FAILED(hr))
    {
        return PrintError(__LINE__, hr);
    }
    
  7. Verwenden Sie die Callback-Funktion, um Added, EnumerationCompleted und Stopped-Ereignisse zu abonnieren.

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

    Der Added-Ereignishandler erhöht die Anzahl der aufgelisteten Geräten.Sie beendet den Enumerationsprozess, nachdem zehn Geräte gefunden werden.

    Der Stopped-Ereignishandler entfernt die Ereignishandler und legt das Abschlussereignis fest.

    Der EnumerationCompleted-Ereignishandler beendet den Enumerationsprozess.Sie behandeln dieses Ereignis, falls es weniger als zehn Geräte gibt.

    TippTipp

    In diesem Beispiel wird ein Lambda-Ausdruck, um die Rückrufe zu definieren.Sie können (Funktionselemente), Funktionsobjekte oder Funktionszeiger std::function-Objekte verwenden.Weitere Informationen zu Lambdaausdrücken finden Sie unter Lambda-Ausdrücke in C++.

  8. Starten Sie den Enumerationsprozess.

    wprintf_s(L"Starting device enumeration...\n");
    hr = watcher->Start();
    if (FAILED(hr))
    {
        return PrintError(__LINE__, hr);
    }
    
  9. Warten Sie den Enumerationsprozess, um eine Meldung abzuschließen und dann zu drucken.Alle ComPtr und RAII-Objekturlaub bewerten und automatisch freigegeben.

    // 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.
    

Hier ist das vollständige Beispiel:

// 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.
*/

Kompilieren des Codes

So kompilieren Sie den Code, ihn kopieren und in einem Visual Studio-Projekt dann einfügen, oder fügen Sie ihn in eine Datei einfügen, die wrl-consume-events.cpp namens und dann den folgenden Befehl in einem Visual Studio-Eingabeaufforderungsfenster ausgeführt.

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

Siehe auch

Konzepte

Windows Runtime C++ Template Library (WRL)