SetClipboardData和HANDLE的新运算符

SetClipboardData and new operator for HANDLE

本文关键字:运算符 HANDLE SetClipboardData      更新时间:2024-09-21
#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;
}

如果我使用new char[4]{ "QWE" };而不是HeapAlloc(),我在执行SetClipboardData()时会收到错误。为什么这样做?h的内存检查器在两种情况下都显示相同的结果。

HeapAlloc()返回LPVOID(void*(指针,而new char[]返回char*指针。它们不是同一类型,并且对于内存对象来说都不是有效的Win32HANDLE

SetClipboardData()想要一个指向内存对象的有效HANDLE,而不仅仅是任何类型的HANDLE。根据SetClipboardData()文件:

如果SetClipboardData成功,则系统拥有由hMem参数标识的对象一旦所有权转移到系统,应用程序可能不会写入或释放数据,但在调用CloseClipboard函数之前,它可以锁定和读取数据。(必须先解锁内存,然后才能关闭剪贴板。(如果hMem参数标识内存对象,则必须使用带有GMEM_MOVEABLE标志的[GlobalAlloc]函数分配该对象

HeapAlloc()new[]都不满足这些要求。您必须使用GlobalAlloc(),这样剪贴板才能正确地获得内存对象的所有权,例如:

#include <Windows.h>
int main()
{
HANDLE h = GlobalAlloc(GMEM_MOVABLE, 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;
}

编译时HANDLE只是void*的别名,而char*指针可以隐式转换为void*,因此编译器将允许HeapAlloc’edLPVOIDnew[]’edchar*传递给SetClipboardData()而不会抱怨。但在运行时操作系统期望传递的HANDLE指向有效的可移动全局内存对象,其他任何操作都将调用未定义的行为