5 Lifetimes and Threads
dxtr edited this page 2026-10-18 15:34:41 +02:00

Lifetimes and Threads

Releasing

Windows does not free what a program made when the garbage collector drops the handle. Release each thing explicitly:

Thing Make Release Scoped
window class register-window-class unregister-window-class
window create-window destroy-window, on its thread
event object make-event close-event with-event

System cursors, from system-cursor, are shared by every program: never release one.

Destroy a class's windows before unregistering it: unregistering a class that still has windows signals a win32-error (1412). Destroying a window destroys the windows it is the parent of. When a thread ends, its windows are destroyed with it.

Handles are plain integers. A handle released is not marked in any way, and Windows may reuse the number. window-p tells whether a window handle names a window now.

Threads

What Rule
a window belongs to the thread that created it: only that thread takes its messages and may destroy it; any thread may move, size, title, show, post to and send to it
a window class belongs to the program: windows of it may be created on any thread
an event object may be used from any thread
DPI awareness belongs to a thread, for the windows it creates afterwards
a message loop runs on one thread, for that thread's windows
key state belongs to a thread: key-state answers for the message the calling thread is handling
a window's input method used from the window's thread only
the cursor set-cursor from the thread of the window the pointer is over
the pointer's position and clip the desktop's: any thread, but a program holds the pointer only while it has the focus
raw mouse input one window of the program receives it, the last registered
the clipboard the desktop's: one program at a time has it open, which clipboard-text waits for

When another thread moves, sizes or titles a window, Windows sends the messages that causes to the window's thread and waits for it. So the window's thread must be taking messages, and must not be waiting for the calling thread, or neither goes on. The same holds for send-message. See Recipes for a thread that runs windows on behalf of the others.

Allocation

These allocate nothing, so they can run every frame:

  • run-message-loop and process-messages, per message, and the call of a procedure defined with define-window-procedure, up to its body;
  • post-message, set-event, wait-for-event;
  • virtual-key-name, virtual-key-code, key-state, map-virtual-key and the word functions;
  • system-cursor, which a window procedure may call for each +wm-setcursor+;
  • raw-mouse-motion.

peek-message and send-message allocate a little per call, 32 bytes, to catch errors in window procedures. Functions that take strings, such as create-window and (setf window-text), copy them to UTF-16 for Windows, and those that return strings, such as window-text, return fresh ones.