SetClipboardData和HANDLE的新运算符
SetClipboardData and new operator for HANDLE
#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
’edLPVOID
或new[]
’edchar*
传递给SetClipboardData()
而不会抱怨。但在运行时,操作系统期望传递的HANDLE
指向有效的可移动全局内存对象,其他任何操作都将调用未定义的行为。
相关文章:
- 为什么比较运算符如此快速
- C++映射:具有自定义类的运算符[]不起作用(总是返回0)
- 使用C++中的模板和运算符重载执行矩阵运算
- 为什么这个运算符<重载函数对 STL 算法不可见?
- 增量运算符与后缀混淆
- 一个关于在C++中重载布尔运算符的问题
- 运算符C++ "delete []"仅删除 2 个前值
- 模板类无法识别友元运算符
- 我可以使用条件运算符初始化C风格的字符串文字吗
- 关闭||运算符优化
- 通过继承类使用来自不同命名空间的运算符
- C++Cast运算符过载
- 如何使用AngelScript注册SFML Vector2运算符
- 重载元组索引运算符-C++
- 如何使用重载的相等(==)运算符向测试用例添加描述
- 为什么Mat类的两个对象可以在不重载运算符+的情况下添加
- 多个If语句与使用逻辑运算符计算条件的单个语句的比较
- 布尔比较运算符是如何在C++中工作的
- 重载运算符new[]的行为取决于析构函数
- 如何防止clang格式在流运算符调用之间添加换行符<<