出于性能原因,我正在尝试通过重用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://docs.microsoft.com/en-us/windows/desktop/memory/creating-named-shared-memory
HANDLE hMapFile;
LPCTSTR pBuf;
// https://docs.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://docs.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://docs.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
);
}
输出为红色屏幕,但您应该在右上角看到黑色部分。
答案 0 :(得分:1)
这种方法是错误的。当目标窗口显示为WM_PAINT时,您的所有工作将被撤消。
始终使用WM_PAINT和BeginPaint按照您希望的方式绘制窗口。
答案 1 :(得分:1)
这里有几个问题,有些与位图无关。
GetDC
上的句柄应该在不再需要时由ReleaseDC
清理。
CreateFileMapping
的句柄应该由CloseHandle
清理,MapViewOfFile
的{{1}}应该清理。
UnmapViewOfFile
句柄必须由HBITMAP
清理
建议在DeleteObject
之后通过调用SelectObject
如果不还原旧的位图,并尝试删除SelectOject(hMemDC, oldHBitmap)
,则Windows无法满足该请求,因为在设备上下文中选择了另一个位图。 Windows将尝试修复此错误,但是如果代码太复杂,它可能会失败。
请注意Windows为您提供了10,000个GDI句柄的限制。如果您没有正确管理这些句柄,该应用程序将很快崩溃。有关这些功能,请参考WinAPI文档。如有疑问,请使用任务管理器监视程序的“ GDI句柄”。
修复这些问题后,代码应可以按预期工作,请参见下面的示例。
这当然仅用于演示。在实际的应用程序中,您可能希望将hMemDC
和其他值保存在堆中,而不是堆栈中。您想减少重复创建这些句柄的次数。
如其他答案和评论所述,应响应HBITMAP
进行绘制,在此您将从WM_PAINT
中获得HDC
(并用BeginPaint
进行清理)。因此,您应避免使用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);
}
用于常量值不会获得任何收益。只需按如下所示更改函数原型:
&
此外,无需使用void createDeviceFromHWND(const HWND hwnd, const int width, const int height);
即可完成此操作,并使用下面显示的CreateFileMapping
。只要buffer
有效,buffer
就会有效。
hbitmap
答案 2 :(得分:0)
您不在此处编辑位图:
for (unsigned int i = 0; i < width * height; ++i)
{
mBackBuffer[i] = 0;
}
仅填充数组,即可从中创建位图,并且为空。