2014-01-05 82 views
0
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; 
} 

我正在尝试使用井字游戏。这是我手动编写的代码(这里没有由Visual Studio生成的标准代码)。我制作了9个儿童窗户。 此代码会运行,但它不会显示子窗口,并且在按下鼠标左键时不会反应。在调试器的帮助下,我看到消息WM_LBUTTONDOWN和WM_PAINT从不发送给ChildProc函数。 有什么问题?子窗口不显示

回答

3
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); 

你犯了一个传统的错误,你一味地希望winapi函数能成功。这是空闲的希望,CreateWindow()失败并返回NULL。你也可以用调试器看到的东西,你会看到hChild数组只包含空值。 始终编写代码的防守,在绝对最低使用断言()来备份你的假设:

for(i = 0; i < 9; i++) { 
     hChild[i] = CreateWindow(ChildClassName, ...); 
     assert(hChild[i]); 
    } 

大量的代码中的其他地方,你应该这样做。您现在必须在诊断故障时遇到麻烦。

实际的错误位于ChildProc():

default: 
    DefWindowProc(hWnd, message, wParam, lParam); 
} 
return 0; 

或者换句话说,它总是 0,这是不行的,你应该只当你处理的消息返回值。您没有按消息处理。再次使用调试器并在ChildProc的switch()语句中设置一个断点。您将看到第一条消息被错误处理,WM_NCCREATE。这要求您返回TRUE以继续创建窗口。你不这样做,你返回FALSE。所以这是窗口创建的快速结束。你必须必须返回DefWindowProc()的值。修复:

default: 
    return DefWindowProc(hWnd, message, wParam, lParam); 

请注意,您还在WndProc()中使用WM_CREATE消息玩一个危险的游戏。返回0意外工作,你应该总是将消息传递给DefWindowProc(),因为你实际上并没有处理WM_CREATE,你只是将它用作通知。