Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/iphone/44.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Winapi 用于CF_DIBV5的Windows剪贴板::GetClipboardData()是否会导致剪贴板上的图像被修改和损坏?_Winapi_Clipboard_Ole - Fatal编程技术网

Winapi 用于CF_DIBV5的Windows剪贴板::GetClipboardData()是否会导致剪贴板上的图像被修改和损坏?

Winapi 用于CF_DIBV5的Windows剪贴板::GetClipboardData()是否会导致剪贴板上的图像被修改和损坏?,winapi,clipboard,ole,Winapi,Clipboard,Ole,我在(至少)Win10上发现,在通过Alt-PrtScrn(可能是合成格式)创建的CF_DIBV5上调用::GetClipboardData(),会导致图像被修改(并且基本上已损坏) 例如,在\u WM\u CLIPBOARDUPDATE()上的处理程序上,下面的简单循环将导致损坏(请注意,您需要使用调试模式,以便::GetClipboardData()未优化) 要进行测试,首先不要运行处理剪贴板的应用程序,使用Alt-PrntScrn捕捉数据,然后将其粘贴到绘图。现在运行处理剪贴板的应用程序(

我在(至少)Win10上发现,在通过Alt-PrtScrn(可能是合成格式)创建的CF_DIBV5上调用
::GetClipboardData()
,会导致图像被修改(并且基本上已损坏)

例如,在\u WM\u CLIPBOARDUPDATE()上的
处理程序上,下面的简单循环将导致损坏(请注意,您需要使用调试模式,以便::GetClipboardData()未优化)

要进行测试,首先不要运行处理剪贴板的应用程序,使用Alt-PrntScrn捕捉数据,然后将其粘贴到绘图。现在运行处理剪贴板的应用程序(以下示例)。重复Alt PrntScrn过程,您将看到捕获窗口的右侧在左侧结束,而不是在该区域居中的位置有所不同

void CMainFrame::OnClipboardUpdate()
    if (::OpenClipboard(AfxGetMainWnd()->m_hWnd)) {
        UINT uformat=0;
        while ((uformat=::EnumClipboardFormats(uformat))!=0) {
            if (uformat==CF_DIBV5) {
                // get the data - run in debug mode so not optimized out 
                HGLOBAL hglobal=::GetClipboardData(uformat);
            }
        }
        // clean up
        ::CloseClipboard();
    }
}
要启用处理程序,需要调用
AddClipboardFormatListener(GetSafeHwnd())类似于
int CMainFrame::OnCreate(LPCREATESTRUCT LPCREATESTRUCT)
然后
RemoveClipboardFormatListener(GetSafeHwnd())打开
void CMainFrame::OnDestroy()

那么这是Win10(和其他Windows版本)中的一个bug,还是我应该做一些示例没有做的事情?(我知道还有其他格式,但CF_DBIV5正是我想要的)

我使用的是版本1903(OS Build 18362.838)

请注意,示例pic在左侧有右侧项目,在左下角有一些垃圾像素。我在应用程序运行时使用alt-prtscrn,粘贴在油漆中

我的分辨率是2560x1600

下面是一个指向将导致问题的项目的链接:


您可以在中找到以下描述:

BI\u位域的红色、绿色和蓝色位域掩码
紧跟在
BitMapInfo标头
BITMAPV4HEADER
之后,然后
BITMAPV5HEADER
结构。
bitmapv4头文件
bitmapv5头文件
结构包含红色、绿色和蓝色遮罩的其他成员 具体如下

bitmapinfo
biCompression
成员设置为
biu BITFIELDS
并且函数接收到类型为
LPBITMAPINFO
的参数时,颜色掩码将立即跟随在标题后面。颜色表(如果存在)将跟随颜色遮罩<代码>位图CoreHeader
位图不支持颜色掩码

正确处理
CF_DIBV5
后,您将成功绘制图像。下面是Win32 C++的一个例子,可以参考:

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    static UINT uFormat = (UINT) -1;
    HDC hdcMem = NULL;
    RECT rc = {0};
    BYTE * pData = NULL;
    BITMAPV5HEADER *pDibv5Info = NULL;

    switch (message)
    {
    case WM_CLIPBOARDUPDATE:
    {       
        if (IsClipboardFormatAvailable(CF_DIBV5))
        {
            uFormat = CF_DIBV5;

            ::CloseClipboard();

            GetClientRect(hWnd, &rc);
            InvalidateRect(hWnd, &rc, TRUE);
        }
    }
    break;
    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);

            switch (uFormat)
            {
            case CF_DIBV5:
                hdcMem = CreateCompatibleDC(hdc);
                if (hdcMem != NULL)
                {
                    if (::OpenClipboard(hWnd)) {
                            HANDLE hglobal = ::GetClipboardData(uFormat);
                            pData = (BYTE*)GlobalLock(hglobal);
                            if (pData)
                            {
                                pDibv5Info = (BITMAPV5HEADER *)pData;
                                int offset = pDibv5Info->bV5Size + pDibv5Info->bV5ClrUsed * sizeof(RGBQUAD);
                                if (pDibv5Info->bV5Compression == BI_BITFIELDS)
                                    offset += 3 * sizeof(DWORD); //three DWORD color masks that specify the red, green, and blue components

                                pData += offset;
                                SetDIBitsToDevice(hdc, 20, 20, pDibv5Info->bV5Width, pDibv5Info->bV5Height, 0, 0, 0, pDibv5Info->bV5Height, pData, (BITMAPINFO *)pDibv5Info, 0);
                            }

                        GlobalUnlock(hglobal);
                        ::CloseClipboard();
                    }
                }
                break;
            }
            EndPaint(hWnd, &ps);
        }
        break;
}
在“我的应用程序”窗口中绘制的正确图像:

我可以不使用代码复制相同的问题:

if (pDibv5Info->bV5Compression == BI_BITFIELDS)
    offset += 3 * sizeof(DWORD);
损坏的图像:


为什么要使用
EnumClipboardFormats()
查找1种格式?您可以改用
IsClipboardFormatAvailable()
。或者,只需无条件调用
GetClipboardData()
,如果所需的格式不可用,就让它失败。我处理了更多的格式,这只是为了显示问题。@df234987我无法在Windows 10 1909 build 18363.778上重现此问题。你能显示你的Windows版本和显示损坏图像的快照吗?添加了操作系统版本和示例图片。我在Windows 10 1903(os Build 18362.836)上进行了测试,它也适用于我。你的.838是打字错误吗?您能否再次检查一下,这个问题是否是由您显示的
CMainFrame::OnClipboardUpdate()
中的代码行引起的?例如,删除
CMainFrame::OnClipboardUpdate()
的主体,此问题是否仍会重现?我不知道这与报告的Windows错误有什么关系?我没有画任何东西,除了调用:
:GetClipboardData(CF_DIBV5)。一旦完成,将图像粘贴到其他应用程序将损坏。如果你不这样做,那没关系。因此,windows::GetClipboardData()中的某些内部内容正在破坏某些内容。我不确定MSPAINT使用的是什么,但它已被::GetClipboardData()损坏。@df234987无需报告剪贴板API/文档的问题。剪贴板上有
CF_DIBV5
的正确数据,因此我可以使用这些数据绘制正确的图像
GetClipboardData()
不会损坏任何内容。它会导致系统崩溃。您看到此问题是因为mspaint似乎不支持转换后的格式DIBV5。如果您还有任何问题,请随时告诉我。或者使用CF_位图或CF_DIB?它似乎会要求任何它想要的格式。如果你把一个CF_DIBV5放在剪贴板上,它要求提供CF_位图,它会返回一个CF_位图。因此,如果剪贴板正在
GetClipboardData()
上转换它,然后将其转换回CF_位图或CF_DIB,那么这可能就是问题所在。但有些东西改变了某些东西,我怀疑MSPAINT是否会要求不同的格式。您是否已完成此操作,然后尝试了CF_位图和CF_DIB版本?@df234987只有一次转换。如果请求的格式与可用格式匹配,则不进行转换,而如果请求的格式与可用格式不匹配,则进行转换。我们不知道打印屏幕快捷方式提供了什么格式,但它提供了mspaint支持的格式。我们也不知道msprint请求的格式,但它似乎不是
CF_DIBV5
GetClipboardData(CF_DIB)
GetClipboardData(CF_位图)
不会导致此问题。@df234987d您是对的。当在
CF_DIBV5
之前请求
CF_DIB
格式时,将正确检索数据。但是,当在
CF_DIBV5
之后请求
CF_DIB
格式时,检索到的数据错误,生成了附加的颜色掩码表。我会在内部报告这个问题。