Skip to content

Instantly share code, notes, and snippets.

@Philosoph228
Last active November 22, 2023 05:56
Show Gist options
  • Save Philosoph228/e4bd6bf62c9ec3f3c59780341dd10015 to your computer and use it in GitHub Desktop.
Save Philosoph228/e4bd6bf62c9ec3f3c59780341dd10015 to your computer and use it in GitHub Desktop.

windowsx.h message crackers cheatsheet

This will be helpful for implementing own GUI framework

Quick reference table

Message Callback function signature
WM_CREATE BOOL OnCreate(HWND hWnd, LPCREATESTRUCT lpcs);
WM_SIZE void OnSize(HWND hWnd, UINT state, int x, int y);
WM_DESTROY void OnDestroy(HWND hWnd);
WM_PAINT void OnPaint(HWND hWnd);
WM_LBUTTONDOWN void OnLButtonDown(HWND hWnd, BOOL fDoubleClick, int x, int y, UINT keyFlags);
WM_LBUTTONUP void OnLButtonUp(HWND hWnd, int x, int y, UINT keyFlags);
WM_COMMAND void OnCommand(HWND hWnd, int id, HWND hwndCtl, UINT codeNotify);
WM_KEYUP void OnKeyUp(HWND hWnd, UINT vk, int cRepeat, UINT flags);
WM_KEYDOWN void OnKeyDown(HWND hWnd, UINT vk, int cRepeat, UINT flags);
WM_MOUSEMOVE void OnMouseMove(HWND hWnd, int x, int y, UINT keyFlags);
WM_DRAWITEM void OnDrawItem(HWND hWnd, LPDRAWITEMSTRUCT lpdis);
WM_MEASUREITEM void OnDrawItem(HWND hWnd, LPDRAWITEMSTRUCT lpdis);
WM_NOTIFY void OnNotify(HWND hWnd, int idFrom, LPNMHDR pnmhdr);

Detailed list

WM_CREATE

BOOL OnCreate(HWND hWnd, LPCREATESTRUCT lpcs);

Should return the success status of window initialization of type BOOL. If WM_CREATE returns FALSE, window creation will be considered unsuccessful.

Parameters description

Symbol Argument Description
LPCREATESTRUCT lpcs dynamic cast of lParam Pointer to window creation data structure

Snippets

HANDLE_MSG(hWnd, WM_CREATE, OnCreate);
OnCreate(HWND hWnd, (LPCREATEPARAM)lpcs);
OnCreate(HWND hWnd, reinterpret_cast<LPCREATESTRUCT>(lparam));

WM_SIZE

void OnSize(HWND hWnd, UINT state, int x, int y);

Parameters description

Symbol Argument Description
UINT state static cast of wParam See MSDN
int x LOWORD lParam Updated client area width
int y HIWORD lParam Updated client area height

Snippets

HANDLE_MSG(hWnd, WM_SIZE, OnSize);
OnSize(HWND hWnd, (UINT)wParam, LOWORD(lParam), HIWORD(lParam));
OnSize(HWND hWnd, static_cast<UINT>(wParam), static_cast<int>(LOWORD(lParam)), static_cast<int>(HIWORD(lParam)));

WM_DESTROY

void OnDestroy(HWND hWnd);

Parameters description

None

Snippets

HANDLE_MSG(hWnd, WM_DESTROY, OnDestroy);
OnDestroy(HWND hWnd);
OnDestroy(HWND hWnd);

WM_PAINT

void OnPaint(HWND hWnd);

Parameters description

None

Snippets

HANDLE_MSG(hWnd, WM_PAINT, OnPaint);
OnPaint(HWND hWnd);
OnPaint(HWND hWnd);

WM_DRAWITEM

void OnDrawItem(HWND hWnd, LPDRAWITEMSTRUCT lpdis);

Parameters description

Symbol Argument Description
LPDRAWITEMSTRUCT lpdis reinterpret cast of lParam Pointer to item being drawn

Snippets

HANDLE_MSG(hWnd, WM_DRAWITEM, OnDrawItem);
OnDrawItem(HWND hWnd, (LPDRAWITEMSTRUCT)lParam);
OnDrawItem(HWND hWnd, reinterpret_cast<LPDRAWITEMSTRUCT>(lParam));

WM_MEASUREITEM

In dialogs called before WM_INITDIALOG. Make sure you have your handler registered.

void OnMeasureItem(HWND hWnd, LPMEASUREITEMSTRUCT lpMeasureItem);

Parameters description

Symbol Argument Description
LPMEASUREITEMSTRUCT lpMeasureItem reinterpret cast of lParam Pointer to structure describing the item being measured

Snippets

HANDLE_MSG(hWnd, WM_MEASUREITEM, OnMeasureItem);
OnMeasureItem(HWND hWnd, (LPMEASUREITEMSTRUCT)lParam);
OnMeasureItem(HWND hWnd, reinterpret_cast<LPMEASUREITEMSTRUCT>(lParam));

WM_NOTIFY

void OnNotify(HWND hWnd, int idFrom, LPNMHDR pnmhdr);

Parameters description

Symbol Argument Description
int idFrom static cast of wParam id
LPNMHDR pnmhdr reinterpret cast of lParam id

Snippets

HANDLE_MSG(hWnd, WM_NOTIFY, OnNotify);
OnNotify(HWND hWnd, (int)wParam, (LPNMHDR)lParam);
OnNotify(HWND hWnd, static_cast<int>(wParam), reinterpret_cast<LPNMHDR>(lParam));

Style guide

For unifying the order which message handling follows it might be helpful to order them by message macro values

  1. WM_CREATE
  2. WM_SIZE
  3. WM_PAINT
  4. ...
  5. WM_DESTROY

Examples

C (Plain WinApi)

...

BOOL OnCreate(HWND hWnd, LPCREATESTRUCT lpcs) {
  /* Return TRUE if window initialization succeed, otherwise return FALSE */
  return TRUE;
}

void OnPaint(HWND hWnd) {
  PAINTSTRUCT ps = { 0 };
  
  HDC hdc = BeginPaint(hWnd, &ps);
  Ellipse(hdc, 0, 0, 50, 50);
  EndPaint(hWnd, &ps);
}

void OnDestroy(HWND hWnd) {
  /* Quit application if the window destroys */
  PostQuitMessage(0);
}

/* Static message handling procedure */
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
  switch (message) {
    HANDLE_MSG(hWnd, WM_CREATE, OnCreate);
    HANDLE_MSG(hWnd, WM_PAINT, OnPaint);
    HANDLE_MSG(hWnd, WM_DESTROY, OnDestroy);
  }

  return DefWindowProc(hWnd, message, wParam, lParam);
}

...

C++ (i.e. OOP GUI framework)

class Wnd {
protected:
  virtual BOOL OnCreate(LPCREATESTRUCT);
  virtual void OnPaint();
  virtual void OnDestroy();
  
  virtual LRESULT CALLBACK UserWndProc(UINT message, WPARAM wParam, LPARAM lParam) {
    return ::DefWindowProc(hWnd_, message, wParam, lParam);
  };
  
  HWND hWnd_;

private:
  static LRESULT CALLBACK StaticWndProc(HWND, UINT, WPARAM, LPARAM);
};


/******************
 *  InheritedWnd  *
 ******************/
 
// Define a custom message code
#define WM_INHW_CUSTOMMESSAGE WM_USER + 1

// Define a custom data type for the custom message
struct _tagCUSTOMMESSAGE {
  int x;
};
typedef struct _tagCUSTOMMESSAGE CUSTOMMESSAGE, *PCUSTOMMESSAGE;


class InheritedWnd : public Wnd {
protected:
  void OnCustomMessage(PCUSTOMMESSAGE);

  virtual LRESULT CALLBACK UserWndProc(UINT, WPARAM, LPARAM) final override;
};

BOOL Wnd::OnCreate(LPCREATESTRUCT lpcs) {
  // Use internal field instead of hWnd parameter
  (void)hWnd_;
  
  return TRUE;
}

void Wnd::OnPaint() {
  PAINTSTRUCT ps{};

  HDC hdc = ::BeginPaint(hWnd_, &ps);
  ::Ellipse(hdc, 0, 0, 10, 10);
  ::EndPaint(hWnd_, &ps);
}

void Wnd::OnDestroy() {
  ::PostQuitMessage(0);
}

LRESULT CALLBACK Wnd::StaticWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
  Wnd* wnd = ...; // Somehow obtain the window object pointer
  
  switch (message) {
    case WM_CREATE:
      return wnd->OnCreate((LPCREATESTRUCT)lParam);
      break;
    case WM_PAINT:
      wnd->OnPaint();
      return 0L;
      break;
    case WM_DESTROY:
      wnd->OnDestroy();
      return 0L;
      break;
  }
  
  if (wnd) {
    return wnd->UserWndProc(hWnd, message, wParam, lParam);
  }
  
  // If its not possible to obtain Wnd*, handle message to system:
  return ::DefWindowProc(hWnd, message, wParam, lParam);
}

void InheritedWnd::OnCustomMessage(PCUSTOMMESSAGE pCustMsg) {
  (void)(pCustMsg->x);
}

LRESULT CALLBACK InheritedWnd::UserWndProc(UINT message, WPARAM wParam, LPARAM lParam) {
  switch (message) {
    case WM_INHW_CUSTOMMESSAGE:
      OnCustomMessage((PCUSTOMMESSAGE)lParam);
      return 0L;
      break;
  }

  return ::DefWindowProc(hWnd, message, wParam, lParam);
}

For more practical examples you can check out these projects

  • Taiga (especially, Windöws) by erengy — Lightweight anime tracker for Windows built on top of own Windows GUI framework
  • Panit.ent — Simple raster graphics editor/painter
  • PaniView — Simple image viewer
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment