Game loop in GDI window / doesn't refresh and crashes after a while - c++

This is my current game loop in a normal Window:
while(running)
{
while( PeekMessage( &msg, 0, 0, 0, PM_REMOVE ) )
{
if( msg.message == WM_QUIT )
{
running = false;
}
TranslateMessage( &msg );
DrawGame(&game);
DispatchMessage( &msg );
}
UpdateGame(&game);
InvalidateRect(hwnd, NULL, 1);
//Sleep(100);
}
... but should I actually place DrawGame between Translate and DispatchMessage? If I put DrawGame above/below UpdateGame nothing is ever drawn.
And after a while if I draw a simple rectangle they start overlapping eachother. It runs good for about a minute, draw a grid of rectangles (out of position due to: window size that you set isn't the correct size of the window. And after a while it draw another grid and sometimes it screws up totally and the window appears to have crashed and I must press "stop" button in Visual Studio.
So, where exactly do I place a Game loop and how do I know when to Draw the game? I need to draw rectangles primarly, although that isn't working so good either.

You should call DrawGame() from you Windows message callback when handling a WM_PAINT message.
In the message loop you are supposed to only fetch and dispatch Windows messages to the appropriate callback.
Additionally this is also the place to update the game world, but not for doing draw calls.

Related

SDL_PollEvent seems to prevent window surface from updating

I'm currently walking through the Lazy Foo tutorials for SDL2 (I'm doing this on a Linux machine) and I'm encountering some kind of bug where the inclusion of SDL_PollEvent in my main loop seems to prevent SDL_UpdateWindowSurface from actually updating. If I leave the SDL_PollEvent loop out, the loaded bmp displays properly. However, if I include the SDL_PollEvent loop or even a call to SDL_PollEvent, then the window never gets updated with an image. Everything else seems to work fine, SDL_PollEvent is queuing events properly and the loop handles the events properly, but for some reason there's a visual discrepancy between the inclusion of SDL_PollEvent vs. leaving it out.
Using the code provided by Lesson 03: Event driven programming:
This loop fails to update the window:
while( !quit )
{
//Handle events on queue
while( SDL_PollEvent( &e ) != 0 )
{
//User requests quit
if( e.type == SDL_QUIT )
{
quit = true;
}
}
//Apply the image
SDL_BlitSurface( gXOut, NULL, gScreenSurface, NULL );
//Update the surface
SDL_UpdateWindowSurface( gWindow );
}
This loop successfully updates the window with the loaded image:
while( !quit )
{
//Apply the image
SDL_BlitSurface( gXOut, NULL, gScreenSurface, NULL );
//Update the surface
SDL_UpdateWindowSurface( gWindow );
}
But it stops working with the inclusion of a single call to SDL_PollEvent:
while( !quit )
{
SDL_PollEvent(&e);
//Apply the image
SDL_BlitSurface( gXOut, NULL, gScreenSurface, NULL );
//Update the surface
SDL_UpdateWindowSurface( gWindow );
}
SDL_GetWindowSurface documentation says This surface will be invalidated if the window is resized. Upon initial window creation several events are generated, like SDL_WINDOWEVENT_SHOWN and SDL_WINDOWEVENT_EXPOSED. While window isn't marked as user-resizable, I suppose window manager still have an ability to perform resize; you may want to check which events are placed in your event queue (as I cannot reproduce your problem - may be e.g. window manager specific).
To put it in other worlds, window surface isn't guaranteed to persist after some events, so theoretically flushing event queue can invalidate surface. You need to get window surface after flushing event queue just before drawing, on each frame:
while( !quit )
{
// event loop here
// get surface to draw on
gScreenSurface = SDL_GetWindowSurface(gWindow);
//Apply the image
SDL_BlitSurface( gXOut, NULL, gScreenSurface, NULL );
//Update the surface
SDL_UpdateWindowSurface( gWindow );
}

Task Manager's "Switch to" doesn't work properly on DirectX 8 application on windows 7

Task Manager's "Switch to" doesn't work properly with DirectX 8 application on Windows 7
Hi! I have very specific and strange problem.
My game is using DirectX 8. Main cycle looked something like this:
while( WM_QUIT != msg.message )
{
if(IsIconic(m_hWnd))
{
if(GetMessage( &msg, NULL, 0U, 0U))
{
// Translate and dispatch the message
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
else
{
// Use PeekMessage() if the app is active, so we can use idle time to
// render the scene. Else, use GetMessage() to avoid eating CPU time.
if(PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE))
{
// Translate and dispatch the message
TranslateMessage( &msg );
DispatchMessage( &msg );
}
else
{
m_pGame->Render();
}
}
}
The Render function has some basic functionality like this:
void CGame::Render()
{
//...
HRESULT hr = m_pD3DDevice->TestCooperativeLevel();
if(hr == D3DERR_DEVICENOTRESET)
Reset();
else if( SUCCEEDED( hr ) )
{
// Render
//...
}
//...
}
In fullscreen, when application loses focus (by Alt+Tab, Windows Button, Ctrl+Shift+Esc etc.) it just minimizes, stay in task bar and doesn't uses any resources. No problem. Then I can activate it by using Alt+Tab or clicking on task bar icon. Also works perfectly: application activates and Resets Direct3D device in fullscreen.
But using Task Manager's “Switch to” feature leads to strange thing: My application window unfolds and then suddenly minimizes again!
I tried to analyze messages input. It's look like my window receives deactivation massage just after the activation message. Like Task Manager activates my application and deactivates it again.
First I tried
LockSetForegroundWindow(LSFW_LOCK);
It helps on machines with slow motherboard integrated GPU, but strangely it doesn't help on machines with faster GPUs. Some times it works. But most of the time it doesn't.
Then I tried SetForegroundWindow to force-bring my window to foreground:
DWORD dwTimeout;
SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, &dwTimeout, 0);
SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, 0, 0);
SetForegroundWindow(hWindow);
SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, (LPVOID)dwTimeout, 0);
LockSetForegroundWindow(LSFW_LOCK);
It doesn't help, so I tried another hack:
HWND hCurrWnd;
int iMyTID;
int iCurrTID;
hCurrWnd = GetForegroundWindow();
iMyTID = GetCurrentThreadId();
iCurrTID = GetWindowThreadProcessId(hCurrWnd,0);
AttachThreadInput(iMyTID, iCurrTID, TRUE);
SetForegroundWindow(hWindow);
AttachThreadInput(iMyTID, iCurrTID, FALSE);
LockSetForegroundWindow(LSFW_LOCK);
Not working.
Why the Task Managers acts so strangely? What else can I do?
///////////////////////////////////////////////////
UPPDATE+SOLUTION.
So, I solve the problem, though I didn't understand completely why it's works.
I find out two solutions. Each of them works for particular set of computers. One for older and weaker computers (or older OS like WindowsXP), and another for more advanced computers with faster videocards and Windows 7. I managed to unite this two solutions and now my game responds to "Switch to" without problems.
For older and weaker computers all I just place LockSetForegroundWindow(LSFW_LOCK) in key places like before main loop start and in WM_ACTIVATE message.
For faster computers I just need to resize my window (made it small) and call for WindowsUpdate when it deactivates. When my window activates again device resets and during device Reset I just restore my window's fullscreen size automatically.
LRESULT APIENTRY WndProc(HWND hWnd,UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_ACTIVATE:
if((LOWORD(wParam)==WA_ACTIVE)||(LOWORD(wParam)==WA_CLICKACTIVE))
{
if(m_pGame->m_bFullScreen)
LockSetForegroundWindow(LSFW_LOCK);
break;
}
else
{
if(m_pGame->m_bFullScreen)
{
SetWindowPos(hWnd,HWND_NOTOPMOST,0,0,
128,64,SWP_NOMOVE);
UpdateWindow(hWnd);
};
break;
};
//...
}
}

C++ simulate left mouse click on minimized program

I have been searching for a bit about this particular problem I am having, I want to be able to simulate a left mouse click on a program that I am currently attached to.
Right now, I create a thread that checks a database for certain values, and when those values come back (the ones I am looking for), I want to be able to then send a left mouse click in any x,y coord of the program (while minimized).
How can this be done for Windows 7? Thanks!
EDIT: Here is how I am calling the thread ...
HWND child = GetActiveWindow();
if ( child == NULL )
MessageBox(0,"Couldn't get the child hwnd!","",0);
DWORD ID;
HANDLE thread_check_game = CreateThread ( NULL , 0 , (LPTHREAD_START_ROUTINE) game_check_thread , (LPVOID)child, 0 , &ID ); CloseHandle ( game_check_thread );
and then ...
DWORD WINAPI game_check_thread(LPVOID lpParam) {
HWND Window;
Window = (HWND)lpParam;
// ... some other code ...
// ...
WORD mouseX = 398;
WORD mouseY = 398;
SendMessage(Window,WM_LBUTTONDOWN,MK_LBUTTON,MAKELPARAM(mouseX,mouseY));
SendMessage(Window, WM_LBUTTONUP, MK_LBUTTON, MAKELPARAM(mouseX, mouseY));
Write("Sent Left Click\n");
ExitThread(0);
return 0;
}
If you want to fire a mouse event in your application, use the SendMessage function, and your message will appear in the window with handle hWnd's message pump.
SendMessage(hWnd, WM_LBUTTONDOWN, MK_LBUTTON, MAKELPARAM(mousePosX, mousePosY));
You may need to notify for WM_LBUTTONUP, depending on the way you application handles it's mouse events.

DoEvents equivalent for C++?

I'm new to native c++. Right now, I made it so when I press the left mouse button, it has a for loop that does InvalidateRect and draws a rectangle, and increments X by the box size each time it iterates. But, C++ is so much faster and efficient at drawing than C# that, it draws all this instantly. What I would like is for it to invalidate the rectangle, show the rectangle, wait 50ms, then continue the loop. I tried Sleep(50) but it still waits until painting is done before showing the result. I also tried PeekMessage but it did not change anything.
Any help would be appreciated. Thanks
DoEvents basically translates as:
void DoEvents()
{
MSG msg;
BOOL result;
while ( ::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE ) )
{
result = ::GetMessage(&msg, NULL, 0, 0);
if (result == 0) // WM_QUIT
{
::PostQuitMessage(msg.wParam);
break;
}
else if (result == -1)
{
// Handle errors/exit application, etc.
}
else
{
::TranslateMessage(&msg);
:: DispatchMessage(&msg);
}
}
}
I am a bit rusty in Win32 API, but the asynchronous way of doing this would be:
Invalidate the rect
Set a timer (see below) to send a message after 50ms
Return to the event loop to let WM_PAINT events happen
On receiving the timer message, move the rect, then repeat
This way integrates nicely with being event driven. I realize this is not exactly what you ask for, but I thought I'd mention it as a possible solution anyway :)
EDIT: A quick google turns up the Windows API call [SetTimer](http://msdn.microsoft.com/en-us/library/ms644906(VS.85,loband).aspx) which you can use to facilitate this. The message will be a WM_TIMER one.

hardware buffering using SDL, question about how it works

I'm deciding to do my first game, its going to be simple but I want to use c++ and I chose SDL for my learning. So my question is about how the "buffers" are handled when writing code. I'll post my related code at the bottom.
Ok, so basically the way I understand it is that SDL takes care of which buffer is actually being drawn to the screen. When I am writing to a buffer it is always the backbuffer I am writing to, or the buffer currently not being drawn on the screen. So, when I call SDL_Flip(screen) it "blits" my screen surface onto the backbuffer, then moves the pointer to which buffer is being drawn to that buffer which used to be the backbuffer, the one I had been working on, and the old buffer that was showing now becomes the backbuffer. At this point if I call SDL_FillRect(arguments) it will be performed on the now back buffer?
I'm going to post my entire "heartbeat" of my learning game as it may help clarify my question:
//While the user hasn't quit
while( quit == false )
{
//If there's an event to handle
if( SDL_PollEvent( &event ) )
{
//If a key was pressed
if( event.type == SDL_KEYDOWN )
{
//Set the proper message surface
switch( event.key.keysym.sym )
{
case SDLK_UP: message = upMessage; break;
case SDLK_DOWN: message = downMessage; break;
case SDLK_LEFT: message = leftMessage; break;
case SDLK_RIGHT: message = rightMessage; break;
}
}
else if( event.type == SDL_QUIT ) //if the user clicks the little X in the upper right corner.
{
quit = true;
}
}
//If a message needs to be displayed
if( message != NULL )
{
// Clear the back buffer.
SDL_FillRect( SDL_GetVideoSurface(), NULL, 0 );
//Draw the backgroudn to the back buffer.
apply_surface( 0, 0, background, screen );
// Draw the "message" to the back buffer.
apply_surface( ( SCREEN_WIDTH - message->w ) / 2, ( SCREEN_HEIGHT - message->h ) / 2, message, screen );
//Null the surface pointer
message = NULL;
}
//Swap the current and back buffer.
if( SDL_Flip( screen ) == -1 )
{
return 1;
}
}
it highly depends on the your system (ie. X11, Linux frame buffer, Windows), and the backend SDL uses to interact with it. Also which flags you passs to SDL_SetVideoMode. There are basically software surfaces which sit in a region of memory in you program and hardware surfaces which are placed in graphical card's memory. What you describe seems to me to be a double buffer, which is enabled if you pass SDL_HWSURFACE | SDL_DOUBLEBUF to SDL. Just remember this is not supported on all platforms and configurations and you may get something different instead.