#include <Windows.h>
int main()
{
HANDLE h = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 4); //new char[4]{ "QWE" };
if (!h) return 1;
strcpy_s((char*)h, 4, "QWE");
OpenClipboard(0);
EmptyClipboard();
SetClipboardData(CF_TEXT, h);
CloseClipboard();
HeapFree(h, 0, 0);
return 0;
}
If I use new char[4]{ "QWE" };
instead of HeapAlloc()
I recieve an error upon SetClipboardData()
execution. Why does this work this way? Memory inspector for h
shows the same result in both cases.
HeapAlloc()
returns an LPVOID
(void*
) pointer, whereas new char[]
returns a char*
pointer. They are NOT the same type, and neither of them is a valid Win32 HANDLE
to a memory object.
SetClipboardData()
wants a valid HANDLE
pointing to a memory object, but not just any type of HANDLE
. Per the SetClipboardData()
documentation:
If
SetClipboardData
succeeds, the system owns the object identified by thehMem
parameter. The application may not write to or free the data once ownership has been transferred to the system, but it can lock and read from the data until theCloseClipboard
function is called. (The memory must be unlocked before the Clipboard is closed.) If thehMem
parameter identifies a memory object, the object must have been allocated using the [GlobalAlloc
] function with theGMEM_MOVEABLE
flag.
Neither HeapAlloc()
nor new[]
satisfy those requirements. You MUST use GlobalAlloc()
instead, so the clipboard can properly take ownership of the memory object, eg:
#include <Windows.h>
int main()
{
HANDLE h = GlobalAlloc(GMEM_MOVEABLE, 4);
if (!h) return 1;
char *pmem = (char*) GlobalLock(h);
if (!pmem) {
GlobalFree(h);
return 1;
}
strcpy_s(pmem, 4, "QWE");
GlobalUnlock(h);
if (OpenClipboard(NULL)) {
EmptyClipboard();
if (SetClipboardData(CF_TEXT, h))
h = NULL; // clipboard now owns it, don't free it!
CloseClipboard();
}
if (h) GlobalFree(h);
return 0;
}
At compile-time, HANDLE
is just an alias for void*
, and a char*
pointer is implicitly convertible to void*
, so the compiler will allow a HeapAlloc
'ed LPVOID
or a new[]
'ed char*
to be passed to SetClipboardData()
without complaining. But at run-time, the OS expects the passed HANDLE
to point at a valid movable global memory object, anything else will invoke undefined behavior.