2015-08-19 107 views
3

我的理解是,一般来说,当您向剪贴板添加句柄时,剪贴板将拥有该句柄,并且您不负责删除它,并且不应将其删除。这就是这里说的:https://msdn.microsoft.com/en-us/library/windows/desktop/ms649051%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396谁在SetClipboardData(CF_BITMAP,HBITMAP)中释放句柄?

如果SetClipboardData成功,该系统拥有由 的HMEM参数标识的对象。一旦所有权已经转移到系统,应用程序可能无法写入或释放数据 ,但它可以锁定并从数据中读取数据,直到调用CloseClipboard函数。 ( 内存在剪贴板关闭之前必须解锁。)如果参数hMem 标识内存对象,则该对象必须使用具有GMEM_MOVEABLE标志的函数分配为 。

事实上我看到很多的例子,人们称之为的GlobalAlloc(),放在全局处理一些文本,调用SetClipboardData(),然后不要释放的全局句柄,因为剪贴板拥有它。

但HBITMAP数据,通过SetClipboardData(CF_BITMAP, hBitmap)增加的情况下,我看到很多的例子像这样:

https://stackoverflow.com/a/7292773/384670

https://stackoverflow.com/a/28248531/384670

在这些情况下,代码删除HBITMAP将其添加到剪贴板后。

关于剪贴板,HBITMAP句柄和GlobalAlloc()句柄之间有区别吗?有没有什么特别的CF_BITMAP这是一个例外的规则,并剪贴板副本而不是拥有它?你能指出我的官方(MSDN)文档,解释不同之处吗?

编辑

这是一个涉及到两种类型的手柄一文中多了一个例子:http://www.codeproject.com/Articles/42/All-you-ever-wanted-to-know-about-the-Clipboard

注意,位图的情况下,专门撰文说:

//已在剪贴板上复制,因此我们可以删除

+1

我会说这些例子是错误的。该文档清楚地表明剪贴板在成功调用“SetClipboardData”后拥有该对象。 –

+0

是的,我同意这是文档说的。但是我又添加了另一个例子,其中在一篇文章中使用了两种类型的句柄。它当然*看起来像是有点特殊的位图数据。 –

+1

我认为唯一特别的是操作系统可以防止GDI句柄被其他所有者删除。 –

回答

0

这是Jonathan Potter鼓励的实验结果。有问题的句柄位于变量HBITMAP hbmScreen中。这个实验的结果是我的可以通过访问hbmScreen中的所有检查点(1)到(4),并且可以在最后保存正确的图像。所以这告诉我手柄仍然是我的使用。正如我所说,我不认为这明确表明句柄不属于剪贴板。但是,既然所有这一切似乎都没有问题,就打电话DeleteObject(hbmScreen),我会继续这样做。

if (OpenClipboard(NULL) && EmptyClipboard()) 
{ 
    BITMAPINFOHEADER bi = { 0 }; 
    bi.biSize = sizeof(BITMAPINFOHEADER); 
    bi.biPlanes = 1; 
    bi.biBitCount = 32; 
    bi.biWidth = rcClient.right - rcClient.left; 
    bi.biHeight = rcClient.bottom - rcClient.top; 
    bi.biCompression = BI_RGB; 
    bi.biSizeImage = 0; // 3 * ScreenX * ScreenY; 

    BYTE *lpbitmap = (BYTE *)malloc(bi.biWidth * bi.biHeight * 4); 

    // (1) call to make sure we can access hbmScreen here 
    memset(lpbitmap, 0, bi.biWidth * bi.biHeight * 4); 
    GetDIBits(hdcScreen, hbmScreen, 0, (UINT)bi.biHeight, lpbitmap, (BITMAPINFO *)&bi, DIB_RGB_COLORS); 

    HANDLE hResult = SetClipboardData(CF_BITMAP, hbmScreen); 
    CloseClipboard(); 

    // (2) call to check if we can access hbmScreen here 
    memset(lpbitmap, 0, bi.biWidth * bi.biHeight * 4); 
    GetDIBits(hdcScreen, hbmScreen, 0, (UINT)bi.biHeight, lpbitmap, (BITMAPINFO *)&bi, DIB_RGB_COLORS); 

    OpenClipboard(NULL); 
    EmptyClipboard(); 
    CloseClipboard(); 

    // (3) call to check if we can access hbmScreen here 
    memset(lpbitmap, 0, bi.biWidth * bi.biHeight * 4); 
    GetDIBits(hdcMemDC, hbmScreen, 0, (UINT)bi.biHeight, lpbitmap, (BITMAPINFO *)&bi, DIB_RGB_COLORS); 

    // (4) actually use the data from hbmScreen 
    std::vector<unsigned char> image; 
    int n = bi.biWidth * bi.biHeight * 4; 
    image.resize(n); 
    int i = 0; 
    for (int y = bi.biHeight - 1 ; y >= 0 ; y--) 
    { 
     for (int x = 0 ; x < bi.biWidth ; x++) 
     { 
      int base = (y * bi.biWidth + x) * 4; 
      image[ i++ ] = lpbitmap[ base + 2 ]; // r 
      image[ i++ ] = lpbitmap[ base + 1 ]; // g 
      image[ i++ ] = lpbitmap[ base ]; // b 
      image[ i++ ] = lpbitmap[ base + 3 ]; // a 
     } 
    } 
    free(lpbitmap); 
    unsigned error = lodepng::encode("C:/a.png", image, bi.biWidth, bi.biHeight); 
} 
+0

请参阅[剪贴板格式](https://msdn.microsoft.com/en-us/library/windows/desktop/ms649013.aspx)文档中关于'CF_BITMAP'的注释。 'CF_BITMAP'是一个DDB,不能按原样存储,而是转换并存储为DIB。 –

相关问题