我编写了一个执行低级打印的Win32应用程序,我正在处理GDI bitmaps and device contexts。
代码基本上这样做(伪代码):
HDC hCompDc = ::CreateCompatibleDC(hDC);
BITMAPINFOHEADER infoHeader = {0};
infoHeader.biSize = sizeof(infoHeader);
infoHeader.biWidth = nWidth;
infoHeader.biHeight = -nHeight; //The document must be right side up
infoHeader.biPlanes = 1;
infoHeader.biBitCount = 24;
infoHeader.biCompression = BI_RGB;
BITMAPINFO info;
info.bmiHeader = infoHeader;
//Use file on disk to store large bitmap data
HANDLE hFileScatch = ::CreateFile(strTempPath,
GENERIC_READ | GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
UINT64 ncbLineSz = nWidth * 3;
if(ncbLineSz & 0x3)
ncbLineSz = (ncbLineSz & ~0x3) + 0x4; //Must be DWORD aligned
UINT64 uiSzBmp = ncbLineSz * nHeight;
HANDLE hFileMapObj = ::CreateFileMapping(hFileScatch,
NULL, PAGE_READWRITE, (DWORD)(uiSzBmp >> 32), (DWORD)(uiSzBmp), NULL);
BYTE* pMemory = 0;
HBITMAP hBitmap = ::CreateDIBSection(hDC, &info, DIB_RGB_COLORS, (void**)&pMemory, hFileMapObj, 0);
::SelectObject(hCompDc, hBitmap);
//Do drawing on `hCompDc` using other GDI APIs
//...
//And print
::SetAbortProc(hPrintDC, _printerAbortProc);
::StartDoc(hPrintDC, &docInfo);
::StartPage(hPrintDC);
::BitBlt(hPrintDC,
rcPrintArea.left,
rcPrintArea.top,
rcRenderArea.Width(),
rcRenderArea.Height(),
hCompDc, //DC from
rcRenderArea.left,
rcRenderArea.top,
SRCCOPY);
::EndPage(hPrintDC);
//Clean up, etc.
//...
这在某种程度上有效。让我解释一下:
由于我处理的打印机分辨率为300 dpi(而普通屏幕为96 dpi),因此位图的大小非常大。
例如,如果我的位图为3900
x 86625
像素,则需要大约966 MB
的DIB部分。 (我可以了解到,如果我在上面的代码中CreateDIBSection
替换默认内存分配,并使用file mapping object
支持file on disk。)否则,我知道我可以达到连续的限制具有该块内存的32位进程中的RAM空间。但事实并非如此。
当我在32位进程中运行具有该位图大小的代码时,使用由file mapping object
支持的file on disk创建位图,但生成的位图/图像完全显示空白,而在64位进程中编译的完全相同的代码,会产生一个看起来很正常的位图。
因此,鉴于GDI对象存在特定的图像大小限制,我很好奇吗?对于32位和64位进程。
还有一个附带问题 - 是否有任何方法可以知道在绘制时达到了这样的尺寸限制?
PS。我的实际代码对所有Win32 API都进行了所有错误检查,虽然我上面描述的32位进程产生了一个空白位图,但它在单个GDI API中没有失败。