在一个应用程序中创建两个窗口

时间:2014-01-01 14:37:02

标签: c++ winapi

我正在学习C++,我有一些问题。 msdn的一些研究对我没有帮助。我想在一个应用程序中创建两个窗口。一个窗口 - 带有选项的对话框和另一个用于图形输出这是我使用的代码。但我有一些问题:

  • 第二个窗口(图示)在关闭时没有反应,最小化,按下标志性按钮。
  • 消息框出现时,没有聚焦,没有任何鼠标点击反应,但在这段时间主窗口工作正常。

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR lpCmdLine, int nCmdShow)
{   
    InitCommonControls();   

    if(FAILED(DialogWindow_OnCreate(hInstance)))
            return 1;

    if(FAILED(GraphicWindow_OnCreate(hInstance)))
            return 1;

    MSG msg;
    memset(&msg, 0, sizeof(MSG));
    while(msg.message != WM_QUIT)
    {
            while(PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
            {       
                    TranslateMessage(&msg);
                    DispatchMessage(&msg);      
            }

            OnUpdate();
    }

    GraphicWindow_OnClose();        

    return 0;
}

创建主窗口(对话框):

 HRESULT DialogWindow_OnCreate(HINSTANCE hInst)
    {
        g_hDialogWindow = CreateDialog(hInst, MAKEINTRESOURCE(IDD_MAIN), NULL, DialogWindow_WndProc);

        if(!g_hDialogWindow)
            return E_NOTIMPL;

        UpdateWindow(g_hDialogWindow);

        return S_OK;
    }

主窗口proc(对话框):

INT_PTR CALLBACK DialogWindow_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);     

    switch (message)
    {
    case WM_INITDIALOG:
        {           
            g_hDialogWindow = hWnd;

            // Some init actions ...

            return (INT_PTR)TRUE;
        }   
    case WM_COMMAND:        
        int wmId, wmEvent;
        wmId    = LOWORD(wParam);
        wmEvent = HIWORD(wParam);
        switch(wmEvent)
        {
        case NULL: // Menu used
            {
                switch(wmId)
                {
                case IDC_BTN_1:
                    {
                        DialogWindow_OnBtn1();
                        MessageBoxA(NULL, "Some message", "Some title", MB_OK);
                        return (INT_PTR)TRUE;
                    } break;
                case IDC_BTN_2:
                    {
                        DialogWindow_OnBtn2();
                        return (INT_PTR)TRUE;
                    } break;

                // ...

                    case IDCANCEL:
                    {
                        // Close window
                        DefWindowProc(hWnd, WM_CLOSE, wParam, lParam);
                    } break;
                    case IDOK:
                    {
                        // Close window
                    DefWindowProc(hWnd, WM_CLOSE, wParam, lParam);
                    } break;
                }
            }
        }
    case WM_CLOSE:
        DefWindowProc(hWnd, message, wParam, lParam);
        return (INT_PTR)TRUE;
        break;
    case WM_DESTROY:        
        PostQuitMessage(0);
        return (INT_PTR)TRUE;
        break;  
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
        break;      
    }

return (INT_PTR)FALSE;
}

第二个窗口(图形)创建:

HRESULT GraphicWindow_OnCreate(HINSTANCE hInst)
{
    HWND g_hGraphicWindow = NULL;

    WNDCLASSEX wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style              = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = GraphicWindow_WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInst;
    wcex.hIcon              = LoadIcon(hInst, MAKEINTRESOURCE(IDI_APP_ICO));
    wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = 0;
    wcex.lpszClassName  = _T("MyApp");
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); 

    if(!RegisterClassEx(&wcex))
    {
        DWORD dwError = GetLastError();
        if(dwError != ERROR_CLASS_ALREADY_EXISTS)
        {
            MessageBoxA(NULL, "GraphicWindow: RegisterClass() failed!", "Error", MB_OK | MB_ICONERROR);
            return HRESULT_FROM_WIN32(dwError);            
        }
    }

    // Set window's initial size, but it might be changed later
    int nDefaultWidth = 320;
    int nDefaultHeight = 240;
    RECT rc;
    SetRect(&rc, 0, 0, nDefaultWidth, nDefaultHeight);
    AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, false);    

    // Create the window
    g_hGraphicWindow = CreateWindowA("MyApp", "GraphicWindow", WS_OVERLAPPEDWINDOW,
                      CW_USEDEFAULT, CW_USEDEFAULT, (rc.right - rc.left), (rc.bottom - rc.top), 0,
                      0, hInst, 0);
    if(!g_hGraphicWindow)
    {
        DWORD dwError = GetLastError();
        MessageBoxA(NULL, "GraphicWindow: CreateWindow() failed!", "Error", MB_OK | MB_ICONERROR);
        return HRESULT_FROM_WIN32(dwError);
    }

    UpdateWindow(g_hGraphicWindow); 

    return S_OK;
}

图形窗口过程:

LRESULT CALLBACK GraphicWindow_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam); 

    switch (message)
    {
    case WM_KEYDOWN:
    {
        switch(wParam)
        {
        case VK_RETURN:         
            // Some actions ...         
            break;              
        case VK_ESCAPE:         
            // Some actions ...             
            break;  
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
    }
    break;    
    case WM_CLOSE:      
        ShowWindow(hWnd, SW_HIDE);      
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);        
    }

    return 0;
}

我的问题在哪里?请帮帮我。

2 个答案:

答案 0 :(得分:2)

我有以下评论:

  1. 不要在对话程序中调用DefWindowProc。这可能是主要问题。在MSDN上查看此示例:http://msdn.microsoft.com/en-us/library/windows/desktop/ms644996.aspx#modeless_box
  2. 你的消息循环有些虚假。稍后会详细介绍。
  3. 您不应该调用ANSI函数。删除所有A后缀。您需要使用L为字符串文字添加前缀以指定宽字符串。例如,L"foo"
  4. 当您致电hWndParent时,您可能会将主窗口句柄传递为CreateDialog。否则,无模式dailog将无主,因此有自己的任务栏按钮,并且不会始终显示在主窗口的顶部。
  5. 当您致电hWnd时,您应该将主窗口句柄作为MessageBox传递。

  6. 在消息循环中查看更多详细信息,您不会遵循文档中列出的CreateDialog规则,其中指出:

      

    要支持键盘导航和其他对话框功能,对话框的消息循环必须调用IsDialogMessage函数。

    所以你的消息循环应该是:

    while(GetMessage(&msg, NULL, 0, 0))
    {
        if(!IsDialogMessage(g_hDialogWindow, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
    

    另请注意,我切换到基于GetMessage的循环。我认为您不需要为您的需求运行热循环。使用GetMessage允许应用程序的主线程产生CPU并在其空闲时阻塞。

答案 1 :(得分:0)

在对话程序中,请勿使用DefWindowProc

请参阅:Dialog Box Default Message Processing