Skip to content

Instantly share code, notes, and snippets.

@retorillo
Last active February 23, 2023 08:46
Show Gist options
  • Save retorillo/bf5ea61460fb1a04006c9214f31312d9 to your computer and use it in GitHub Desktop.
Save retorillo/bf5ea61460fb1a04006c9214f31312d9 to your computer and use it in GitHub Desktop.

Win32 Window Basic

Minimal setting to registry window class

The following members of WNDCLASSEX/WNDCLASS are mandatory to register class. Note that name of WNDCLASS structure is NOT WINDOWCLASS or WNDCLS.

  • cbSize
  • lpszClassName (Must be NON-empty string, otherwise, RegisterClass or RegisterClassEx will fail)
  • lpfnWndProc
  • hInstance
  • hCursor (Generally not-necessary but mandatory on layered window)
WNDCLASSEX c;
memset(&c, 0, sizeof(WNDCLASSEX));
c.cbSize = sizeof(WNDCLASSEX);
c.lpszClassName = L"ClassName";
c.lpfnWndProc = reinterpret_cast<WNDPROC>(WndProc);
c.hInstance = i;
c.hCursor = LoadCursor(NULL, IDC_ARROW);
ATOM atom = RegisterClassEx(&c);
if (!atom) return -1;
HWND hwnd = CreateWindowEx(NULL, reinterpret_cast<LPCTSTR>(atom),
  WindowTitle, WS_OVERLAPPED | WS_VISIBLE, 0, 0, WindowWidth, WindowHeight, 
  NULL, NULL, h, NULL);

Minimal definition of message loop

A basic message loop should loop until GetMessage returns -1 or 0

MSG m; BOOL r;
while ((r = GetMessage(&m, NULL, 0, 0)) != 0 && r != -1) {
  TranslateMessage(&m); DispatchMessage(&m);
}
// NOTE: Must call DispatchMessage no matter if TranslateMessage returns non-zero value.
// Otherwise, window will be hung up.
// WRONG short form: TranslateMessage(&m) && DispatchMessage(&m);

In addition, != 0 can be abbreviated, so the most shortest form may be the following:

while (r = GetMessage(&m, NULL, 0, 0) && r != -1) { ...

If you want to completely purge curly brace, combine TranslateMessage and DispatchMessage with bit operator. Do not use && and ||. But, note that this form might be slightly lose performance by meaningless bit operation.

while (r = GetMessage(&m, NULL, 0, 0) && r != -1)
  TranslateMessage(&m) & DispatchMessage(&m);

In addition, compiler may warn like: "warning C4552: '&': operator has no effect". To prevent this, cast its result to void.

while (r = GetMessage(&m, NULL, 0, 0) && r != -1)
  static_cast<void>(TranslateMessage(&m) & DispatchMessage(&m));

CS_HREDRAW and CS_VREDRAW

WNDCLASSEX class;
memset(&class, 0, sizeof(WNDCLASSEX));
class.style = CS_HREDRAW | CS_VREDRAW; // mandatory?
// ...

These "Windows Class Style" are always set on most examples, but they are NOT mandatory for some applications.

They are described as follows at https://msdn.microsoft.com/en-us/library/windows/desktop/ff729176(v=vs.85).aspx

Constant Value Description
CS_HREDRAW 0x0002 Redraws the entire window if a movement or size adjustment changes the width of the client area.
CS_VREDRAW 0x0001 Redraws the entire window if a movement or size adjustment changes the height of the client area.

According to the above, perhaps they invalidate entire window and send WM_ERASEBKGND and WM_PAINT. if your application has non-standard redraw mechanism (like frequent redraw animation), CS_HREDRAW and CS_VREDRAW may be overhead, so they should be unset.

ShowWindow and WS_VISIBLE

int wWinMain(HINSTANCE i, HINSTANCE p, PWSTR c, int s) {
  // ...
  HWND hwnd = CreateWindowEx(...);
  ShowWindow(hwnd, s);

By default, created window is invisible, so, until call ShowWindow, window does not appear and app will works as background process, excepting CreateWindow with WS_VISIBLE.

WS_DESTROY and PostQuitMessage(0)

Application termination is not responsibility of DefWindowProc, so must manually handle WM_DESTROY and call PostQuitMessage(0), otherwise, app will keep running as background process so after window was destroyed.

case WM_DESTROY:
  PostQuitMessage(0);
  break; // return DefWindowProc

Until call ShowWindow, window does not appear and app will works as background process.

Tips of WinMain

int WinMain(HINSTANCE,HINSTANCE,LPSTR,int)
int wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
  • Type of command line string is not const. (LPCSTR LPSTR, PCWSTR PWSTR)
  • The last argument int is used for 2nd argument of ShowWindow (like SW_SHOW)
  • WinMain cannot be used by Unicode programs. The GetCommandLineW function can be used to obtain the command line as a Unicode string. Some programming frameworks might provide an alternative entry point that provides a Unicode command line. For example, the Microsoft Visual Studio C++ complier uses the name wWinMain for the Unicode entry point. ( https://msdn.microsoft.com/en-us/library/windows/desktop/ms633559(v=vs.85).aspx)

Tips of WndProc

LRESULT WndProc(HWND, UINT, WPARAM, LPARAM)

  • WPARAM first
  • No special type defined for message identifier, use UINT. This value is came from message member of MSG structure used by GetMessage, TranslateMessage, and DispatchMessage.
  • Returns LRESULT not HRESULT (Memorise as LRESULT-LPARAM sandwitch)
  • Must bypass to DefWindowProc(HWND, UINT, WPARAM, LPARAM) if no operation by yours.
    • This name is NOT DefWndProc!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment