sergiu reznicencu
sergiu reznicencu

Reputation: 1039

Saving pixels from screen HDC

Many forums give the following code regarding how to get into an array a copy of the screen's pixels:

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;
}

(Link)

But this involves actually copying the pixels "memory" area from screen HDC to an in-memory one. Why not this:

char* Pixels = NULL;
HBITMAP Section = CreateDIBSection(Context, &Info, DIB_RGB_COLORS, (void**)&Pixels, 0, 0);
SelectObject(Context, Section);

The Context HDC already contains all the data. Why can't I just read it?

And I thought that a bitmap must be selected into a HDC and that the HDC actually carries the data. Then why does CreateDIBSection return a pointer although the bitmap was not yet selected into any HDC? (If it gives a pointer to the memory of the HDC passed as argument then the array already contains the screen's pixels values but this is not the case because BitBlt is still required.)

I reached this conclusion because BitBlt accepts an HDC argument, not a bitmap. This probably means it copies the data to the associated HDC.

Upvotes: 0

Views: 301

Answers (1)

1201ProgramAlarm
1201ProgramAlarm

Reputation: 32732

Video memory can be stored in several places, including main system memory (RAM), dedicated memory on a video card, in an external display device, or even some combination of these. Access to this memory can be slow, and the memory might not be accessible to a process (at the very least it would need to be mapped into the address space of the process).

Video data stored in hardware might need to be translated into a different format before passing to your application. And that hardware might be able to utilize other methods to copy the data that do not directly involve the CPU (like Direct Memory Access, or DMA). Since that copy does take some small amount of time, the section you want might be copied to another section of video memory on the video adapter (which can be an extremely quick process) before being copied to main memory (a much slower process).

The video display is also a shared resource: all processes on the system may need to access it. If you had a pointer to the video memory, what you read might not be what's visible (if it was updated to different content), or you could corrupt the screen if you wrote to it.

Upvotes: 0

Related Questions