Udostępnij za pośrednictwem


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

Ten dokument 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 instancję 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ć procedury 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ą dodane, usunięte lub zmienione.Wywołania zwrotnego funkcja jest ważnym elementem w tym przykładzie, ponieważ umożliwia jej określić programy obsługi zdarzeń, które przetwarzają wyniki operacji tła.Poniżej przedstawiono prosty przykład kompletne.

Informacje dotyczące przestrogiPrzestroga

Chociaż zazwyczaj używa się WRL w Windows Store aplikacji, w tym przykładzie używa aplikacji konsoli jako ilustracja.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 aplikacji Win32 i COM dla magazynu systemu Windows.

  1. Obejmują (#include) wszystkie wymagane Środowisko wykonawcze systemu Windows, WRL, lub standardowych nagłówków biblioteka języka 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 oświadcza, typy, które są wymagane do wyliczenia urządzeń.

    Firma Microsoft zaleca, aby wykorzystać using namespace w dyrektywie w pliku .cpp, aby kod był bardziej czytelny.

  2. Deklaruje zmienne lokalne dla aplikacji.W tym przykładzie zostały przedstawione licznik wyliczanych urządzeń i tokeny rejestracji, które pozwolą później Anuluj 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. Zainicjuj Środowisko wykonawcze systemu Windows.

    // Initialize the Windows Runtime.
    RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);
    if (FAILED(initialize))
    {
        return PrintError(__LINE__, initialize);
    }
    
  4. Tworzenie zdarzenie obiektu, która synchronizuje zakończenie 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));
    hr = threadCompleted.IsValid() ? S_OK : HRESULT_FROM_WIN32(GetLastError());
    if (FAILED(hr))
    {
        return PrintError(__LINE__, hr);
    }
    

    [!UWAGA]

    To zdarzenie jest demonstracyjne tylko jako część aplikacji konsoli.W tym przykładzie użyto zdarzenie, aby zapewnić, że operacji asynchronicznej zostanie zakończony przed wyjściach aplikacji.W większości aplikacji należy zwykle nie czekać na na zakończenie operacji asynchronicznej.

  5. Utworzyć fabryki aktywacji dla IDeviceWatcher interfejsu.

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

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

  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 funkcji, aby zapisać się do 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 licznik wyliczanych urządzeń.Po dziesięciu znalezione, zatrzymuje proces wyliczenie.

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

    EnumerationCompleted Programu obsługi zdarzeń powoduje zatrzymanie procesu wyliczenie.W przypadku, gdy nie ma mniej niż dziesięć urządzeń zajmujemy się to zdarzenie.

    PoradaPorada

    W tym przykładzie użyto wyrażenia lambda, do zdefiniowania 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 Lambda wyrażenia w języku C++.

  8. Rozpocznij proces wyliczenie.

    wprintf_s(L"Starting device enumeration...\n");
    hr = watcher->Start();
    if (FAILED(hr))
    {
        return PrintError(__LINE__, hr);
    }
    
  9. Poczekaj, aż proces wyliczenie, aby zakończyć, a następnie wydrukować wiadomość.Wszystkie ComPtr i RAII obiektów 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 kompletny przykład:

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

Kompilowanie kodu

Aby skompilować kod, skopiuj go i następnie wkleić go w projekcie programu Visual Studio lub wklej go w pliku o nazwie światowym laboratorium referencyjnym zużywają events.cpp a następnie uruchom następujące polecenie w oknie wiersza polecenia usługi 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)