Reputation: 1055
ATOM MyRegisterChildClass(void)
{
WNDCLASSEX wcex = {0};
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.lpfnWndProc = ChildProc;
wcex.hInstance = hInst;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 8);
wcex.lpszClassName = ChildClassName;
return RegisterClassEx(&wcex);
}
static HFONT newFont;
static HWND hChild[9];
unsigned char k[9] = {0};
char text[] = {' ', 'X', '0'};
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int i;
static int sx, sy;
switch (message)
{
case WM_CREATE:
MyRegisterChildClass();
for(i = 0; i < 9; i++)
hChild[i] = CreateWindow(ChildClassName, NULL, WS_CHILD |
WS_DLGFRAME | WS_VISIBLE, 0, 0, 0, 0, hWnd, NULL, hInst, NULL);
break;
case WM_SIZE:
if(wParam == SIZE_MINIMIZED)
break;
sx = LOWORD(lParam)/3;
sy = HIWORD(lParam)/3;
if(newFont)
DeleteObject(newFont);
newFont = CreateFont(min(sx, sy), 0, 0, 0, FW_NORMAL, 0, 0, 0,
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Arial");
for(i = 0; i < 9; i++)
{
MoveWindow(hChild[i], (i%3)*sx, (i/3)*sy, sx, sy, TRUE);
UpdateWindow(hChild[i]);
}
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case ID_NEW:
for(i = 0; i < 9; i++)
{
k[i] = 0;
InvalidateRect(hChild[i], NULL, TRUE);
UpdateWindow(hChild[i]);
}
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
LRESULT CALLBACK ChildProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hDC;
RECT rt;
int s, i;
char *ch;
switch(message)
{
case WM_LBUTTONDOWN:
for(i = 0; hWnd != hChild[i]; i++)
;
if(k[i])
break;
else
k[i] = 1;
InvalidateRect(hWnd, NULL, TRUE);
UpdateWindow(hWnd);
srand(lParam);
for(i = s = 0; i < 9; i++)
if(k[i])
s++;
if(s == 9)
MessageBox(hWnd, L"...",L"...", MB_OK|MB_ICONQUESTION);
else
{
while(true)
{
s = rand()*9/(RAND_MAX+1);
if(k[s])
continue;
k[s] = 2;
InvalidateRect(hChild[s], NULL, TRUE);
UpdateWindow(hChild[s]);
break;
}
}
break;
case WM_PAINT:
for(i = 0; hWnd != hChild[i]; i++);
if(k[i])
{
ch = text+k[i];
hDC = BeginPaint(hWnd, &ps);
GetClientRect(hWnd, &rt);
SelectObject(hDC, newFont);
DrawTextA(hDC, ch, 1, &rt, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint(hWnd, &ps);
}
else
DefWindowProc(hWnd, message, wParam, lParam);
break;
default:
DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
I try to create a Tic-Tac-Toe game. Here is the code that I've written by hand (no standard code generated by Visual Studio included). I made 9 child windows. This code runs, but it doesn't show child windows and doesn't react when I push left mouse button. With the help of debugger I saw that messages WM_LBUTTONDOWN
and WM_PAINT
are never sent to ChildProc
function.
What's wrong?
Upvotes: 0
Views: 581
Reputation: 942255
for(i = 0; i < 9; i++)
hChild[i] = CreateWindow(ChildClassName, NULL, WS_CHILD |
WS_DLGFRAME | WS_VISIBLE, 0, 0, 0, 0, hWnd, NULL, hInst, NULL);
You are making a traditional mistake, you are blindly hoping that winapi functions will succeed. That's idle hope, CreateWindow() fails and returns NULL. Something you could also see with the debugger, you'll see the hChild array contain nothing but nulls. Always write defensive code, at the absolute minimum use assert() to backup your assumptions:
for(i = 0; i < 9; i++) {
hChild[i] = CreateWindow(ChildClassName, ...);
assert(hChild[i]);
}
Lots of other places in your code where you should do this. You'll now have to trouble diagnosing failure.
The actual bug is located in ChildProc():
default:
DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
Or in other words, it always return 0. That's not okay, you should only return that value when you processed the message. You didn't process every message. Again use the debugger and set a breakpoint on the switch() statement in ChildProc. You'll see the first message being improperly handled, WM_NCCREATE. Which requires you to return TRUE to continue creation of the window. You don't, you return FALSE. So that's a quick end to the window getting created. You must return the value of DefWindowProc(). Fix:
default:
return DefWindowProc(hWnd, message, wParam, lParam);
Upvotes: 4