user3476738
user3476738

Reputation: 186

How to properly handle a win32 GUI message loop?

I'm making a simple text editor win32 application for fun. I'm having a peculiar problem with my program. It seems that my program is not returning zero when it exits. Instead, it is returning 1385929. When my main GUI window is destroyed, I use PostQuitMessage( 0 ), but it seems that is not what is being returned in my main function's message.wParam. Here is my code thus far,

#define WIDTH 500
#define HEIGHT 400

#define EDIT_ID 10

LRESULT CALLBACK windowProc( HWND window, UINT message, WPARAM wParam, LPARAM lParam )
{
    static HDC deviceContext = INVALID_HANDLE_VALUE;
    static HWND editControl = INVALID_HANDLE_VALUE;

    switch ( message )
    {
        case WM_CREATE :
            deviceContext = GetDC( window );

            if ( !deviceContext )
            {
                showWindowsError( "Creating Device Context", FALSE );
                DestroyWindow( window );
            }

            editControl = CreateWindow(
                                       "EDIT",
                                       NULL,
                                       WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_LEFT |
                                       ES_MULTILINE | ES_AUTOVSCROLL | ES_NOHIDESEL,
                                       0,
                                       0,
                                       0,
                                       0,
                                       window,
                                       ( HMENU )EDIT_ID,
                                       ( HINSTANCE )GetWindowLong( window, GWL_HINSTANCE ),
                                       NULL
                                      );

            if ( !editControl )
            {
                showWindowsError( "Creating Edit Control", TRUE );
                DestroyWindow( window );
            }

            return 0;
        break;

        case WM_COMMAND :
            switch ( wParam )
            {
                case WM_UNDO :
                    SendMessage( editControl, WM_UNDO, 0, 0 );
                break;

                case WM_CUT :
                    SendMessage( editControl, WM_CUT, 0, 0 );
                break;

                case WM_COPY :
                    SendMessage( editControl, WM_COPY, 0, 0 );
                break;

                case WM_PASTE :
                    SendMessage( editControl, WM_PASTE, 0, 0 );
                break;

                case WM_CLEAR :
                    SendMessage( editControl, WM_CLEAR, 0, 0 );
                break;

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

        case WM_SIZE :
            MoveWindow( editControl, 0, 0, LOWORD( lParam ), HIWORD( lParam ), TRUE );

            return 0;
        break;

        case WM_DESTROY :
            ReleaseDC( window, deviceContext );
            DestroyWindow( editControl );
            PostQuitMessage( 0 );

            return 0;
        break;
    }

    return DefWindowProc( window, message, wParam, lParam );
}

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR CmdArgs, int nCmdShow )
{
    WNDCLASSEX windowClass = { 0 };
    HWND window = INVALID_HANDLE_VALUE;

    MSG message = { 0 };
    HBRUSH windowColor = CreateSolidBrush( GetSysColor( COLOR_WINDOW ) );

    windowClass.cbSize = sizeof( windowClass );
    windowClass.style = CS_HREDRAW | CS_VREDRAW;
    windowClass.lpfnWndProc = windowProc;
    windowClass.hInstance = hInstance;
    windowClass.hCursor = LoadCursor( NULL, IDC_ARROW );
    windowClass.hIcon = LoadIcon( NULL, IDI_APPLICATION );
    windowClass.hbrBackground = windowColor;
    windowClass.lpszClassName = "TextEditorWindow";

    if ( !RegisterClassEx( &windowClass ) )
    {
        DeleteObject( windowColor );
        showWindowsError( "Registering Windows Class", TRUE );
    }

    window = CreateWindow(
                           "TextEditorWindow",
                           "Text Editor",
                           WS_OVERLAPPED | WS_SYSMENU | WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
                           CW_USEDEFAULT,
                           CW_USEDEFAULT,
                           WIDTH,
                           HEIGHT,
                           NULL,
                           NULL,
                           hInstance,
                           NULL
                        );

    if ( !window )
    {
        DeleteObject( windowColor );
        showWindowsError( "Creating GUI", TRUE );
    }

    ShowWindow( window, SW_SHOW );
    UpdateWindow( window );

    do
    {
        TranslateMessage( &message );
        DispatchMessage( &message );
    } while ( GetMessage( &message, window, 0, 0 ) > 0 );

    DeleteObject( windowColor );
    return message.wParam;
}

Upvotes: 1

Views: 3975

Answers (1)

Yirkha
Yirkha

Reputation: 13868

Your call to GetMessage() has the 2nd parameter set to your window's HWND, which limits the messages received only to those sent to that window - see the documentation of the API function.

WM_QUIT is, on the other hand, a message sent to the thread running the message pump, without any particular window. Because of that filter, you don't receive it and message.wParam is never set to that 0.

But why does the loop end and the program shuts down anyway? Because that HWND in window gets invalid after the window is closed, therefore GetMessage() ends with an error and returns -1.


Additionally, you are currently calling TranslateMessage() and DispatchMessage() with message before it is filled with any correct data, on the first iteration. The loop should rather be like this:

while ( GetMessage( &message, NULL, 0, 0 ) > 0 )
{
    TranslateMessage( &message );
    DispatchMessage( &message );
}

Upvotes: 8

Related Questions