I'm trying to use the CLISP FFI to call some Win32 functions.
I was able to make a call out and have that call a callback in Lisp, but now I can't figure out how to access the values passed to the callback.
One of the values is a pointer to a struct
. I have the structure defined ok, I can print it and get a #<FOREIGN-VARIABLE #x00000000>
or wrap it in foreign-address
and get #<FOREIGN-ADDRESS #x00000000>
(not the real value or addr in either), but when I try to deref
it I get the following:
*** - FFI:DEREF is only allowed after FFI:FOREIGN-VALUE:
(FFI:DEREF (FFI:FOREIGN-ADDRESS PRECT*))
I've tried to wrap the foreign-address
call in foreign-value
, tried to use with-c-place
, and other things, but nothing works. I either get nothing printed (in which case I assume there was an error during the call and it borked), or I get that error.
The only documentation I've been able to find is this dffi reference but it has scant examples and the documentation for those functions isn't clear.
Anyone have any pointers? (Pun!) Should I switch to CFFI/UFFI or SBCL even?
Update
I got it to print the struct out once after wrapping the pointer in foreign-value
reload
ing it in the REPL (without exiting), then it seemed to error in the callback for subsequent reload
s.
Edit
Still can't get it working; here's the code:
(defpackage "WIN32")
(in-package "WIN32")
(use-package "FFI")
; Listen for a WM_DISPLAYCHANGE message to get notifications of when
; a monitor (setting) is added/removed/changed
(def-c-type BOOL boolean)
(def-c-type CHAR char)
(def-c-type DWORD uint)
(def-c-type HANDLE c-pointer)
(def-c-type HDC HANDLE)
(def-c-type HMONITOR HANDLE)
(def-c-type HWND HANDLE)
(def-c-type LONG long)
(def-c-type LPARAM c-pointer)
(def-c-type LPCSTR c-string)
(def-c-type LPCTSTR LPCSTR) ; LPCWSTR
;(def-c-type LPCWSTR )
(def-c-type TCHAR CHAR) ; WCHAR
;(def-c-type WCHAR )
(defun symbol-to-keyword (sym)
(intern (symbol-name sym) :keyword))
(defun affix-to-symbol (prefix sym suffix)
(intern (concatenate 'string prefix (symbol-name sym) suffix)))
(defun car-symbol-to-keyword (pair)
(cons
(symbol-to-keyword (car pair))
(cdr pair)))
(defmacro def-struct-type (name &rest fields)
`(progn
(def-c-struct ,name ,@fields)
(def-c-type
,(affix-to-symbol "P" name "")
(c-pointer ,name))
(defconstant
,(affix-to-symbol "" name "-INSTANCE")
'(c-struct ,name ,@(mapcar #'car-symbol-to-keyword fields)))
))
;typedef struct _RECT {
; LONG left;
; LONG top;
; LONG right;
; LONG bottom;
;} RECT, *PRECT;
(def-struct-type RECT
(left LONG)
(top LONG)
(right LONG)
(bottom LONG))
;BOOL CALLBACK MonitorEnumProc(
; _In_ HMONITOR hMonitor,
; _In_ HDC hdcMonitor,
; _In_ LPRECT lprcMonitor,
; _In_ LPARAM dwData
;);
;BOOL EnumDisplayMonitors(
; _In_ HDC hdc,
; _In_ LPCRECT lprcClip,
; _In_ MONITORENUMPROC lpfnEnum,
; _In_ LPARAM dwData
;);
(def-call-out EnumDisplayMonitors
(:name "EnumDisplayMonitors")
(:library "User32.dll")
(:arguments
(hdc HDC)
(lprcClip PRECT)
(lpfnEnum
(c-function
(:arguments
(hMonitor HMONITOR)
(hdcMonitor HDC)
(lprcMonitor PRECT)
(dwData LPARAM))
(:return-type BOOL)
(:language :stdc-stdcall)))
(dwData LPARAM))
(:return-type BOOL)
(:language :stdc-stdcall))
(export 'EnumDisplayMonitors)
(defun callback (hmon hdc* prect* data)
(progn
(format t "~A ~A ~A ~A~%" hmon hdc* (foreign-address prect*) data)
t))
(EnumDisplayMonitors nil nil #'callback nil)