4 Errors
dxtr edited this page 2026-10-18 16:25:37 +02:00

Errors

Failed calls

A Win32 function that fails signals a win32-error:

(win32:destroy-window 12345)
;; signals: DestroyWindow failed with Windows error 1400: Invalid window handle.

(handler-case (win32:destroy-window 12345)
  (win32:win32-error (condition)
    (list (win32:win32-error-function condition)    ; => "DestroyWindow"
          (win32:win32-error-code condition)        ; => 1400
          (win32:win32-error-message condition))))  ; => "Invalid window handle."

The code is Windows' own, as GetLastError gives it, and the message is Windows' description of it, in the system's language. Codes you may meet:

Code Name Usually
5 ERROR_ACCESS_DENIED destroying a window from a thread it does not belong to
1400 ERROR_INVALID_WINDOW_HANDLE a window that does not exist, or was destroyed
1407 ERROR_CANNOT_FIND_WND_CLASS creating a window of a class not registered
1410 ERROR_CLASS_ALREADY_EXISTS registering a class name twice
1412 ERROR_CLASS_HAS_WINDOWS unregistering a class whose windows still exist

The clipboard functions signal a win32-error from OpenClipboard when another program keeps the clipboard open for longer than their :timeout, or while the session is locked, when Windows gives no program the clipboard; the message says both.

Arguments of the wrong type signal a type-error before Windows is called: each function declaims the full domain of its arguments, and SBCL checks it when the function is called, and warns of a constant outside it when it compiles the call. A window, an event or a cursor is never 0, which names nothing, a width or a height is never negative, and the keywords a function takes are types, such as window-style, show-command and system-cursor-name:

(win32:show-window 0)
;; signals: The value 0 is not of type (INTEGER 1 18446744073709551615) when binding CL-WIN32::WINDOW

A list of styles is checked keyword by keyword, and an unknown one signals a type-error that lists the styles there are. So do arguments that go together given alone: set-window-bounds's :x without :y, or clip-cursor's rectangle in part.

Errors in window procedures

Windows calls a window procedure from inside its own code, and a Lisp error must not unwind through that. So the procedure that define-window-procedure defines catches an error its body signals, gives the message its default handling, and keeps the error. The cl-win32 function during which Windows called the procedure signals it once Windows has returned:

Windows called the procedure during The error comes from
the message loop run-message-loop or process-messages, right after that message
a message sent from the same thread send-message
creating or destroying a window create-window or destroy-window
sizing, showing or titling a window set-window-bounds, show-window, (setf window-text)
changing its styles or placement change-window-styles, set-window-placement
putting text on the clipboard, as its owner clipboard-text or (setf clipboard-text)
looking ahead peek-message

Only the first error during one call is kept. The window is otherwise unharmed: a window whose +wm-destroy+ handling fails is destroyed all the same. run-message-loop may be called again to go on.

A message sent from another thread runs in the window's thread, so its error comes from that thread's message loop, not from the sender's send-message. To hand an error back to the sender, catch it in the procedure, as the first of the Recipes does.

A body must not leave by any other non-local exit: no throw, return-from or go out of it, and no restarts established outside it.

If Windows calls a window procedure outside any cl-win32 call, which only happens when other foreign code runs a message loop, there is nowhere to signal the error, and cl-win32 warns instead.