SetClipboardData 和 HANDLE 的新运算符

问题描述 投票:0回答:1
#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
的内存检查器在两种情况下显示相同的结果。

c++ winapi clipboard
1个回答
5
投票

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

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

如果

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

HeapAlloc()
new[]
都不满足这些要求。您必须使用
GlobalAlloc()
来代替,以便剪贴板可以正确获取内存对象的所有权,例如:

#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;
}

编译时

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

© www.soinside.com 2019 - 2024. All rights reserved.