Unexpected behavior when placing Unicode text on Clipboard with NULL owner window

Viewed 155

I'm trying to place text on the clipboard from a Windows desktop application that I'm working on, but I am getting some behavior I don't understand.

The function I'm using is as follows:

bool Clipboard::CopyText(const XStringW& txt)
{
    size_t memsize = sizeof(wchar_t) * (txt.Length() + 1);
    HGLOBAL glob = GlobalAlloc(GMEM_MOVEABLE, memsize);
    if (glob != NULL)
    {
        void* mem = GlobalLock(glob);
        if (mem != NULL)
        {
            memcpy(mem, (LPCWSTR) txt, memsize);
            GlobalUnlock(glob);

            HANDLE handle = NULL;

            if (OpenClipboard(NULL))
            {
                EmptyClipboard();
                handle = SetClipboardData(CF_UNICODETEXT, glob);
                ASSERT(handle != NULL);
                CloseClipboard();
            }

            return handle != NULL;
        }
        else

What happens after else is not especially important.

If I execute the above block of code, everything actually works as it should. This is strange to me, because according to the documentation:

If an application calls OpenClipboard with hwnd set to NULL, EmptyClipboard sets the clipboard owner to NULL; this causes SetClipboardData to fail.

But I find that it's working as it should.

However, I only added EmptyClipboard() as an experiment. Prior to this, my code was not working properly. Let's say I placed the text "Hello" from a Word document. Then I copied a number 999 from my application. What would happen is, if I tried pasting to Excel or Word (for example), it would paste "Hello". However if I selected "Paste Special" in (say) Excel and pasted as text, it would paste "999". So it would work, but only if a non-default paste was used.

If I add in the EmptyClipboard() (as per my code above), it works perfectly. It clears whatever was there before. But it shouldn't, according to the documentation.

Can anybody help me understand?

1 Answers

I don't know how to respond to this question with anything other than:

"Because the documentation says so." tm

and leave it at that. The documentation and the examples provided therein specifically state that you must call, in order* (pseudo-code):

if(::OpenClipboard(hwnd)) {
    if(::EmptyClipboard()) {
        //Copy data...
        ::SetClipboardData(/*...*/)'
    }
    ::CloseClipboard();
}

Which also says basically: "Do not call EmptyClipboard without first calling OpenClipboard with a proper handle to a window".

Failing to do that and then wondering why it doesn't work is an exercise in frustration.

*There are cases where responding to specific WM messages should not call ::OpenClipboard but they do not apply here.

Related