I have an HDC file(that is taken by screen that I want to save it to any image file (prefer Bmp) , the thing is I don't really know the format and any function that I find for saving takes to many function inputs (that must be maximum 2). Any help saving it?

int nScreenWidth = GetSystemMetrics(SM_CXSCREEN);
int nScreenHeight = GetSystemMetrics(SM_CYSCREEN);
HWND hDesktopWnd = GetDesktopWindow();
HDC hDesktopDC = GetDC(hDesktopWnd);
HDC hCaptureDC = CreateCompatibleDC(hDesktopDC);
HBITMAP hCaptureBitmap =CreateCompatibleBitmap(hDesktopDC, 
nScreenWidth, nScreenHeight);
SelectObject(hCaptureDC,hCaptureBitmap); 
BitBlt(hCaptureDC,0,0,nScreenWidth,nScreenHeight,
hDesktopDC,0,0,SRCCOPY);// |CAPTUREBLT); 
SaveBitmap("Screen Capture.bmp",hCaptureBitmap);<----- //Save Bmp 
//here to save the captured image to disk
ReleaseDC(hDesktopWnd,hDesktopDC);
DeleteDC(hCaptureDC);
DeleteObject(hCaptureBitmap);

Dani AI

Generated

A couple of easy-to-miss details when dumping an HDC to a BMP: DIBs are bottom-up by default. If you want the file to match on-screen orientation without manually flipping rows, use a top-down DIB by setting biHeight to -abs(height) in your BITMAPINFOHEADER. Always compute the stride as ((bitsPerPixel * width + 31) & ~31) / 8, and set biSizeImage = stride * height for correctness. To capture layered (per-pixel alpha) windows, include CAPTUREBLT in your ROP; otherwise they will be omitted. Cursor pixels are not part of the DC; draw them yourself via GetCursorInfo + DrawIconEx if you need them. On high-DPI systems, make the process DPI-aware to avoid scaled captures; see High DPI desktop development.

If you prefer a minimal, modern save path (BMP/PNG/JPEG) without hand-writing headers, use Windows Imaging Component (WIC). Example (error checks omitted):

CoInitialize(NULL);
ComPtr<IWICImagingFactory> fac; CoCreateInstance(CLSID_WICImagingFactory, 0, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&fac));
ComPtr<IWICBitmap> wicBmp;     fac->CreateBitmapFromHBITMAP(hCaptureBitmap, 0, WICBitmapIgnoreAlpha, &wicBmp);
ComPtr<IWICStream> stream;     fac->CreateStream(&stream); stream->InitializeFromFilename(L"screen.bmp", GENERIC_WRITE);
ComPtr<IWICBitmapEncoder> enc; fac->CreateEncoder(GUID_ContainerFormatBmp, 0, &enc); enc->Initialize(stream.Get(), WICBitmapEncoderNoCache);
ComPtr<IWICBitmapFrameEncode> frame; enc->CreateNewFrame(&frame, 0); frame->Initialize(0);
frame->SetResolution(GetDeviceCaps(hDesktopDC, LOGPIXELSX), GetDeviceCaps(hDesktopDC, LOGPIXELSY));
frame->WriteSource(wicBmp.Get(), 0); frame->Commit(); enc->Commit();

Remember to restore and delete GDI objects: HGDIOBJ old = SelectObject(hCaptureDC, hCaptureBitmap); ... SelectObject(hCaptureDC, old); DeleteObject(hCaptureBitmap);. WIC references: , CreateBitmapFromHBITMAP.

Recommended Answers

All 3 Replies

#include <vector>
#include <fstream>
#include <cstring>
#include <windows.h>

bool HDCToFile(const char* FilePath, HDC Context, RECT Area, uint16_t BitsPerPixel = 24)
{
    uint32_t Width = Area.right - Area.left;
    uint32_t Height = Area.bottom - Area.top;

    BITMAPINFO Info;
    BITMAPFILEHEADER Header;
    memset(&Info, 0, sizeof(Info));
    memset(&Header, 0, sizeof(Header));
    Info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    Info.bmiHeader.biWidth = Width;
    Info.bmiHeader.biHeight = Height;
    Info.bmiHeader.biPlanes = 1;
    Info.bmiHeader.biBitCount = BitsPerPixel;
    Info.bmiHeader.biCompression = BI_RGB;
    Info.bmiHeader.biSizeImage = Width * Height * (BitsPerPixel > 24 ? 4 : 3);
    Header.bfType = 0x4D42;
    Header.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);


    char* Pixels = NULL;
    HDC MemDC = CreateCompatibleDC(Context);
    HBITMAP Section = CreateDIBSection(Context, &Info, DIB_RGB_COLORS, (void**)&Pixels, 0, 0);
    DeleteObject(SelectObject(MemDC, Section));
    BitBlt(MemDC, 0, 0, Width, Height, Context, Area.left, Area.top, SRCCOPY);
    DeleteDC(MemDC);

    std::fstream hFile(FilePath, std::ios::out | std::ios::binary);
    if (hFile.is_open())
    {
        hFile.write((char*)&Header, sizeof(Header));
        hFile.write((char*)&Info.bmiHeader, sizeof(Info.bmiHeader));
        hFile.write(Pixels, (((BitsPerPixel * Width + 31) & ~31) / 8) * Height);
        hFile.close();
        DeleteObject(Section);
        return true;
    }

    DeleteObject(Section);
    return false;
}

int main()
{
    HWND win = GetDesktopWindow();
    HDC dc = GetDC(win);
    HDCToFile("C:/.../Desktop/Foo.bmp", dc, {0, 0, 1366, 768});
    ReleaseDC(win, dc);
}

Btw.. You can set: Info.bmiHeader.biSizeImage = Width * Height * (BitsPerPixel > 24 ? 4 : 3); to 0 instead. It'd auto calculate it for you. I just chose to show you how it actually does it (an approximation). The real calculation is done at line 38.. So it's better to set line 21 to 0 or remove it.

Hi ,

You were almost there. Just need another single line code :). Let me know if this works for you

int nScreenWidth = GetSystemMetrics(SM_CXSCREEN);
int nScreenHeight = GetSystemMetrics(SM_CYSCREEN);
HWND hDesktopWnd = GetDesktopWindow();
HDC hDesktopDC = GetDC(hDesktopWnd);
HDC hCaptureDC = CreateCompatibleDC(hDesktopDC);
HBITMAP hCaptureBitmap =CreateCompatibleBitmap(hDesktopDC, nScreenWidth, nScreenHeight);
SelectObject(hCaptureDC,hCaptureBitmap); 
BitBlt(hCaptureDC,0,0,nScreenWidth,nScreenHeight, hDesktopDC,0,0,SRCCOPY);// |CAPTUREBLT); 
// SaveBitmap("Screen Capture.bmp",hCaptureBitmap);<----- //Save Bmp 
// here to save the captured image to disk

// call GDI+ Bitmap class static method to save your HBITMAP

    const CLSID clsidBmpEncoder = Polytec::Drawing::GetEncoderClsid(Polytec::Drawing::BmpMimeType);
    Gdiplus::Bitmap::FromHBITMAP(hCaptureBitmap, NULL)->Save(L"D:\\temp_images\\gdi_drawing.bmp", &clsidBmpEncoder);

ReleaseDC(hDesktopWnd,hDesktopDC);
DeleteDC(hCaptureDC);
DeleteObject(hCaptureBitmap);
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.