5 Raw FFI Layer
dxtr edited this page 2026-10-18 15:34:41 +02:00

Raw FFI Layer

The system cl-win32/ffi and the package of the same name hold the raw bindings that cl-win32 is built on: the part of user32, kernel32 and imm32 that cl-win32 uses. The foreign libraries are user32, kernel32 and imm32, the system's DLLs.

Use them only for what cl-win32 does not cover. They do no error checking, take strings as Lisp strings, and leave memory to you. If a common task needs this layer, the idiomatic layer is missing something: please open an issue.

Naming

One Lisp function per C function, the W (UTF-16) form where there are two, named in Lisp case without the W:

C Lisp
CreateWindowExW create-window-ex
DefWindowProcW def-window-proc
GetDpiForWindow get-dpi-for-window
MsgWaitForMultipleObjectsEx msg-wait-for-multiple-objects-ex

x86-64 Windows has one calling convention, so each function is a plain cl-ffi:defcfun, which declaims the function's ftype from its types.

Strings

A string argument, an LPCWSTR, is of the cl-ffi type wide-string, (:string :encoding :utf-16le): a Lisp string, which cl-ffi copies to UTF-16 for the call and frees after it, or a pointer as it is, such as a null pointer where Windows takes none. Strings Windows writes into a buffer, as get-window-text does, come as pointers to the buffer: read them with cl-ffi:foreign-string-to-lisp and :encoding :utf-16le.

Handles

Handles of every kind are integers, of the cl-ffi type handle (:uintptr), in arguments, results and struct slots alike. So the results of this layer can be handed to cl-win32 and back without conversion, and passing them allocates nothing.

Contents

kernel32: get-module-handle, get-last-error, set-last-error, format-message, local-free, create-event, set-event, reset-event, wait-for-single-object, close-handle, get-current-thread-id; and the global memory the clipboard takes, global-alloc, global-lock, global-unlock, global-size, global-free.

Window classes and windows: register-class-ex, unregister-class, load-cursor, create-window-ex, destroy-window, is-window, enable-window, is-window-enabled, show-window, set-window-text, get-window-text, get-window-text-length, get-client-rect, get-window-rect, set-window-pos, validate-rect, get-window-thread-process-id, get-window-long-ptr, set-window-long-ptr, get-window-placement, set-window-placement.

Displays: monitor-from-window, monitor-from-rect, get-monitor-info.

DPI: set-thread-dpi-awareness-context, get-dpi-for-window, adjust-window-rect-ex-for-dpi.

Messages: def-window-proc, get-message, peek-message, translate-message, dispatch-message, post-message, send-message, post-quit-message, msg-wait-for-multiple-objects-ex, get-message-time, get-message-pos.

Keyboard and pointer: get-key-state, map-virtual-key, track-mouse-event, set-capture, release-capture, get-capture, screen-to-client, client-to-screen, get-system-metrics, set-cursor, get-cursor-pos, set-cursor-pos, clip-cursor, get-clip-cursor, register-raw-input-devices, get-raw-input-data.

Clipboard: open-clipboard, close-clipboard, empty-clipboard, is-clipboard-format-available, get-clipboard-data, set-clipboard-data.

imm32: imm-get-context, imm-release-context, imm-associate-context-ex, imm-get-composition-string, imm-set-candidate-window, imm-get-candidate-window, imm-set-composition-window, imm-notify-ime.

Structs: wndclassex, msg, rect, point, trackmouseevent, monitorinfo, windowplacement, candidateform, compositionform, rawinputdevice, rawinputheader, rawmouse and rawinput-mouse, with the slots size, style, wndproc, cls-extra, wnd-extra, instance, icon, cursor, background, menu-name, name, small-icon; hwnd, message, wparam, lparam, message-time, pt, private; left, top, right, bottom; x, y; flags, hwnd-track, hover-time; monitor, work; show-command, min-position, max-position, normal-position; index, current-position, area; usage-page, usage, target; input-type, device; raw-buttons, buttons, last-x, last-y, extra-information; header, mouse.

(cl-ffi:with-foreign-object (rect '(:struct cl-win32/ffi:rect))
  (cl-win32/ffi:get-client-rect window rect)
  (cl-ffi:foreign-slot-value rect '(:struct cl-win32/ffi:rect) 'cl-win32/ffi:right))

The constants, such as message numbers, live in cl-win32: they are plain integers, and work with both layers.