【发布时间】:2021-05-10 20:49:57
【问题描述】:
当我在 Windows 程序中调用以下函数时,程序突然终止。
ScanRect()的目的是在屏幕上的指定坐标处复制一个矩形,并将像素值加载到内存缓冲区中。
ScanRect() 中的每个函数调用都会成功,包括对GetDIBits() 的两次调用。第一次调用,将lpvBits 设置为NULL,使它用有关像素数据的信息填充bmInfo 的BITMAPINFOHEADER,报告每像素32 位的值。第二次调用GetDIBits() 将矩形的80 行复制到内存缓冲区pMem,返回值80 表示复制的行数。
一切似乎都成功了,但随后程序突然终止。我在第二次调用GetDIBits() 后插入了Sleep(8192) 行,程序在8 秒后终止。
是什么导致程序终止?
编辑:原始代码根据此线程中的建议进行了修改。函数运行时没有检测到错误,但程序仍然意外终止。我意识到内存缓冲区大小是硬编码的,但它比测试中使用的矩形所需的要大得多。这不应该导致错误。当然,在找出程序终止的原因后,我会让程序计算必要的缓冲区大小。
VOID ScanRect(int x, int y, int iWidth, int iHeight) // 992, 96, 64, 80
{ HDC hDC = GetDC(NULL);
if (!hDC)
{
cout << "!hDC" << endl; // error handling ...
}
else
{ HBITMAP hBitmap = CreateCompatibleBitmap(hDC, iWidth, iHeight);
if (!hBitmap)
{
cout << "!hBitmap" << endl; // error handling ...
}
else
{ HDC hCDC = CreateCompatibleDC(hDC); // compatible with screen DC
if (!hCDC)
{
cout << "!hCDC" << endl; // error handling ...
}
else
{ HBITMAP hOldBitmap = (HBITMAP) SelectObject(hCDC, hBitmap);
BitBlt(hCDC, 0, 0, iWidth, iHeight, hDC, x, y, SRCCOPY);
BITMAPINFO bmInfo = {0};
bmInfo.bmiHeader.biSize = sizeof(bmInfo.bmiHeader);
if (!GetDIBits(hCDC, hBitmap, 0, iHeight, NULL, &bmInfo, DIB_RGB_COLORS))
{
cout << "!GetDIBits" << endl; // error handling ...
}
else
{ HANDLE hHeap = GetProcessHeap();
LPVOID pMem = HeapAlloc(hHeap, HEAP_ZERO_MEMORY, 65536); // TODO: calculate a proper size based on bmInfo's pixel information ...
if (!pMem)
{
cout << "!pMem" << endl;
}
else
{ int i = GetDIBits(hCDC, hBitmap, 0, iHeight, pMem, &bmInfo, DIB_RGB_COLORS);
cout << "i returned by GetDIBits() " << i << endl;
HeapFree(hHeap, NULL, pMem);
}
}
SelectObject(hCDC, hOldBitmap);
DeleteDC(hCDC);
}
DeleteObject(hBitmap);
}
ReleaseDC(NULL, hDC);
}
}
【问题讨论】:
-
使用调试器而不是睡眠来找出问题所在。
-
在删除 HDC 或 HGDIOBJ 之前,您应该始终撤消
SelectObject。 -
你不知道任何函数是否成功,因为你没有做错误检查
-
David Heffernan,我使用 cout 对 AllocConsole 创建的控制台进行了错误检查,但为了简洁起见,我在代码示例中省略了这一点。相信我,我检查了所有调用函数的返回值,它们成功了。如果将函数复制并粘贴到 Windows 程序中,则可以检查返回值。在第二次调用 GetDIBits() 之后,i 的值是 80。根据 Ben Voight 的建议,我将在弄清楚如何执行此操作后尝试撤消 SelectObject()。但请注意,当我注释掉函数的最后四行时,程序仍然会终止。
-
你没有为颜色表预留空间,所以这可能会溢出堆栈缓冲区,这是个坏消息。
标签: winapi