0
votes

I make small game and have some problem with low priority window messages, that incessantly sending from system and block running game logic's code.

I create my message loop something like this:

bool Window::SystemRoutineAndCheckQuit() {
    ::MSG msg;
    while( ::PeekMessage( &msg, nullptr, 0, 0, PM_REMOVE ) ) {
        if( msg.message == WM_QUIT ) {
            ::UnregisterClass( registeredClassName, ::GetModuleHandle( nullptr ) );
            DLOG( lg ) << "Exit from system loop" << DLOG_END;
            return false;
        }

        ::TranslateMessage( &msg );
        ::DispatchMessage( &msg );
    }

    return true;
}
//....
    while( window.SystemRoutineAndCheckQuit() ) {
        // do all render and logic
    }

I.e. before every frame I wanna process all messages from windows and then, when queue will empty do all logic. I notice when window resizing I get same message WM_SIZING again and again and queue never will empty when mouse button still press (even when size of window don't change from previos call I receive message with same window coordinates). So it block execute my code.

Is there any other messages, that keep windows message queue don't empty and what is the best way to process all messages without some low priority, like WM_SIZING?

I test it on Windows 8.

PS: I need resize window, so I don't wanna disallow it by change style.

EDIT: sorry for incorrect description problem, but found what real happened (and why my previously attempt to fix it by limit number of processed messages, or by break message process when get same message two times in sequence will not success). From PeekMessage I get message WM_NCLBUTTONDOWN and after this message program don't return from ::DispatchMessage and block continue execution of thread until mouse will be released. And when program in DispatchMessage, my handler get repeatly WM_SIZING or WM_MOVING (independently what return from message handler function (result of DefWindowProc, TRUE (message was processed) or 0).

2

2 Answers

1
votes

You could just process N messages before each frame.. where N is a limit you set between 1-10. That way you can process a reasonable number of events, then get onto your actual game logic.

It's conceivable that Windows may just generate the 'window sizing' message continually when the queue is empty, to make sure applications are aware the window is being resized.

(Maybe MS think applications might not know, maybe there's nothing else the user can do.. so MS want to hammer that single message.)

1
votes

When DefWindowProc handles WM_SYSCOMMAND with either SC_MOVE or SC_SIZE in the wParam, it enters a loop until the user stops it by releasing the mouse button, or pressing either enter or escape. It does this because it allows the program to render both the client area (where your widgets or game or whatever is drawn) and the borders and caption area by handling WM_PAINT and WM_NCPAINT messages (you should still receive these events in your Window Procedure).

It works fine for normal Windows apps, which do most of their processing inside of their Window Procedure as a result of receiving messages. It only effects programs which do processing outside of the Window Procedure, such as games (which are usually fullscreen and not affected anyway).

However, there is a way around it: handle WM_SYSCOMMAND yourself, resize or move yourself. This requires a good deal of effort, but may prove to be worth it. Alternatively, you could use setjmp/longjmp to escape from the Window Procedure when WM_SIZING is sent, or Windows Fibers along the same lines; these are hackish solutions though.

I solved it (using the first method) this past weekend, if you're interested I have released the code to the public domain on sourceforge. Just make sure to read the README, especially the caveat section. Here it is: https://sourceforge.net/projects/win32loopl/