Simple Main Window Class

Here’s another fairly trivial code snippet. I’ve stumbled across some borked attempts at initializing and maintaining rendering windows for games lately. Most failed to properly respond to window messages, either ignoring WM_CLOSE outright or letting DefWindowProc() call DestroyWindow() when WM_CLOSE was received, thereby not giving the rest of the game’s code any time to cleanly shut down before the window handle becomes invalid.

So I’ll provide a clean and well-behaved window class here. It doesn’t use any global variables – in fact, you could create any number of windows from any number of threads. WM_CLOSE simply causes the class’ WasCloseRequested() method to return true, so by polling this method you can first shut down graphics and input devices and then destroy the window in an orderly fashion.

For your convenience I also added some helper methods: one resizes the window in a way that ensures the client area will actually end up with the exact pixel size requested. Another will center the window on the screen without messing up if the user has extended his desktop over multiple monitors.

Usage example:

 

/// <summary>Main entry point for the application</summary>
/// <param name="instanceHandle">Instance handle of the new process</param>
/// <param name="previousInstanceHandle">Instance handle of the previous process</param>
/// <param name="commandLine">arguments provided to the application on the command line</param>
/// <param name="showWindow">Desired initial state of the application's window</param>
/// <returns>Zero on success</returns>
int WINAPI WinMain(
  HINSTANCE instanceHandle, HINSTANCE previousInstanceHandle,
  LPSTR commandLine, int showWindow
) {

  // This creates a new window, using the default window size and position.
  // It starts invisible, so you can tweak the window before showing it.
  Window mainWindow(instanceHandle, L"My Game");

  // You can resize the window and it will end up with its drawable region
  // having the exact size you requested
  mainWindow.ResizeViewRectangle(800, 600);
  
  // Centering the window can be done with a single call and it will for once
  // not mess up if your game is run on a workstation with multiple monitors.
  mainWindow.CenterOnPrimaryDisplay();
  
  // After you're done tweaking the window, you show it
  mainWindow.Show();
  
  // Run the message loop. When the user tries to close the window by clicking
  // on 'X' or pressing Alt+F4, your game is informed via WasCloseRequested()
  // and can perform an orderly shutdown.
  while(!mainWindow.WasCloseRequested()) {
    MSG message;
    while(::PeekMessage(&message, NULL, 0, 0, PM_REMOVE)) {
      if(message.message == WM_QUIT) {
        return message.wParam;
      }

      ::TranslateMessage(&message);
      ::DispatchMessage(&message);
    }
  }
  
  // As the window goes out of scope, it gets destroyed and everything will
  // be cleaned up.
  return 0;

}  

 

Download

Download

Nuclex.SimpleMainWindow.Example.7z (14.2 KiB)

Includes Visual C++ 2010 project files and an example application.