Почему GetObject возвращает BITMAP с нулевыми bmBits?

Контекст: я пытаюсь сделать снимок экрана из другого окна, чтобы передать его в OpenCV. Я нашел код в Интернете, который должен иметь возможность конвертировать BITMAP в то, с чем может работать OpenCV. К сожалению, я столкнулся с некоторыми проблемами.

Вопрос: Почему атрибут bmBits/член всегда имеет значение null? (Я также попытался с PrintWindow вместо BitBlt, результат был тем же)

#include <iostream>
#include <string>
#include <Windows.h>

int main(int argc, char* argv[])
{
    std::wstring windowName = L"Calculator";

    RECT rect;
    HWND hwnd = FindWindow(NULL, windowName.c_str());
    if (hwnd == NULL)
    {
        return 0;
    }
    GetClientRect(hwnd, &rect);

    HDC hdcScreen = GetDC(NULL);
    HDC hdc = CreateCompatibleDC(hdcScreen);
    HBITMAP hbmp = CreateCompatibleBitmap(hdcScreen, 
        rect.right - rect.left, rect.bottom - rect.top);
    SelectObject(hdc, hbmp);

    PrintWindow(hwnd, hdc, PW_CLIENTONLY);

    BITMAP bmp;
    GetObject(hbmp, sizeof(BITMAP), &bmp);

    return 0;
}

Ответ 1

Элемент bmBits не равен null для разделов DIB. Для зависимых от устройства растровых изображений (например, тот, который вы создаете), bmBits не установлен, поскольку пиксели находятся на видеокарте, а не в основной памяти.

В вашем примере вам нужно изменить CreateCompatibleBitmap на CreateDIBSection, если вы хотите получить прямой доступ к битам.

Ответ 2

Просто для информации. При загрузке растрового изображения из файла и хотите использовать BITMAP .bmBits (для glTexImage2D, glDrawPixels):

LoadImage(NULL, "path_to.bmp", IMAGE_BITMAP, 0, 0,
                                       LR_LOADFROMFILE);

u должен указывать флаг LR_CREATEDIBSECTION

HBITMAP hBmp = NULL;
BITMAP BMp;
hBmp = (HBITMAP) LoadImage(NULL, "bitmap.bmp", IMAGE_BITMAP, 0, 0,
                                       LR_LOADFROMFILE | LR_CREATEDIBSECTION);
GetObject(hBmp, sizeof(BMp), &BMp);
//BMp.bmBits now points to data

Ответ 3

От GetObject документация по MSDN. Обратите внимание на второй абзац.

Если hgdiobj является дескриптором растрового изображения, созданного при вызове CreateDIBSection, и указанный буфер достаточно велик, функция GetObject возвращает структуру DIBSECTION. Кроме того, член bmBits структуры BITMAP, содержащийся в DIBSECTION, будет содержать указатель на битовые значения бит.

Если hgdiobj является дескриптором растрового изображения, созданного любым другим способом, GetObject возвращает только информацию о ширине, высоте и цветовом формате растрового изображения. Вы можете получить битовые значения битмапа, вызвав функцию GetDIBits или GetBitmapBits.

Ответ 4

Одна вещь, которую вы могли бы сделать, - посмотреть на возвращаемое значение GetObject. Если 0, вы знаете, что что-то пошло не так. Что-то не так с параметрами вызова.