0

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.

1201ProgramAlarm
  • 32,384
  • 7
  • 42
  • 56
sergiu reznicencu
  • 1,039
  • 1
  • 11
  • 31

1 Answers1

0

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.

1201ProgramAlarm
  • 32,384
  • 7
  • 42
  • 56
  • Then to what does the pointer returned by createDIBSection point to? The only argument received is the screen hdc and it definitely is not a pointer to its data. – sergiu reznicencu Apr 03 '19 at 21:37
  • And it is not bound to memDC either. (because the pointer stays the same even after we select the section onto memDC. This means this pointer is not a function of the HDC, it is independent of it. Then what is it? – sergiu reznicencu Apr 03 '19 at 21:40
  • It looks as if it is an independent region of memory. The HDC into which I selected the bitmap can be full and contain whatever it wants but if I don't BitBlt something onto that hdc then the section memory won't change. Is this right? – sergiu reznicencu Apr 03 '19 at 21:42
  • @sergiureznicencu [`CreateDIBSection`](https://learn.microsoft.com/en-us/windows/desktop/api/wingdi/nf-wingdi-createdibsection) returns a pointer that applications can write to directly. It probably resides in main system RAM. – 1201ProgramAlarm Apr 03 '19 at 21:46
  • And when I select a section into a hdc what exactly happens? The HDC represents some device with graphical memory and the section also contains its own area of memory in ram. I understood the speed argument and the problem of corruption(probably that's why I have to use BitBlt : to take a "snapshot" of that memory) but why do I have to "select" the section? Why can't I give BitBlt the pointer returned by CreateDIBSection ? – sergiu reznicencu Apr 03 '19 at 21:50