Alex Shul
Alex Shul

Reputation: 500

Creating two windows in one app

I'm learning C++ and I have some questions. Some researches at msdn didn't help me. I wanna create two windows in one app. One window - dialog with options and another for graphic output. Here is the code that I use. But I have some problems with it:

 

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;
}

Creation of main window (Dialog):

 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;
    }

Main window proc (Dialog):

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;
}

Second window (Graphic) creation:

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;
}

Graphic window proc:

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;
}

Where is my problem? Help me, please.

Upvotes: 0

Views: 219

Answers (2)

David Heffernan
David Heffernan

Reputation: 612794

I have the follow comments to make:

  1. Do not call DefWindowProc in your dialog procedure. That could well be the main problem. See this example on MSDN: http://msdn.microsoft.com/en-us/library/windows/desktop/ms644996.aspx#modeless_box
  2. Your message loop is somewhat bogus. More on that later.
  3. You should not be calling ANSI functions. Remove all A suffixes. You'll need to prefix string literals with L to specify wide strings. For instance, L"foo".
  4. You should presumably pass the main window handle as hWndParent when you call CreateDialog. Otherwise, the modeless dailog will be unowned and so have its own taskbar button, and not appear always on top of the main window.
  5. You should pass the main window handle as hWnd when you call MessageBox.

Looking in more detail at the message loop, you are not following the rules laid out in the documentation to CreateDialog, which states:

To support keyboard navigation and other dialog box functionality, the message loop for the dialog box must call the IsDialogMessage function.

So your message loop should be:

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

Note also that I switched to a GetMessage based loop. I don't think you need to run a hot loop for your needs. Using GetMessage allows your app's main thread to yield the CPU and block if it is idle.

Upvotes: 2

manuell
manuell

Reputation: 7620

In your Dialog Procedure, don't use DefWindowProc.

See: Dialog Box Default Message Processing.

Upvotes: 0

Related Questions