Standard if(PeekMessage) else update&render-loop creates delay in message handling - c++

Following a Direct2D tuturial I've created a realtime update&render-loop like below. But when the update&render-loop takes long (eg when I have a Sleep(5000) somewhere in the Update()), normal messages handling like clicking the close window, can have to wait up to 5s.
So what is the proper way to split the message handling and realtime update&render-loop in two separate threads?
while (message.message != WM_QUIT)
{
if (PeekMessage(&message, windowHandle, 0, 0, PM_REMOVE)) // check for events and pass them to WindowProc, otherwise
DispatchMessage(&message);
else // run the realtime update&render loop
{
GameController::Update();
graphics->BeginDraw();
GameController::Render();
graphics->EndDraw();
}
}

Related

Continue update&render whilst handling windowproc messages

I've created a win32 C++ app that uses direct2d to plot stuff in a window. In a loop as shown below, I call render and update whilst also peeking at any messages. But when ever I have WM_COMMAND that lets WindowProc call a MessageBox() or DiaLogBox(), my update&render loop no longer gets executed and the plot window freezes. Is there a simple fix with another loop structure or do I need to enter the, for me, unknown world of multithreading?
while (message.message != WM_QUIT)
{
if (PeekMessage(&message, NULL, 0, 0, PM_REMOVE))
DispatchMessage(&message);
else
{
Update();
BeginDraw();
Render();
EndDraw();
}
}
EDIT: By popular demand I have changed above "ugly" mechanism in to another approach, yet with the same issue
bool runGame = true;
while (runGame)
{
while (PeekMessage(&message, NULL, 0, 0, PM_REMOVE))
{
DispatchMessage(&message);
if (message.message == WM_QUIT)
runGame = false;
}
Update();
BeginDraw();
Render();
EndDraw();
}

Forcing a ListBox to Update

I am using C++ with MFC, and I have a ListBox tied to a variable that I'm updating as I run through a function:
void CFileSelection::OnBnClickedFiletousb()
{
m_LogC.AddString(_T("Starting move to USB, Please Wait..."));
UpdateData(FALSE);
// Code to move files from disk to USB
m_LogC.AddString(_T("Move to USB Successful."));
}
However, despite the UpdateData, the ListBox doesn't populate with either string until it has completed it's task. Is there a way to make it update the screen before the rest of the code is executed?
Use this function after changing the text on the listbox. Your issue is that the other calls are blocking the MessageThread, but you can force an update with this.
void ProcessWindowMessages()
{
MSG msg;
while (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) // let them see the message before we go into longer term wait
{
TranslateMessage(&msg); // translate it
DispatchMessage(&msg); // and let windows dispatch it to WinProc
}
}
Alternatively you can also call
yourlistboxVariable->UpdateWindow();

Opengl Game Loop Multithreading

I have been messing around with OpenGL lately, and I noticed that the windows message pump is blocking whenever i attempt to resize my window, so as a result rendering is halted whenever i click on the menu bar or resize the window.
To fix this, I am looking into multithreading.
I have the following:
_beginthread(RenderEntryPoint, 0, 0);
while (!done)
{
PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE);
if (msg.message == WM_QUIT)
{
done = true;
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
void RenderEntryPoint(void *args)
{
while (1)
{
//render code
}
}
However, my scene isn't being rendered, and I'm not sure why.
You need to make the OpenGL rendering context current in the rendering thread, and make sure it's not current in the windowing thread. This also means that you can't call any OpenGL functions from the windowing thread.

PostMessage() succeeds but my message processing code never receives the message

In my C++ application's GUI object I have the following in the main window procedure:
case WM_SIZE:
{
OutputDebugString(L"WM_SIZE received.\n");
RECT rect = {0};
GetWindowRect(hwnd, &rect);
if (!PostMessage(0, GUI_MSG_SIZECHANGED, w, MAKELONG(rect.bottom - rect.top, rect.right - rect.left))) {
OutputDebugString(L"PostMessage failed.\n"); // <--- never called
}
}
return 0; // break;
The GUI object also has the following getMessage() method:
int GUI::getMessage(MSG & msg) {
BOOL result = 0;
while ((result = GetMessage(&msg, 0, 0, 0)) > 0) {
if (msg.message > (GUI_MSG_BASE-1) && msg.message < (GUI_MSG_LAST+1)) {
OutputDebugString(L"GUI message received.\n");
break;
}
else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return result;
}
The application object calls this method in the following way:
while ((result = _gui.getMessage(msg)) > 0) {
switch (msg.message) {
// TODO: Add gui message handlers
case GUI_MSG_SIZECHANGED:
OutputDebugString(L"GUI_MSG_SIZECHANGED received.\n");
_cfg.setWndWidth(HIWORD(msg.lParam));
_cfg.setWndHeight(LOWORD(msg.lParam));
if (msg.wParam == SIZE_MAXIMIZED)
_cfg.setWndShow(SW_MAXIMIZE);
else if (msg.wParam == SIZE_MINIMIZED)
_cfg.setWndShow(SW_MINIMIZE);
else if (msg.wParam == SIZE_RESTORED)
_cfg.setWndShow(SW_SHOWNORMAL);
break;
}
}
The application object is interested in the window size because it stores this information in a configuration file.
When I run this in Visual Studio's debugger, the output window looks like this after resizing the window:
WM_SIZE received.
GUI message received.
GUI_MSG_SIZECHANGED received.
WM_SIZE received.
WM_SIZE received.
WM_SIZE received.
WM_SIZE received.
...etc...
The PostMessage() function never fails, but seems to only send GUI_MSG_SIZECHANGED (#defined as WM_APP + 0x000d) the first time WM_SIZE is handled, which is right after handling WM_CREATE.
I have no idea what could be causing this. I tried using SendMessage and PostThreadMessage but the result is the same. Also read through MSDN's message handling documentation but couldn't find what's wrong with my code.
Could anyone help?
Hacking a custom message loop is something you'll live to regret some day. You hit it early.
Don't post messages with a NULL window handle, they can only work if you can guarantee that your program only ever pumps your custom message loop. You cannot make such a guarantee. These messages fall into the bit bucket as soon as you start a dialog or Windows decides to pump a message loop itself. Which is the case when the user resizes a window, the resize logic is modal. Windows pumps its own message loop, WM_ENTERSIZEMOVE announces it. This is also the reason that PostThreadMessage is evil if the thread is capable of displaying any window. Even a MessageBox is fatal. DispatchMessage cannot deliver the message.
Create a hidden window that acts as the controller. Now you can detect GUI_MSG_SIZECHANGED in its window procedure and no hacks to the message loop are necessary. That controller is not infrequently the main window of your app btw.

Game loop in Win32 API

I'm creating game mario like in win32 GDI . I've implemented the new loop for game :
PeekMessage(&msg,NULL,0,0,PM_NOREMOVE);
while (msg.message!=WM_QUIT)
{
if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else // No message to do
{
gGameMain->GameLoop();
}
}
But my game just running until I press Ctrl + Alt + Del ( mouse cursor is rolling ).
I've always been using something like that:
MSG msg;
while (running){
if (PeekMessage(&msg, hWnd, 0, 0, PM_REMOVE)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
try{
onIdle();
}
catch(std::exception& e){
onError(e.what());
close();
}
}
onIdle is actual game lopp implementation, onError() is an error handler (takes error description as argument), and "running" is either a global bool variable or a class member. Setting "running" to false shuts down the game.
I think this really depends on your context. Windows will only send a WM_QUIT in response to your application calling PostQuitMessage. A common (if not great) solution here is to use a bool to exit the message loop when your program wants to end.
I guess the program may ask user for continue or exit, inside GameLoop function call. On exit Post WM_QUIT message to the window.
PostMessage(hWnd, WM_QUIT, 0, 0 );
hWnd-> The handle of the game window
else make a call to
DestroyWindow(hWnd);
This will send a WM_DESTROY to your window procedure. There you can call
PostQuitMessage(0);