Udostępnij za pośrednictwem


Porady: obsługa zdarzeń z użyciem biblioteki WRL

Dokument ten pokazuje sposób używania Biblioteka szablonów C++ środowiska wykonawczego systemu Windows (WRL) subskrybować i obsługi zdarzeń z Środowisko wykonawcze systemu Windows obiektu.

Na przykład bardziej podstawową, która tworzy wystąpienie składnika i pobiera wartość właściwości, zobacz Porady: uaktywnianie składnika środowiska wykonawczego systemu Windows za pomocą biblioteki WRL i korzystanie z niego.

Subskrybowanie i obsługa zdarzeń

Następujące kroki start ABI::Windows::System::Threading::IDeviceWatcher object i użyć obsługi zdarzeń do monitorowania postępu.IDeviceWatcher Interfejs umożliwia wyliczanie urządzeń asynchronicznie lub w tle i otrzymać powiadomienie, gdy urządzenia są dodawane, usuwane lub zmieniony.Wywołania zwrotnego funkcja jest ważną częścią w tym przykładzie, ponieważ umożliwia jej do określenia procedury obsługi zdarzeń, które przetwarzają wyniki operacji tła.Pełny przykład poniżej.

Informacje dotyczące przestrogiPrzestroga

Chociaż zazwyczaj używają WRL w Windows Store aplikacji, w tym przykładzie używa aplikacja konsoli dla celów ilustracyjnych.Funkcji, takich jak wprintf_s nie są dostępne z Windows Store aplikacji.Aby uzyskać więcej informacji na temat typów i funkcji, których można używać w Windows Store aplikacji, zobacz CRT funkcje nie obsługiwane przez /ZW i aplikacje Win32 i COM dla Sklepu Windows.

  1. Obejmują (#include) wszystkie wymagane Środowisko wykonawcze systemu Windows, WRL, lub standard C++ library nagłówków.

    #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 oświadcza, typy, które są wymagane do wyliczenia urządzeń.

    Firma Microsoft zaleca, aby wykorzystać using namespace w pliku cpp, aby zwiększyć czytelność kodu w dyrektywie.

  2. Deklaruje zmienne lokalne dla aplikacji.W tym przykładzie zawiera liczbę wyliczanych urządzeń i tokeny rejestracji, które umożliwiają później subskrypcję zdarzeń.

    // 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. Inicjowanie Środowisko wykonawcze systemu Windows.

    // Initialize the Windows Runtime.
    RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);
    if (FAILED(initialize))
    {
        return PrintError(__LINE__, initialize);
    }
    
  4. Tworzenie zdarzenia obiektu, która synchronizuje zakończenia procesu wyliczenie do głównej aplikacji.

    // 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));
    HRESULT hr = enumerationCompleted.IsValid() ? S_OK : HRESULT_FROM_WIN32(GetLastError());
    if (FAILED(hr))
    {
        return PrintError(__LINE__, hr);
    }
    

    [!UWAGA]

    To zdarzenie jest wykazanie tylko jako część aplikacji konsoli.W tym przykładzie użyto zdarzenia do zapewnienia, że operacji asynchronicznej zostanie zakończony przed zamyka aplikację.W większości aplikacji należy zwykle nie Czekaj na asynchroniczne czynności do wykonania.

  5. Utworzyć fabryki aktywacji dla IDeviceWatcher interfejsu.

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

    Środowisko wykonawcze systemu Windows Używa nazwy w pełni kwalifikowane do identyfikacji typów.RuntimeClass_Windows_Devices_Enumeration_DeviceInformation Parametr jest ciągiem, który jest udostępniany przez Środowisko wykonawcze systemu Windows i zawiera nazwę klasy wymagane w czasie wykonywania.

  6. Tworzenie IDeviceWatcher obiektu.

    // Create a IDeviceWatcher object from the factory.
    ComPtr<IDeviceWatcher> watcher;
    hr = watcherFactory->CreateWatcher(&watcher);
    if (FAILED(hr))
    {
        return PrintError(__LINE__, hr);
    }
    
  7. Użycie Callback funkcja subskrybować Added, EnumerationCompleted, i Stopped zdarzenia.

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

    Added Programu obsługi zdarzeń zwiększa liczbę urządzeń wyliczanych.Zatrzymuje proces wyliczenie po dziesięciu urządzenia znajdują się.

    Stopped Programu obsługi zdarzeń usuwa programy obsługi zdarzeń i ustawia zdarzeń zakończenia.

    EnumerationCompleted Programu obsługi zdarzeń zatrzymuje proces wyliczania.W przypadku urządzeń mniej niż dziesięć, obsługi tego zdarzenia.

    PoradaPorada

    W tym przykładzie wyrażenie lambda do definiowania wywołania zwrotne.Można również użyć funkcji obiektów (funktory), wskaźników funkcji lub std::function obiektów.Aby uzyskać więcej informacji na temat wyrażeń lambda, zobacz Wyrażenia lambda w języku C++.

  8. Rozpocznij proces wyliczania.

    wprintf_s(L"Starting device enumeration...\n");
    hr = watcher->Start();
    if (FAILED(hr))
    {
        return PrintError(__LINE__, hr);
    }
    
  9. Poczekaj, aż proces wyliczenie do wykonania, a następnie wydrukować wiadomość.Wszystkie ComPtr i obiekty RAII pozostawić zakres i są automatycznie zwalniane.

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

Oto przykład kompletne:

// 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));
    HRESULT hr = enumerationCompleted.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;
    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.
*/

Kompilowanie kodu

Aby skompilować kod, skopiuj go a następnie wkleić go w projekcie programu Visual Studio lub wkleić go w pliku o nazwie wrl zużywają events.cpp , a następnie uruchomić następujące polecenie w oknie wiersza polecenia programu Visual Studio.

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

Zobacz też

Koncepcje

Biblioteka szablonów języka C++ środowiska wykonawczego systemu Windows (WRL)