gpt4 book ai didi

c++ - 我怎样才能不断重复使用 HBITMAP 和 HDC?

转载 作者:行者123 更新时间:2023-11-30 03:21:40 25 4
gpt4 key购买 nike

出于性能原因,我正在尝试通过重用 HBITMAP 和 HDC 来使 HBIPMAP 正常工作。

这是我想做的一个小测试项目,以了解有关基于 CPU 的光栅化的更多信息。对于窗口,我使用的是 SDL2。

如果我们注释掉,下面的代码就可以工作了:

DeleteDC(hdcMem);
hdcMem = CreateCompatibleDC(device);

我找不到 2018+ 年的任何例子。

mBackBuffer 只是一个 Vector(DWORD)

void Device::createDeviceFromHWND(const HWND& hwnd, const int& width, const int& height)
{
// This is hacked code for an example.

auto device = GetDC(hwnd);
DWORD colorSize = 4; // ARGB;

// Create page section
// https://learn.microsoft.com/en-us/windows/desktop/memory/creating-named-shared-memory
HANDLE hMapFile;
LPCTSTR pBuf;
// https://learn.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-createfilemappinga
hMapFile = CreateFileMappingA
(
INVALID_HANDLE_VALUE,
NULL,
PAGE_READWRITE,
0,
width * height * colorSize,
NULL
);

if (hMapFile == NULL)
{
return;
}

DWORD* buffer = (DWORD*)MapViewOfFile(
hMapFile,
FILE_MAP_ALL_ACCESS,
0,
0,
width * height * colorSize
);

BITMAPINFOHEADER header;
memset(&header, 0, sizeof(BITMAPINFOHEADER));
// https://msdn.microsoft.com/en-us/02f8ed65-8fed-4dda-9b94-7343a0cfa8c1
header.biSize = sizeof(BITMAPINFOHEADER);
header.biWidth = width;
header.biHeight = height;
header.biPlanes = 1;
header.biBitCount = 32;
header.biCompression = BI_RGB;
header.biSizeImage = width * height * sizeof(BYTE);
header.biXPelsPerMeter = 0;
header.biYPelsPerMeter = 0;
header.biClrUsed = 0;
header.biClrImportant = 0;


tagBITMAPINFO bitmap;
memset(&bitmap, 0, sizeof(tagBITMAPINFO));
// https://learn.microsoft.com/en-us/windows/desktop/api/wingdi/ns-wingdi-tagbitmapinfo
tagRGBQUAD RGBQUAD;
memset(&RGBQUAD, 0, sizeof(tagRGBQUAD));

bitmap.bmiHeader = header;
bitmap.bmiColors[0] = RGBQUAD;

LPVOID p;
// https://learn.microsoft.com/en-us/windows/desktop/api/wingdi/nf-wingdi-createdibsection
auto hBitMap = CreateDIBSection
(
device,
&bitmap,
DIB_RGB_COLORS,
&p,
hMapFile,
0
);

for (DWORD i = 0; i < width * height; ++i)
{
buffer[i] = 0xFF0000;
}

HDC hdcMem = CreateCompatibleDC(device);
auto oldHBITMAP = (HBITMAP)SelectObject(hdcMem, hBitMap);

BitBlt(
device,
0,
0,
width,
height,
hdcMem,
0,
0,
SRCCOPY
);

DeleteDC(hdcMem);

for (DWORD i = 0; i < width * height; ++i)
{
buffer[i] = 0;
}

hdcMem = CreateCompatibleDC(device);

BitBlt(
device,
400,
300,
width,
height,
hdcMem,
0,
0,
SRCCOPY
);
}

输出是红色屏幕,但您应该看到右角的黑色部分。

最佳答案

这里有几个问题,有些与位图无关。

当不再需要句柄时,GetDC 中的句柄应由 ReleaseDC 清除。

来自 CreateFileMapping 的句柄应该被 CloseHandle 清除,MapViewOfFile 应该被 UnmapViewOfFile 清除.

HBITMAP 句柄必须由 DeleteObject

清除

建议在 SelectObject 之后通过调用 SelectOject(hMemDC, oldHBitmap) 进行清理

如果您不恢复旧位图,并尝试删除 hMemDC,Windows 将无法满足请求,因为在设备上下文中选择了另一个位图。 Windows 将尝试修复此错误,但如果代码过于复杂,它可能会失败。

请注意,Windows 为您提供了 10,000 个 GDI 句柄的限制。如果您不正确管理这些句柄,应用程序将很快崩溃。有关这些功能,请参阅 WinAPI 文档。如有疑问,请使用任务管理器监视程序的“GDI 句柄”。

解决这些问题后,代码应按预期工作,请参见下面的示例。

当然这只是为了演示。在现实世界的应用程序中,您可能希望将 HBITMAP 以及其他一些值保存在堆中,而不是堆栈中。您希望尽量减少重复创建这些句柄。

如其他答案和评论中所述,绘制应响应于 WM_PAINT,您从 BeginPaint 获得 HDC(并清理使用 EndPaint)。因此你应该避免 GetDC/ReleaseDC

void Device::createDeviceFromHWND(const HWND& hwnd, const int& width, const int& height)
{
auto hdc = GetDC(hwnd);
auto hMapFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0,
width * height * sizeof(DWORD), NULL);

auto buffer = (DWORD*)MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0,
width * height * sizeof(DWORD));

BITMAPINFOHEADER biheader = { sizeof(biheader), width, height, 1, 32, BI_RGB };

LPVOID bits;
auto hbitmap = CreateDIBSection(hdc, (BITMAPINFO*)&biheader, DIB_RGB_COLORS,
&bits, hMapFile, 0);

for(int i = 0; i < width * height; ++i)
buffer[i] = 0xFF0000;

auto memdc = CreateCompatibleDC(hdc);
auto oldhbitmap = SelectObject(memdc, hbitmap);

BitBlt(hdc, 0, 0, width, height, memdc, 0, 0, SRCCOPY);
for(int i = 0; i < width * height; ++i)
buffer[i] = 0;
BitBlt(hdc, 0, 0, 100, 100, memdc, 0, 0, SRCCOPY);

SelectObject(memdc, oldhbitmap); //<- ***EDIT***
//oldhbitmap is selected in to memdc, now we can destroy hbitmap and memdc

DeleteObject(hbitmap);
DeleteDC(memdc);
ReleaseDC(hwnd, hdc);
UnmapViewOfFile(buffer);
CloseHandle(hMapFile);
}

旁注,对常量值使用引用运算符 & 不会获得任何好处。只需更改函数原型(prototype)如下:

void createDeviceFromHWND(const HWND hwnd, const int width, const int height);

此外,这可以在没有 CreateFileMapping 的情况下完成,并使用如下所示的 buffer。只要 hbitmap 有效,buffer 就会有效。

void test(const HWND hwnd, const int w, const int h)
{
auto hdc = GetDC(hwnd);

//use the negative value of height, so bitmap bits are not upside-down
BITMAPINFOHEADER bi = { sizeof(bi), w, -h, 1, 32, BI_RGB };

DWORD* buffer;
auto hbitmap = CreateDIBSection(hdc, (BITMAPINFO*)&bi, DIB_RGB_COLORS,
(void**)&buffer, NULL, 0);

auto memdc = CreateCompatibleDC(hdc);
auto oldbmp = SelectObject(memdc, hbitmap);

for(int i = 0; i < w * h; ++i) buffer[i] = 0xFF0000;
BitBlt(hdc, 0, 0, w, h, memdc, 0, 0, SRCCOPY);

//draw black square on top-left
for(int y = 0; y < 100; y++)
for(int x = 0; x < 100; x++)
buffer[y * w + x] = 0;
BitBlt(hdc, 0, 0, 100, 100, memdc, 0, 0, SRCCOPY);

//cleanup:
SelectObject(memdc, oldbmp);
DeleteObject(hbitmap); //<- buffer is not valid after hbitmap is destroyed
DeleteDC(memdc);
ReleaseDC(hwnd, hdc);
}

关于c++ - 我怎样才能不断重复使用 HBITMAP 和 HDC?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51950182/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com