c语言 - 创建笔在调整窗口大小时返回 NULL



所以我正在试验Win32 API,并尝试用颜色渐变绘制一条线(通过创建自定义笔)。代码工作正常,我得到了我想要的结果,但是当我开始调整窗口大小时,CreatePen()函数开始给出NULL值,因此 Windows 开始使用默认的黑笔。

这是我WndProc代码:

(https://pastebin.com/xiyzX5fu 完整代码)

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static int cxClient, cyClient;
HDC hdc;
HPEN hPen;
PAINTSTRUCT ps;
switch (message)
{
case WM_SIZE:
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
return 0;

case WM_PAINT:
printf("%dt%dn", cxClient, cyClient); //Printing the resolution
hdc = BeginPaint(hwnd, &ps);
MoveToEx(hdc, 0, cyClient / 2, NULL);
int count = 0;

//Plotting 256 lines each of length (cxClient/256) with different color
for (int i = 0; i < cxClient; i += cxClient / 256)
{
if ((hPen = CreatePen(PS_SOLID, 10, RGB(count, 255, 255))) == NULL)
{
DWORD lasterror;
lasterror = GetLastError();
printf("We got a NULL Value and last error code was %lun", lasterror);
break;
}
else
SelectObject(hdc, hPen);

count += 1; // For uniform color gradient across width
LineTo(hdc, i, cyClient / 2);
}
DeleteObject(hPen);
EndPaint(hwnd, &ps);
return 0;

case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}

我正在尝试在过去几个小时内对其进行调试,以下是我的一些观察结果:

  • 我对RGB的计算是正确的。事实上,即使是默认笔CreatePen(PS_SOLID, 1, 0x00000000)会导致相同的错误。
  • 如果增量值较小,则误差更严重,即 对于i += cxClient/5(绘图只有 5 行)CreatePen将返回 与i += cxClient/256相比,调整大小时 NULL 值的频率要低得多(图 256行)(第 59 行)
  • 有趣的一个:我使用printf(第 53 行)打印客户区的大小。当CreatePen()返回 NULL 值时, 控制台将停止打印包含客户端的语句 区域,只会一次又一次地打印 NULL 错误语句(第 65 行)。它将 仅在打印后添加break(第 66 行)时打印两者 空错误语句。
  • 我想我无法捕获使用CreatePen()的错误 正确GetlastError()(第 64 行),因为它始终打印 0(ERROR_SUCCESS)控制台上。

基于这些观察,我认为问题不在于CreatePen(),而在于我计算每行长度的方式。

您正在创建笔,将其选择到 dc 中,然后在 dc 中仍处于选中状态时将其删除。这将导致DeleteObject失败。您需要记住所选的旧笔,然后在删除笔之前将其重新选择到 dc 中:

HPEN oldPen;
...
oldPen = SelectObject(hdc, hPen);
...
SelectObject(hdc, oldPen);
DeleteObject(hPen);

是的,您正在泄漏 GDI 对象。当进程中的 GDI 对象数达到 10,000 时,系统将不再允许创建新的 GDI 对象。这就是为什么hPen最终会返回 NULL 的原因。

此外,正如我们上次看到的,窗口管理器的最大数量 可以创建的对象约为 32,700。给一个程序 10,000 已经是可用总金额的三分之一。那已经是了 非常慷慨,如果你问我。阻止程序 逃跑并消耗所有窗口管理器对象是一个 尝试控制失控程序造成的损害。即使 程序混乱,仍有大约 20,000 个对象可用 供其他程序使用。

参考:为什么每个进程的窗口句柄限制为 10,000?

最新更新