Windows
Windows Zwischenablage: Warten auf den Clipboard History Change
Wie kann man Clipboard-Inhalte verwalten, insbesondere um sicherzustellen, dass Änderungen in der Zwischenablage von der Clipboard History erkannt werden, bevor neue Veränderungen vorgenommen werden? Eine grundlegende Erkenntnis ist, dass der Clipboard-Historien-Service schnelle Änderungen an den Inhalten nicht erfasst. Dies stellt ein Problem für Programme dar, die darauf abzielen, die Clipboard-Historie zu füllen.
Um sicherzustellen, dass eine Änderung erfolgreich in die Historie aufgenommen wurde, muss auf das Clipboard.HistoryChanged-Ereignis gewartet werden. Dieses Ereignis signalisiert, dass eine Änderung in der Clipboard-Historie stattgefunden hat, etwa wenn neue Daten hinzugefügt oder bestehende Daten entfernt wurden. Für einfache Anwendungen nehmen wir an, dass die einzige Quelle für Historienänderungen die neuen Clipboard-Daten sind, die von der Anwendung hinzugefügt werden.
Der folgende C++ Code demonstriert, wie man dies implementieren kann:
#include <windows.h>#include <winrt/Windows.ApplicationModel.DataTransfer.h>#include <winrt/Windows.Foundation.h>#include <winrt/Windows.System.h> namespace winrt { using namespace winrt::Windows::ApplicationModel::DataTransfer; using namespace winrt::Windows::Foundation; using namespace winrt::Windows::System; } void SetClipboardText(HWND hwnd, PCWSTR text) { OpenClipboard(hwnd); EmptyClipboard(); auto size = sizeof(wchar_t) * (1 + wcslen(text)); auto clipData = GlobalAlloc(GMEM_MOVEABLE, size); auto buffer = (LPWSTR)GlobalLock(clipData); strcpy_s(buffer, size, text); GlobalUnlock(clipData); SetClipboardData(CF_UNICODETEXT, clipData); CloseClipboard(); } static constexpr PCWSTR messages[] = { L"314159", // Bug-Nummer L"e83c5163316f89bfbde7d9ab23ca2e25604af290", // Commit L"Widget polarity was set incorrectly." }; winrt::IAsyncAction Sample() { co_await winrt::resume_foreground(queue); if (!winrt::Clipboard::IsHistoryEnabled()) { co_return; } winrt::handle changed( winrt::check_pointer(CreateEventW(nullptr, FALSE, FALSE, nullptr))); auto historyChanged = winrt::Clipboard::HistoryChanged(winrt::auto_revoke, [h = changed.get()](auto&&, auto&&) { SetEvent(h); }); auto tempWindow = CreateWindowExW(0, L"static", nullptr, WS_POPUPWINDOW, 0, 0, 0, 0, nullptr, nullptr, nullptr, nullptr); for (auto message : messages) { SetClipboardText(tempWindow, message); co_await winrt::resume_on_signal(changed.get()); co_await winrt::resume_foreground(queue); } DestroyWindow(tempWindow); } int wmain([[maybe_unused]] int argc, [[maybe_unused]] wchar_t* argv[]) { winrt::init_apartment(); { auto controller = winrt::DispatcherQueueController::CreateOnDedicatedThread(); Sample(controller.DispatcherQueue()).get(); controller.ShutdownQueueAsync().get(); } winrt::uninit_apartment(); return 0; }
In dem Beispiel wird ein temporäres Fenster erstellt, um Clipboard-Operationen durchzuführen. Jedes Mal, wenn ein Text in das Clipboard gesetzt wird, wird auf das HistoryChanged-Ereignis gewartet, um zu prüfen, ob der Clipboard-Inhalt erfolgreich aktualisiert wurde. Dies ermöglicht eine sequenzielle Verarbeitung von Clipboard-Daten ohne Verzögerungen oder Abstürze.
Ein Augenmerk sollte auch auf die Notwendigkeit gelegt werden, die Clipboard-Historie zu überprüfen, da das Programm während seiner Ausführung möglicherweise auf nicht aktivierte Clipboard-Historienbezeichnungen stösst. Dies kann zu Blockierungen führen, wenn die Historie während der Laufzeit deaktiviert wird. Daher sind Feinjustierungen bei der Implementierung erforderlich, um eine robuste Handhabung zu gewährleisten.
Kommentare