0

许多论坛提供以下代码,说明如何将屏幕像素的副本放入数组:

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

链接

但这实际上涉及将像素“内存”区域从屏幕 HDC 复制到内存中。为什么不这样:

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

上下文 HDC 已经包含所有数据。为什么我不能读它?

而且我认为必须将位图选择到 HDC 中,并且 HDC实际上承载数据。那么为什么CreateDIBSection虽然位图还没有被选择到任何 HDC 中却返回一个指针呢?(如果它提供了一个指向作为参数传递的 HDC 内存的指针,则该数组已经包含屏幕的像素值,但情况并非如此,因为BitBlt仍然需要。)

我得出这个结论是因为 BitBlt 接受 HDC 参数,而不是位图。这可能意味着它将数据复制到关联的 HDC。

4

1 回答 1

0

视频内存可以存储在多个位置,包括主系统内存 (RAM)、视频卡上的专用内存、外部显示设备中,甚至这些位置的某种组合。访问此内存可能很,并且进程可能无法访问该内存(至少需要将其映射到进程的地址空间)。

存储在硬件中的视频数据在传递到您的应用程序之前可能需要转换为不同的格式。并且该硬件可能能够利用其他方法来复制不直接涉及 CPU 的数据(例如直接内存访问或 DMA)。由于该复制确实需要一些时间,因此您需要的部分可能会先复制到视频适配器上视频内存的另一部分(这可能是一个非常快速的过程),然后再复制到主内存(一个慢得多的过程)。

视频显示也是共享资源:系统上的所有进程都可能需要访问它。如果您有一个指向视频内存的指针,那么您读取的内容可能不是可见的(如果它已更新为不同的内容),或者如果您写入屏幕可能会损坏屏幕。

于 2019-04-03T21:34:19.483 回答