Without creating global variables, is there a way to pass variables to the WindowProcedure that handles the messages?

For example, if I create a variable and initialize it in WinMain, is there any way to use it in my WindowProcedure?

What I am doing is this. I have a class called Map. I also have a class called Texture and Window.

When I create Texture and Window, certain variables are created such as texWidth, texHeight, windowWidth, and WindowHeight inside of the class.

In my Window Procedure, I need to use those variables held inside of Texture and Window for some function calls.

Is there any way to do this easily? I would really like to keep it simple and try to avoid global variables if possible.

Dani AI

Generated

Both and are pointing at the right ideas. The clean, non-global approach is to associate your per-window state (your Window/Texture/Map objects or a small struct holding their pointers) with the HWND and then forward messages to that object. lParam/wParam are for individual messages; they won't give you persistent per-window storage across arbitrary messages.

A common, robust pattern is a static window procedure that installs an object pointer when the window is created and then forwards every message to an instance method. Example (illustrative):

class Window {
  HWND hwnd;
  // texture/map members...

  static LRESULT CALLBACK WndProcStatic(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    Window* self = nullptr;
    if (msg == WM_NCCREATE) {
      CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(lParam);
      self = reinterpret_cast<Window*>(cs->lpCreateParams);
      SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(self));
      self->hwnd = hWnd;
    } else {
      self = reinterpret_cast<Window*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
    }
    return self ? self->HandleMessage(msg, wParam, lParam)
                : DefWindowProc(hWnd, msg, wParam, lParam);
  }

  LRESULT HandleMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
    if (msg == WM_NCDESTROY) {
      SetWindowLongPtr(hwnd, GWLP_USERDATA, 0);
      delete this; // only if ownership was transferred
      return 0;
    }
    // use texture/window members here...
    return DefWindowProc(hwnd, msg, wParam, lParam);
  }
};

Practical notes and pitfalls:

  • Use WM_NCCREATE/CREATESTRUCT::lpCreateParams to get the pointer passed at CreateWindowEx time; this arrives earlier than WM_CREATE (WM_NCCREATE, CREATESTRUCT).
  • Store pointers with SetWindowLongPtr / read with GetWindowLongPtr (not SetWindowLong) to be safe on 64-bit (SetWindowLongPtr).
  • Free per-window resources in WM_NCDESTROY (not earlier) to avoid receiving messages after deletion (WM_NCDESTROY). Delete only if the window owns the object; if the object is stack-allocated or shared, skip deletion.
  • If you need safer subclassing or to avoid touching GWLP_USERDATA, consider SetWindowSubclass / DefSubclassProc APIs (SetWindowSubclass).
  • As an alternative, a thread-local or global map from HWND to your object (erase on WM_NCDESTROY) works too, but requires careful synchronization if windows are created on multiple threads.

This keeps your design object-oriented, avoids file-scope globals, and gives a clear place to use texWidth, windowWidth etc. inside instance message handlers.

Recommended Answers

All 2 Replies

define a struct to hold the data/operations for your window

struct my_window_stuff
{
// functions          // ...
// data                     // Texture
// Window
// Map
// whatever else
};

In main/WinMain:
1. initialize a my_window_stuff structure.
2. pass its address (pointer) in the LPARAM argument of CreateWindow/CreateWindowEx

in the window procedure:
case WM_CREATE: store the pointer received (in CREATESTRUCT::lpCreateParams) in the window data
using SetWindowLong/SetWindowLongPtr with WL_USERDATA/GWLP_USERDATA as index.

subsequent messages: retrieve the pointer through GetWindowLong/GetWindowLongPtr,
cast it to my_window_stuff* and use it.

note: if the my_window_stuff needs to be allocated using new (for instance if CreateWindow/CreateWindowEx needs to be called from somewhere other than main/WinMain),
case WM_DESTROY: retrieve the pointer, cast and delete

What Vijayon is talking about I really can't guess.
Global structures and global variables are one and the same
or at least of the same generic route.

WindowProcedure is a a callback funtion, you use lParam amd wParm
to transport variables with the additional facility of HIWORD and LOWORD .

Both of you need to delve into win32 system services!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.