Concepts
Handles
Windows names what it makes with handles: a window is an HWND, the
running program an HINSTANCE, an event object a HANDLE. cl-win32 gives
them all as integers, of the type handle. 0 is no handle, so a function
that takes a window, an event or a cursor refuses it with a type-error.
Integers are plain Lisp values: they compare with =, go into hash
tables, and passing them to Windows allocates nothing.
window-p tells whether an integer is a window that exists.
Window classes and window procedures
Every window has a window class, a name registered with
register-window-class. The class names the window's window procedure:
the function Windows calls with each message for the window.
A message is an integer, such as +wm-size+, with two integer
parameters, wparam and lparam, whose meaning depends on the message.
For +wm-size+, wparam says whether the window is minimised and
lparam's two 16-bit halves are the new width and height. The constants'
docstrings say what each message's parameters are.
A window procedure returns the message's result, an integer, or nil.
nil leaves the message to Windows' default handling,
default-window-procedure, which does what an ordinary window does: draws
the frame, moves and sizes the window when the user drags it, and so on.
Most messages should go there.
See Window Procedures and Classes.
Windows belong to threads
A window belongs to the thread that created it, for its whole life:
- Its messages go to that thread's message queue, and only that thread
can take them, with
run-message-looporprocess-messages. - Only that thread may destroy it.
- Its window procedure runs on that thread, whoever sends it a message.
So a thread that creates windows must also run their message loop, and keep running it: a window whose thread does not take its messages stops responding, and Windows marks it "Not responding" after a few seconds.
Other threads may still use the window: move it, set its title, post and send it messages. Windows passes the work to the window's thread where it must.
Posted and sent messages
There are two ways to give a window a message:
- Posting, with
post-message, puts the message on the queue of the window's thread and returns at once. The message loop takes it later. Input from the user, such as keys and the pointer, arrives this way. - Sending, with
send-message, calls the window procedure and returns its result. From the window's own thread, that is a plain function call. From another thread, Windows hands the message to the window's thread and waits; that thread takes it while it waits for messages, inrun-message-loop.
Many of Windows' own calls send messages. create-window sends
+wm-nccreate+ and +wm-create+ before it returns, destroy-window sends
+wm-destroy+, and set-window-bounds sends +wm-size+.
See Messages and Message Loops.
Errors in window procedures
Windows calls a window procedure from inside its own code. An error must not unwind through that code, so cl-win32 catches it in the procedure, gives the message its default handling, and signals the error again once Windows has returned: from the cl-win32 function during which Windows called the procedure. See Errors.
Pixels and DPI
With per-monitor DPI awareness, which set-thread-dpi-awareness turns on
for a thread, Windows gives sizes and positions in pixels, and tells each
window the DPI of the display it is on: 96 at 100%, 144 at 150%. A
program that draws at the same physical size everywhere scales by the DPI
over 96. See DPI.