So I am experimenting with Win32 API and trying to plot a line with colour gradient (by creating a custom Pen). The code is working fine and I am getting my desired result but when I start resizing my window, CreatePen()
function starts giving NULL
value, and thus Windows start using the default black pen.
This is my WndProc
code:
(https://pastebin.com/xiyzX5fu for full code)
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("%d\t%d\n", 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 %lu\n", 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);
}
I am trying to debug it for the last few hours and here are some of my observations:
RGB
are correct. In fact, even a default pen
CreatePen(PS_SOLID, 1, 0x00000000)
leads to same error.i += cxClient/5
(plots only 5 lines) CreatePen
would return
NULL values much less often while resizing as compared to i += cxClient/256
(plots 256 lines)
(Line 59)printf
(Line 53). The moment CreatePen()
returns a NULL value,
the console will stop printing the statement containing the Client
Area and will only print the NULL error statement (Line 65) again and again. It will
print both only when I add a break
(Line 66) after printing the
NULL error statement.CreatePen()
using
GetlastError()
(Line 64) correctly because it always prints 0
(ERROR_SUCCESS)
on the console.Based on these observations I think the problem doesn't lie in CreatePen()
but in my way of calculating the length of each line.
You are creating the pen, selecting it into the dc, and then deleting it while it is still selected in the dc. This will case DeleteObject
to fail. You need to remember the old pen that was selected, and then select that back into the dc before deleting your pen:
HPEN oldPen;
...
oldPen = SelectObject(hdc, hPen);
...
SelectObject(hdc, oldPen);
DeleteObject(hPen);
Yes, you are leaking GDI object. When the number of GDI objects in your process reaches 10,000, the system will no longer allow the creation of new GDI objects. This is why hPen
will eventually return NULL.
Furthermore, as we saw last time, the maximum number of window manager objects that can be created is around 32,700. Giving a program 10,000 is already a third of the total amount available. That’s already pretty darned generous, if you ask me. Preventing a program from running away and consuming all of the window manager objects is an attempt to contain the damage caused by a runaway program. Even if a program goes haywire, there’s still around 20,000 objects available for the other programs to use.
Refer: Why is the limit of window handles per process 10,000?
User contributions licensed under CC BY-SA 3.0