May 8th, 2025

Why doesn’t Clipboard History capture rapid changes to clipboard contents?

A customer was trying to write a tool to preload items into the clipboard history. In a way, this is sort of the opposite of history. Instead of looking backward to things that were once on the clipboard in the past, they want to look forward into the future and preload things that they anticipate you are soon going to wish were on the clipboard. Here’s a stripped-down version.

// All error checking elided for expository purposes
#include <windows.h>

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

// Put these strings in the clipboard history for quick access.
static constexpr PCWSTR messages[] = {
    L"314159", // the bug number we want to edit
    L"e83c5163316f89bfbde7d9ab23ca2e25604af290", // the commit to link the bug to
    L"Widget polarity was set incorrectly.", // the comment to add
};

int wmain([[maybe_unused]] int argc,
          [[maybe_unused]] wchar_t* argv[])
{
    auto tempWindow = CreateWindowExW(0, L"static", nullptr, WS_POPUPWINDOW,
            0, 0, 0, 0, nullptr, nullptr, nullptr, nullptr);

    for (auto message : messages)
    {
        SetClipboardText(tempWindow, message);
    }
    DestroyWindow(tempWindow);
    return 0;
}

This program sets three strings onto the clipboard one after the other. But when you run it, only the last string makes it into the clipboard history. What happened to the other two?

The clipboard history service operates asynchronously. It registers for clipboard changes via Add­Clipboard­Format­Listener, and when it receives a change notification, it updates the clipboard history. The listener is notified asynchronous, however, so by the time the listener receives the WM_CLIPBOARD­UPDATE message, the clipboard may have changed a second time.

This is different from clipboard viewers, which are notified synchronously when the clipboard changes. The downside is that you might miss out on clipboard changes. The much better upside is that you don’t slow down or hang the clipboard.

In practice, missing every little clipboard change is sort of a feature of the clipboard history service. I can imagine that there are programs that just spam the clipboard with a rapid sequence of clipboard changes. All of the intermediate ones are useless because they are never on the clipboard long enough for the user to paste them. Only the last one really counts from an end-user point of view, so it’s reasonable that the clipboard history service matches what the user sees on the clipboard.

Next time, we’ll see what we can do to repair this program.

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

6 comments

  • Igor Levicki

    Developers who call

    EmptyClipboard()

    without the action being user-initiated should be executed.

    • Raymond ChenMicrosoft employee Author 3 days ago

      The action is user-initiated because the user ran this program, whose stated purpose is emptying the clipboard and replacing its contents! This is just a hard-coded version of clip.exe.

      • Raymond ChenMicrosoft employee Author 1 day ago

        The scenario is “I have a workflow that requires me to paste a lot of long hard-to-remember strings. I can make this easier by writing an app that figures out what strings I need, and then preloads them into the clipboard history, so that I can use Win+V to access them, rather than having to keep switching back and forth between the app that has the strings and the app that I want to paste them into.” This program is presumably being run by the user for this express purpose. I don’t see where encrypted storage enters the picture.

      • GL 2 days ago

        Re 2: it’s the program’s responsibility because prior to preloading, Windows isn’t aware that a program is about to edit the clipboard. But I suspect you have a non-desktop model of security. If the program preloading the history runs in the context of the user, there’s no security boundary to other processes running as the same user (at the same integrity level). Any decryption the program can do, other programs can do for it.

        Re 3: It’s clear from the exposition that the user will press Win+V, then click through the three items. The purpose is to make the three things...

        Read more
      • Igor Levicki 2 days ago

        First, stated purpose in your article was “to preload items into the clipboard history” — that doesn’t imply erasing current contents.

        Second, what guarantee the user has that those clipboard items will be kept in encrypted storage until it’s time to preload them?

        Third, if history is enabled shouldn’t you save what’s on the clipboard and add it back after preloading to, you know, preserve history?

  • GL 5 days ago

    Guess: Listen to Windows.ApplicationModel.DataTransfer.Clipboard.HistoryChanged?