Windows
13.05.2025, 09:52 Uhr
Windows Zwischenablage: Warten auf den Clipboard History Change
In einem Blog-Post beschreibt der Autor Raymond Chen, wie man auf Änderungen der Clipboard History wartet, um effizientere Clipboard-Operationen durchzuführen.

(Quelle: EMGenie)
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.