Table of Contents
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.