Cara: Menangani Peristiwa Menggunakan WRL
Dokumen ini memperlihatkan cara menggunakan Windows Runtime C++ Template Library (WRL)untuk berlangganan dan menangani peristiwa objek Windows Runtime.
Untuk contoh yang lebih mendasar yang membuat instans komponen tersebut dan mengambil nilai properti, lihat Cara: Mengaktifkan dan Menggunakan Komponen Runtime Windows.
Berlangganan dan Menangani Peristiwa
Langkah-langkah berikut memulai ABI::Windows::System::Threading::IDeviceWatcher
objek dan menggunakan penanganan aktivitas untuk memantau kemajuan. Antarmuka memungkinkan IDeviceWatcher
Anda menghitung perangkat secara asinkron, atau di latar belakang, dan menerima pemberitahuan saat perangkat ditambahkan, dihapus, atau diubah. Fungsi Callback adalah bagian penting dari contoh ini karena memungkinkannya untuk menentukan penanganan aktivitas yang memproses hasil operasi latar belakang. Contoh lengkapnya adalah sebagai berikut.
Peringatan
Meskipun Anda biasanya menggunakan Pustaka Templat C++ Windows Runtime di aplikasi Platform Windows Universal, contoh ini menggunakan aplikasi konsol untuk ilustrasi. Fungsi seperti wprintf_s
tidak tersedia dari aplikasi Platform Windows Universal. Untuk informasi selengkapnya tentang jenis dan fungsi yang dapat Anda gunakan di aplikasi Platform Windows Universal, lihat Fungsi CRT yang tidak didukung di aplikasi Platform Windows Universal dan Win32 dan COM untuk aplikasi UWP.
Sertakan (
#include
) Runtime Windows yang diperlukan, Pustaka Templat Windows Runtime C++, atau header Pustaka Standar 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
menyatakan jenis yang diperlukan untuk menghitung perangkat.Kami menyarankan agar Anda menggunakan arahan
using namespace
dalam file .cpp Anda untuk membuat kode lebih mudah dibaca.Deklarasikan variabel lokal untuk aplikasi. Contoh ini menyimpan jumlah jumlah perangkat enumerasi dan token pendaftaran yang memungkinkannya berhenti berlangganan nanti dari peristiwa.
// 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;
Menginisialisasi Windows Runtime.
// Initialize the Windows Runtime. RoInitializeWrapper initialize(RO_INIT_MULTITHREADED); if (FAILED(initialize)) { return PrintError(__LINE__, initialize); }
Buat objek Peristiwa yang menyinkronkan penyelesaian proses enumerasi ke aplikasi utama.
// 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); }
Catatan
Acara ini hanya untuk demonstrasi sebagai bagian dari aplikasi konsol. Contoh ini menggunakan peristiwa untuk memastikan bahwa operasi asinkron selesai sebelum aplikasi keluar. Di sebagian besar aplikasi, Anda biasanya tidak menunggu operasi asinkron selesai.
Buat pabrik aktivasi untuk
IDeviceWatcher
antarmuka.// 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); }
Windows Runtime menggunakan nama yang sepenuhnya memenuhi syarat untuk mengidentifikasi jenis. Parameter
RuntimeClass_Windows_Devices_Enumeration_DeviceInformation
adalah string yang disediakan oleh Windows Runtime dan berisi nama kelas runtime yang diperlukan.Buat objek
IDeviceWatcher
:// Create a IDeviceWatcher object from the factory. ComPtr<IDeviceWatcher> watcher; hr = watcherFactory->CreateWatcher(&watcher); if (FAILED(hr)) { return PrintError(__LINE__, hr); }
Callback
Gunakan fungsi untuk berlanggananAdded
peristiwa , ,EnumerationCompleted
danStopped
.// 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); }
Penanganan
Added
aktivitas meningkatkan jumlah perangkat enumerasi. Ini menghentikan proses enumerasi setelah sepuluh perangkat ditemukan.Penanganan
Stopped
aktivitas menghapus penanganan aktivitas dan mengatur peristiwa penyelesaian.Penanganan
EnumerationCompleted
aktivitas menghentikan proses enumerasi. Kami menangani peristiwa ini jika ada kurang dari sepuluh perangkat.Tip
Contoh ini menggunakan ekspresi lambda untuk menentukan panggilan balik. Anda juga dapat menggunakan objek fungsi (functors), penunjuk fungsi, atau objek std::function . Untuk informasi selengkapnya tentang ekspresi lambda, lihat Ekspresi Lambda.
Mulai proses enumerasi.
wprintf_s(L"Starting device enumeration...\n"); hr = watcher->Start(); if (FAILED(hr)) { return PrintError(__LINE__, hr); }
Tunggu hingga proses enumerasi selesai lalu cetak pesan. Semua
ComPtr
objek RAII dan meninggalkan cakupan dan dirilis secara otomatis.// 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.
Berikut adalah contoh lengkapnya:
// 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.
*/
Mengompilasi Kode
Untuk mengkompilasi kode, salin lalu tempelkan dalam proyek Visual Studio, atau tempelkan dalam file yang diberi nama wrl-consume-events.cpp
lalu jalankan perintah berikut di jendela Prompt Perintah Visual Studio.
cl.exe wrl-consume-events.cpp runtimeobject.lib
Baca juga
Saran dan Komentar
https://aka.ms/ContentUserFeedback.
Segera hadir: Sepanjang tahun 2024 kami akan menghentikan penggunaan GitHub Issues sebagai mekanisme umpan balik untuk konten dan menggantinya dengan sistem umpan balik baru. Untuk mengetahui informasi selengkapnya, lihat:Kirim dan lihat umpan balik untuk