How to get a string from a hbitmap

3

I have a function that captures the monitor image and creates a bitmap file with the result, but I would like it to return a string with the contents that the file would have, instead of writing it to disk.

The function:

int CaptureRegion(char *filename, int nLeft, int nTop, int nWidth, int nHeight)
{
    HWND hDesktopWnd = GetDesktopWindow(); // Desktop handle
    HDC hDesktopDC = GetDC(hDesktopWnd); // Desktop DC

    BITMAPINFO bi;
    void *pBits = NULL;
    ZeroMemory(&bi, sizeof(bi));
    bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
    bi.bmiHeader.biHeight = nHeight;
    bi.bmiHeader.biWidth = nWidth;
    bi.bmiHeader.biPlanes = 1;
    bi.bmiHeader.biBitCount = 24;
    bi.bmiHeader.biCompression = BI_RGB;
    // bitmap width should be aligned by DWORD under NT
    bi.bmiHeader.biSizeImage = ((nWidth * bi.bmiHeader.biBitCount +31)& ~31) /8 * nHeight; 

    HDC hBmpFileDC=CreateCompatibleDC(hDesktopDC);
    HBITMAP hBmpFileBitmap=CreateDIBSection(hDesktopDC,&bi,DIB_RGB_COLORS,&pBits,NULL,0);
    SelectObject(hBmpFileDC, hBmpFileBitmap);
    BitBlt(hBmpFileDC, 0, 0, nWidth, nHeight, hDesktopDC, nLeft,nTop, SRCCOPY);
        HANDLE  hFile=CreateFile(filename,GENERIC_WRITE,FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
    if(hFile!=INVALID_HANDLE_VALUE)
    {
        DWORD   dwRet = 0;
        BITMAPFILEHEADER bfh;

        ZeroMemory(&bfh, sizeof(bfh));
        bfh.bfType = 0x4D42;
        bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
        bfh.bfSize = bi.bmiHeader.biSizeImage + bfh.bfOffBits;

        WriteFile(hFile, &bfh, sizeof(bfh), &dwRet, NULL);
        WriteFile(hFile, &bi.bmiHeader, sizeof(bi.bmiHeader), &dwRet, NULL);
        WriteFile(hFile, pBits, bi.bmiHeader.biSizeImage, &dwRet, NULL);
        CloseHandle(hFile);
    } else return 0;
    DeleteDC(hBmpFileDC);
    DeleteObject(hBmpFileBitmap);
    ReleaseDC(hDesktopWnd,hDesktopDC);
        return 1;
}

For what I researched, I have to use the "GetDIBits" function, but I do not know how to proceed.

    
asked by anonymous 27.11.2016 / 12:09

1 answer

6

You want the function to return the bitmap data instead of writing them to a file, right? I changed your code a little bit so that the function returns the data in memory:

unsigned char* CaptureRegion(int nLeft, int nTop, int nWidth, int nHeight, unsigned int* size){
HWND hDesktopWnd = GetDesktopWindow(); // Desktop handle
HDC hDesktopDC = GetDC(hDesktopWnd); // Desktop DC
unsigned char* image;

BITMAPINFO bi;
void *pBits = NULL;
ZeroMemory(&bi, sizeof(bi));
bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
bi.bmiHeader.biHeight = nHeight;
bi.bmiHeader.biWidth = nWidth;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biBitCount = 24;
bi.bmiHeader.biCompression = BI_RGB;
// bitmap width should be aligned by DWORD under NT
bi.bmiHeader.biSizeImage = ((nWidth * bi.bmiHeader.biBitCount + 31)& ~31) / 8 * nHeight;

HDC hBmpFileDC = CreateCompatibleDC(hDesktopDC);
HBITMAP hBmpFileBitmap = CreateDIBSection(hDesktopDC, &bi, DIB_RGB_COLORS, &pBits, NULL, 0);
SelectObject(hBmpFileDC, hBmpFileBitmap);
BitBlt(hBmpFileDC, 0, 0, nWidth, nHeight, hDesktopDC, nLeft, nTop, SRCCOPY);

DWORD   dwRet = 0;
BITMAPFILEHEADER bfh;

ZeroMemory(&bfh, sizeof(bfh));
bfh.bfType = 0x4D42;
bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
bfh.bfSize = bi.bmiHeader.biSizeImage + bfh.bfOffBits;

*size = sizeof(bfh) + sizeof(bi.bmiHeader) + bi.bmiHeader.biSizeImage;
image = new unsigned char[*size];

memcpy_s(image, sizeof(bfh), &bfh, sizeof(bfh));
memcpy_s(image + sizeof(bfh), sizeof(bi.bmiHeader), &bi.bmiHeader, sizeof(bi.bmiHeader));
memcpy_s(image + sizeof(bfh) + sizeof(bi.bmiHeader), bi.bmiHeader.biSizeImage, pBits, bi.bmiHeader.biSizeImage);

DeleteDC(hBmpFileDC);
DeleteObject(hBmpFileBitmap);
ReleaseDC(hDesktopWnd, hDesktopDC);

return (unsigned char*)image;
}

Instead of writing to a file you allocate sufficient memory to the bitmap, copy the contents to it and return the data. If you want you can still write them to a file:

unsigned char* image = CaptureRegion(0, 0, 500, 500, &size);

std::ofstream file("desktop.bmp", std::ios_base::out |std::ios_base::binary);

if (!file.is_open()) {
    std::cout << "Failed to open file!\n";
    delete [] image;
    return 0;
}

file.write((char*)image, size);
file.close();
delete[] image;

obs: I also recommend doing error checking with these windows functions: s

    
01.12.2016 / 12:48