2015-08-19 2 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) документацию, объясняющую разницу?

Edit:

Вот еще один пример, который включает в себя оба типа ручки в одной статье: http://www.codeproject.com/Articles/42/All-you-ever-wanted-to-know-about-the-Clipboard

Обратите внимание, что в случае точечного рисунка автор прямо говорит:

// копия была сделана в буфере обмена, поэтому мы можем удалить

+1

Я бы сказал, что эти примеры неверны.Документы четко говорят, что буфер обмена владеет объектом после успешного вызова «SetClipboardData». –

+0

Да, я согласен, это то, что говорят документы. Но я добавил еще один пример, в котором оба типа дескриптора используются в одной статье. Это, конечно, похоже на то, что есть что-то особенное в битмап-данных. –

+1

Я думаю, что единственное, что особенное, - это то, что ОС имеет защиту от удаления дескриптора GDI, отличного от его владельца. –

ответ

0

Вот результаты эксперимента, поощряемого Джонатаном Поттером. Указанная рукоятка находится в переменной HBITMAP hbmScreen. Результатом этого эксперимента является то, что I может получить доступ к 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

См. Примечания о 'CF_BITMAP' в документации [Формат буфера обмена] (https://msdn.microsoft.com/en-us/library/windows/desktop/ms649013.aspx). 'CF_BITMAP' является DDB и не может быть сохранен как-есть, он преобразуется и сохраняется как DIB. –

Смежные вопросы