ecl/contrib/win32/win32.lisp
2015-09-01 20:10:10 +00:00

638 lines
34 KiB
Common Lisp

;;; Copyright (c) 2005, Michael Goffioul (michael dot goffioul at swing dot be)
;;;
;;; This program is free software; you can redistribute it and/or
;;; modify it under the terms of the GNU Library General Public
;;; License as published by the Free Software Foundation; either
;;; version 2 of the License, or (at your option) any later version.
;;;
;;; See file '../../Copyright' for full details.
;;;
;;; FOREIGN FUNCTION INTERFACE TO MICROSOFT WINDOWS API
;;;
(defpackage "WIN32"
(:use "COMMON-LISP" "FFI")
(:export))
(in-package "WIN32")
(clines
"#include <windows.h>"
"#include <commctrl.h>"
)
;; Windows types
(def-foreign-type HANDLE :pointer-void)
(def-foreign-type LPCSTR :cstring)
(def-foreign-type WNDPROC :pointer-void)
(def-foreign-type DWORD :unsigned-int)
(def-foreign-type WORD :unsigned-short)
;; Windows constants
(defmacro define-win-constant (name value &optional (c-type :int))
`(defconstant ,name ,value))
(define-win-constant *TRUE* 1)
(define-win-constant *FALSE* 0)
(define-win-constant *WM_CLOSE* #x0010)
(define-win-constant *WM_COMMAND* #x0111)
(define-win-constant *WM_CONTEXTMENU* #x007b)
(define-win-constant *WM_COPY* #x0301)
(define-win-constant *WM_CREATE* #x0001)
(define-win-constant *WM_CUT* #x0300)
(define-win-constant *WM_DESTROY* #x0002)
(define-win-constant *WM_GETFONT* #x0031)
(define-win-constant *WM_GETMINMAXINFO* #x0024)
(define-win-constant *WM_INITMENU* #x0116)
(define-win-constant *WM_INITMENUPOPUP* #x0117)
(define-win-constant *WM_NCPAINT* #x0085)
(define-win-constant *WM_NOTIFY* #x004e)
(define-win-constant *WM_PAINT* #x000f)
(define-win-constant *WM_PASTE* #x0302)
(define-win-constant *WM_QUIT* #x0012)
(define-win-constant *WM_SETFOCUS* #x0007)
(define-win-constant *WM_SETFONT* #x0030)
(define-win-constant *WM_SIZE* #x0005)
(define-win-constant *WM_UNDO* #x0304)
(define-win-constant *WM_USER* #x0400)
(define-win-constant *WS_BORDER* #x00800000)
(define-win-constant *WS_CHILD* #x40000000)
(define-win-constant *WS_CLIPCHILDREN* #x02000000)
(define-win-constant *WS_CLIPSIBLINGS* #x04000000)
(define-win-constant *WS_DLGFRAME* #x00400000)
(define-win-constant *WS_DISABLED* #x08000000)
(define-win-constant *WS_HSCROLL* #x00100000)
(define-win-constant *WS_OVERLAPPEDWINDOW* #x00CF0000)
(define-win-constant *WS_VISIBLE* #x10000000)
(define-win-constant *WS_VSCROLL* #x00200000)
(define-win-constant *WS_EX_CLIENTEDGE* #x00000200)
(define-win-constant *RICHEDIT_CLASS* "RichEdit20A")
(define-win-constant *WC_LISTVIEW* "SysListView32")
(define-win-constant *WC_TABCONTROL* "SysTabControl32")
(define-win-constant *HWND_BOTTOM* (make-pointer 1 'HANDLE))
(define-win-constant *HWND_NOTOPMOST* (make-pointer -2 'HANDLE))
(define-win-constant *HWND_TOP* (make-pointer 0 'HANDLE))
(define-win-constant *HWND_TOPMOST* (make-pointer -1 'HANDLE))
(define-win-constant *SWP_DRAWFRAME* #x0020)
(define-win-constant *SWP_HIDEWINDOW* #x0080)
(define-win-constant *SWP_NOMOVE* #x0002)
(define-win-constant *SWP_NOOWNERZORDER* #x0200)
(define-win-constant *SWP_NOREDRAW* #x0008)
(define-win-constant *SWP_NOREPOSITION* #x0200)
(define-win-constant *SWP_NOSIZE* #x0001)
(define-win-constant *SWP_NOZORDER* #x0004)
(define-win-constant *SWP_SHOWWINDOW* #x0040)
(define-win-constant *BS_DEFPUSHBUTTON* #x00000000)
(define-win-constant *BS_PUSHBUTTON* #x00000001)
(define-win-constant *BN_CLICKED* 0)
(define-win-constant *ES_AUTOHSCROLL* #x0080)
(define-win-constant *ES_AUTOVSCROLL* #x0040)
(define-win-constant *ES_LEFT* #x0000)
(define-win-constant *ES_MULTILINE* #x0004)
(define-win-constant *EM_CANUNDO* #x00c6)
(define-win-constant *EM_SETEVENTMASK* (+ *WM_USER* 69))
(define-win-constant *EM_SETSEL* #x00b1)
(define-win-constant *EM_UNDO* #x00c7)
(define-win-constant *EN_CHANGE* #x0300)
(define-win-constant *ENM_CHANGE* #x00000001)
(define-win-constant *TCIF_IMAGE* #x0002)
(define-win-constant *TCIF_PARAM* #x0008)
(define-win-constant *TCIF_RTLREADING* #x0004)
(define-win-constant *TCIF_STATE* #x0010)
(define-win-constant *TCIF_TEXT* #x0001)
(define-win-constant *TCHT_NOWHERE* #x0001)
(define-win-constant *TCHT_ONITEM* #x0006)
(define-win-constant *TCHT_ONITEMICON* #x0002)
(define-win-constant *TCHT_ONITEMLABEL* #x0004)
(define-win-constant *TCM_FIRST* #x1300)
(define-win-constant *TCN_FIRST* #xfffffdda)
(define-win-constant *TCM_ADJUSTRECT* (+ *TCM_FIRST* 40))
(define-win-constant *TCM_DELETEITEM* (+ *TCM_FIRST* 8))
(define-win-constant *TCM_GETCURSEL* (+ *TCM_FIRST* 11))
(define-win-constant *TCM_HITTEST* (+ *TCM_FIRST* 13))
(define-win-constant *TCM_INSERTITEM* (+ *TCM_FIRST* 7))
(define-win-constant *TCM_SETCURSEL* (+ *TCM_FIRST* 12))
(define-win-constant *TCM_SETITEM* (+ *TCM_FIRST* 6))
(define-win-constant *TCN_SELCHANGE* (- *TCN_FIRST* 1))
(define-win-constant *NM_FIRST* #x100000000)
(define-win-constant *NM_CLICK* (- *NM_FIRST* 1))
(define-win-constant *NM_RCLICK* (- *NM_FIRST* 5))
(define-win-constant *SW_HIDE* 0)
(define-win-constant *SW_SHOW* 5)
(define-win-constant *SW_SHOWNORMAL* 1)
(define-win-constant *RDW_ERASE* #x0004)
(define-win-constant *RDW_FRAME* #x0400)
(define-win-constant *RDW_INTERNALPAINT* #x0002)
(define-win-constant *RDW_INVALIDATE* #x0001)
(define-win-constant *RDW_NOERASE* #x0020)
(define-win-constant *RDW_NOFRAME* #x0800)
(define-win-constant *RDW_NOINTERNALPAINT* #x0010)
(define-win-constant *RDW_VALIDATE* #x0008)
(define-win-constant *RDW_ERASENOW* #x0200)
(define-win-constant *RDW_UPDATENOW* #x0100)
(define-win-constant *RDW_ALLCHILDREN* #x0080)
(define-win-constant *RDW_NOCHILDREN* #x0040)
(define-win-constant *CW_USEDEFAULT* (- #x80000000))
(define-win-constant *IDC_ARROW* 32512)
(define-win-constant *IDI_APPLICATION* 32512)
(define-win-constant *COLOR_BACKGROUND* 1)
(define-win-constant *DEFAULT_GUI_FONT* 17)
(define-win-constant *OEM_FIXED_FONT* 10)
(define-win-constant *SYSTEM_FONT* 13)
(define-win-constant *SYSTEM_FIXED_FONT* 16)
(define-win-constant *MB_HELP* #x00004000)
(define-win-constant *MB_OK* #x00000000)
(define-win-constant *MB_OKCANCEL* #x00000001)
(define-win-constant *MB_YESNO* #x00000004)
(define-win-constant *MB_YESNOCANCEL* #x00000003)
(define-win-constant *MB_ICONEXCLAMATION* #x00000030)
(define-win-constant *MB_ICONWARNING* #x00000020)
(define-win-constant *MB_ICONERROR* #x00000010)
(define-win-constant *MB_ICONINFORMATION* #x00000040)
(define-win-constant *MB_ICONQUESTION* #x00000020)
(define-win-constant *IDCANCEL* 2)
(define-win-constant *IDNO* 7)
(define-win-constant *IDOK* 1)
(define-win-constant *IDYES* 6)
(define-win-constant *MF_BYCOMMAND* #x00000000)
(define-win-constant *MF_BYPOSITION* #x00000400)
(define-win-constant *MF_CHECKED* #x00000008)
(define-win-constant *MF_DISABLED* #x00000002)
(define-win-constant *MF_ENABLED* #x00000000)
(define-win-constant *MF_GRAYED* #x00000001)
(define-win-constant *MF_MENUBREAK* #x00000040)
(define-win-constant *MF_POPUP* #x00000010)
(define-win-constant *MF_SEPARATOR* #x00000800)
(define-win-constant *MF_STRING* #x00000000)
(define-win-constant *MF_UNCHECKED* #x00000000)
(define-win-constant *TPM_CENTERALIGN* #x0004)
(define-win-constant *TPM_LEFTALIGN* #x0000)
(define-win-constant *TPM_RIGHTALIGN* #x0008)
(define-win-constant *TPM_BOTTOMALIGN* #x0020)
(define-win-constant *TPM_TOPALIGN* #x0000)
(define-win-constant *TPM_VCENTERALIGN* #x0010)
(define-win-constant *TPM_NONOTIFY* #x0080)
(define-win-constant *TPM_RETURNCMD* #x0100)
(define-win-constant *TPM_LEFTBUTTON* #x0000)
(define-win-constant *TPM_RIGHTBUTTON* #x0002)
(define-win-constant *OFN_FILEMUSTEXIST* #x00001000)
(define-win-constant *OFN_OVERWRITEPROMPT* #x00000002)
(define-win-constant *OFN_PATHMUSTEXIST* #x00000800)
(define-win-constant *OFN_READONLY* #x00000001)
(define-win-constant *FVIRTKEY* *TRUE*)
(define-win-constant *FNOINVERT* #x02)
(define-win-constant *FSHIFT* #x04)
(define-win-constant *FCONTROL* #x08)
(define-win-constant *FALT* #x10)
(define-win-constant *VK_F1* #x70)
(define-win-constant *VK_LEFT* #x25)
(define-win-constant *VK_RIGHT* #x27)
(define-win-constant *GWL_EXSTYLE* -20)
(define-win-constant *GWL_HINSTANCE* -6)
(define-win-constant *GWL_HWNDPARENT* -8)
(define-win-constant *GWL_ID* -12)
(define-win-constant *GWL_STYLE* -16)
(define-win-constant *GWL_WNDPROC* -4)
(define-win-constant *FINDMSGSTRING* "commdlg_FindReplace")
(define-win-constant *HELPMSGSTRING* "commdlg_help")
(define-win-constant *FR_DIALOGTERM* #x00000040)
(define-win-constant *FR_DOWN* #x00000001)
(define-win-constant *FR_FINDNEXT* #x00000008)
(define-win-constant *FR_HIDEUPDOWN* #x00004000)
(define-win-constant *FR_HIDEMATCHCASE* #x00008000)
(define-win-constant *FR_HIDEWHOLEWORD* #x00010000)
(define-win-constant *FR_MATCHCASE* #x00000004)
(define-win-constant *FR_NOMATCHCASE* #x00000800)
(define-win-constant *FR_NOUPDOWN* #x00000400)
(define-win-constant *FR_NOWHOLEWORD* #x00001000)
(define-win-constant *FR_REPLACE* #x00000010)
(define-win-constant *FR_REPLACEALL* #x00000020)
(define-win-constant *FR_SHOWHELP* #x00000080)
(define-win-constant *FR_WHOLEWORD* #x00000002)
(defconstant *NULL* (make-null-pointer :void))
;; Windows structures
(def-struct WNDCLASS
(style :unsigned-int)
(lpfnWndProc WNDPROC)
(cbClsExtra :int)
(cbWndExtra :int)
(hInstance HANDLE)
(hIcon HANDLE)
(hCursor HANDLE)
(hbrBackground HANDLE)
(lpszMenuName :cstring)
(lpszClassName :cstring))
(defun make-wndclass (name &key (style 0) (lpfnWndProc nil) (cbClsExtra 0) (cbWndExtra 0) (hInstance *NULL*)
(hIcon (default-icon)) (hCursor (default-cursor)) (hbrBackground (default-background))
(lpszMenuName ""))
(with-foreign-object (cls 'WNDCLASS)
(setf (get-slot-value cls 'WNDCLASS 'style) style
(get-slot-value cls 'WNDCLASS 'lpfnWndProc) (callback 'wndproc-proxy)
(get-slot-value cls 'WNDCLASS 'cbClsExtra) cbClsExtra
(get-slot-value cls 'WNDCLASS 'cbWndExtra) cbWndExtra
(get-slot-value cls 'WNDCLASS 'hInstance) hInstance
(get-slot-value cls 'WNDCLASS 'hIcon) hIcon
(get-slot-value cls 'WNDCLASS 'hCursor) hCursor
(get-slot-value cls 'WNDCLASS 'hbrBackground) hbrBackground
(get-slot-value cls 'WNDCLASS 'lpszMenuName) lpszMenuName
(get-slot-value cls 'WNDCLASS 'lpszClassName) (string name))
(register-wndproc (string name) lpfnWndProc)
(registerclass cls)))
(def-struct POINT
(x :int)
(y :int))
(def-struct MSG
(hwnd HANDLE)
(message :unsigned-int)
(wParam :unsigned-int)
(lParam :int)
(time :unsigned-int)
(pt POINT))
(def-struct CREATESTRUCT
(lpCreateParams :pointer-void)
(hInstance HANDLE)
(hMenu HANDLE)
(hwndParent HANDLE)
(cx :int)
(cy :int)
(x :int)
(y :int)
(style :long)
(lpszName :cstring)
(lpszClass :cstring)
(dwExStyle :unsigned-int))
(def-struct MINMAXINFO
(ptReserved POINT)
(ptMaxSize POINT)
(ptMaxPosition POINT)
(ptMinTrackSize POINT)
(ptMaxTrackSize POINT))
(def-struct TEXTMETRIC (tmHeight :long) (tmAscent :long) (tmDescent :long) (tmInternalLeading :long) (tmExternalLeading :long)
(tmAveCharWidth :long) (tmMaxCharWidth :long) (tmWeight :long) (tmOverhang :long) (tmDigitizedAspectX :long)
(tmDigitizedAspectY :long) (tmFirstChar :char) (tmLastChar :char) (tmDefaultChar :char) (tmBreakChar :char)
(tmItalic :byte) (tmUnderlined :byte) (tmStruckOut :byte) (tmPitchAndFamily :byte) (tmCharSet :byte))
(def-struct SIZE (cx :long) (cy :long))
(def-struct RECT (left :long) (top :long) (right :long) (bottom :long))
(def-struct TITLEBARINFO (cbSize :unsigned-int) (rcTitlebar RECT) (rgstate (:array :unsigned-int 6)))
(def-struct OPENFILENAME (lStructSize :unsigned-int) (hwndOwner HANDLE) (hInstance HANDLE) (lpstrFilter LPCSTR) (lpstrCustomFilter LPCSTR)
(nMaxFilter :unsigned-int) (nFilterIndex :unsigned-int) (lpstrFile LPCSTR) (nMaxFile :unsigned-int) (lpstrFileTitle LPCSTR)
(nMaxFileTitle :unsigned-int) (lpstrInitialDir LPCSTR) (lpstrTitle LPCSTR) (Flags :unsigned-int) (nFileOffset :unsigned-short)
(nFileExtension :unsigned-short) (lpstrDefExt LPCSTR) (lCustData :int) (lpfnHook HANDLE) (lpTemplateName LPCSTR)
#|(pvReserved :pointer-void) (dwReserved :unsigned-int) (FlagsEx :unsigned-int)|#)
(def-struct ACCEL (fVirt :byte) (key :unsigned-short) (cmd :unsigned-short))
(def-struct TCITEM (mask :unsigned-int) (dwState :unsigned-int) (dwStateMask :unsigned-int)
(pszText :cstring) (cchTextMax :int) (iImage :int) (lParam :long))
(def-struct NMHDR (hwndFrom HANDLE) (idFrom :unsigned-int) (code :unsigned-int))
(def-struct TCHITTESTINFO (pt POINT) (flag :unsigned-int))
(def-struct TPMPARAMS (cbSize :unsigned-int) (rcExclude RECT))
(def-struct FINDREPLACE (lStructSize :unsigned-int) (hwndOwner HANDLE) (hInstance HANDLE) (Flags DWORD)
(lpstrFindWhat LPCSTR) (lpstrReplaceWith LPCSTR) (wFindWhatLen WORD) (wReplaceWithLen WORD)
(lpCustData :int) (lpfnHook HANDLE) (lpTemplateName LPCSTR))
;; Windows functions
(defvar *wndproc-db* nil)
(defun register-wndproc (class-or-obj wndproc)
(let ((entry (assoc class-or-obj *wndproc-db* :test #'equal)))
(if entry
(rplacd entry wndproc)
(push (cons class-or-obj wndproc) *wndproc-db*)))
(unless (stringp class-or-obj)
(let ((old-proc (make-pointer (getwindowlong class-or-obj *GWL_WNDPROC*) 'HANDLE)))
(setwindowlong class-or-obj *GWL_WNDPROC* (make-lparam (callback 'wndproc-proxy)))
old-proc)))
(defun get-wndproc (obj)
(let ((entry (or (assoc obj *wndproc-db* :test #'equal)
(assoc (getclassname obj) *wndproc-db* :test #'equal))))
(and entry
(cdr entry))))
(defcallback (wndproc-proxy :stdcall) :int ((hnd :pointer-void) (umsg :unsigned-int) (wparam :unsigned-int) (lparam :int))
(let* ((wndproc (get-wndproc hnd)))
(unless wndproc
(error "Cannot find a registered Windows prodecure for object ~S" hnd))
(funcall wndproc hnd umsg wparam lparam)))
(defun make-ID (id) (make-pointer id :pointer-void))
(setf (symbol-function 'make-handle) #'make-ID)
(defun make-wparam (hnd) (pointer-address hnd))
(defun make-lparam (hnd) (pointer-address hnd))
(defmacro with-cast-int-pointer ((var type &optional ptr) &body body)
(unless ptr (setq ptr var))
`(let ((,var (make-pointer ,ptr ',type))) ,@body))
(defmacro def-win32-function (name args &key (returning :void) module)
`(def-function ,name ,args :returning ,returning :module ,module :call :stdcall))
(eval-when (:compile-toplevel)
(define-compiler-macro def-win32-function (name args &key (returning :void) module)
`(def-function ,name ,args :returning ,returning)))
(load-foreign-library "kernel32")
(load-foreign-library "comdlg32")
(load-foreign-library "gdi32")
(load-foreign-library "comctl32")
(def-win32-function ("RtlZeroMemory" zeromemory) ((Destination :pointer-void) (Length :unsigned-int)) :returning :void :module "kernel32")
(def-win32-function ("LoadLibraryA" loadlibrary) ((lpLibFileName LPCSTR)) :returning HANDLE :module "kernel32")
(def-win32-function ("FreeLibrary" freelibrary) ((hLibModule HANDLE)) :returning :int :module "kernel32")
(def-win32-function ("GetModuleHandleA" getmodulehandle) ((lpModuleName LPCSTR)) :returning HANDLE :module "kernel32")
(def-win32-function ("GetStockObject" getstockobject) ((fnObject :int)) :returning HANDLE :module "gdi32")
(def-win32-function ("GetTextMetricsA" gettextmetrics) ((hdc HANDLE) (lptm (* TEXTMETRIC))) :returning :int :module "gdi32")
(def-win32-function ("GetDC" getdc) ((hWnd HANDLE)) :returning HANDLE :module "user32")
(def-win32-function ("ReleaseDC" releasedc) ((hWnd HANDLE) (hdc HANDLE)) :returning :int :module "user32")
(def-win32-function ("SelectObject" selectobject) ((hdc HANDLE) (hgdiobj HANDLE)) :returning HANDLE :module "gdi32")
(def-win32-function ("GetTextExtentPoint32A" gettextextentpoint32) ((hdc HANDLE) (lpString :cstring) (cbString :int) (lpSize (* SIZE))) :returning :int :module "gdi32")
(def-win32-function ("LoadCursorA" loadcursor-string) ((hnd HANDLE) (lpCursorName LPCSTR)) :returning HANDLE :module "user32")
(def-win32-function ("LoadCursorA" loadcursor-int) ((hnd HANDLE) (lpCursorName :unsigned-int)) :returning HANDLE :module "user32")
(defun loadcursor (hnd cur-name)
(etypecase cur-name
(fixnum (loadcursor-int hnd cur-name))
(string (loadcursor-string hnd cur-name))))
(defun default-cursor () (loadcursor *NULL* *IDC_ARROW*))
(def-win32-function ("LoadIconA" loadicon-int) ((hnd HANDLE) (lpIconName :unsigned-int)) :returning HANDLE :module "user32")
(def-win32-function ("LoadIconA" loadicon-string) ((hnd HANDLE) (lpIconName LPCSTR)) :returning HANDLE :module "user32")
(defun loadicon (hnd cur-name)
(etypecase cur-name
(fixnum (loadicon-int hnd cur-name))
(string (loadicon-string hnd cur-name))))
(defun default-icon () (loadicon *NULL* *IDI_APPLICATION*))
(defun default-background () (getstockobject *COLOR_BACKGROUND*))
(def-win32-function ("GetLastError" getlasterror) () :returning :unsigned-int :module "kernel32")
(def-win32-function ("GetClassNameA" getclassname-i) ((hnd HANDLE) (lpClassName (* :char)) (maxCount :int)) :returning :int :module "user32")
(defun getclassname (hnd &aux (max-length 64))
(with-foreign-object (s `(:array :char ,max-length))
(let ((n (getclassname-i hnd s max-length)))
(when (= n 0)
(error "Unable to get class name for ~A" hnd))
(convert-from-foreign-string s :length n))))
(def-win32-function ("RegisterClassA" registerclass) ((lpWndClass (* WNDCLASS))) :returning :int :module "user32")
(def-win32-function ("UnregisterClassA" unregisterclass) ((lpClassName :cstring) (hInstance HANDLE)) :returning :int :module "user32")
(def-win32-function ("GetWindowLongA" getwindowlong) ((hWnd HANDLE) (nIndex :int)) :returning :long :module "user32")
(def-win32-function ("SetWindowLongA" setwindowlong) ((hWnd HANDLE) (nIndex :int) (dwNewLong :long)) :returning :long :module "user32")
(def-win32-function ("CreateWindowExA" createwindowex) ((dwExStyle :unsigned-int) (lpClassName :cstring) (lpWindowName :cstring) (dwStyle :unsigned-int)
(x :int) (y :int) (nWidth :int) (nHeight :int) (hWndParent HANDLE) (hMenu HANDLE) (hInstance HANDLE)
(lpParam :pointer-void))
:returning HANDLE :module "user32")
(defun createwindow (&rest args)
(apply #'createwindowex 0 args))
(def-win32-function ("DestroyWindow" destroywindow) ((hWnd HANDLE)) :returning :int :module "user32")
(def-win32-function ("ShowWindow" showwindow) ((hWnd HANDLE) (nCmdShow :int)) :returning :int :module "user32")
(def-win32-function ("UpdateWindow" updatewindow) ((hWnd HANDLE)) :returning :void :module "user32")
(def-win32-function ("RedrawWindow" redrawwindow) ((hWnd HANDLE) (lprcUpdate (* RECT)) (hrgnUpdate HANDLE) (flags :unsigned-int)) :returning :int :module "user32")
(def-win32-function ("MoveWindow" movewindow) ((hWnd HANDLE) (x :int) (y :int) (nWidth :int) (nHeight :int) (bRepaint :int)) :returning :int :module "user32")
(def-win32-function ("SetWindowPos" setwindowpos) ((hWnd HANDLE) (hWndInsertAfter HANDLE) (x :int)
(y :int) (cx :int) (cy :int) (uFlags :unsigned-int)) :returning :int :module "user32")
(def-win32-function ("BringWindowToTop" bringwindowtotop) ((hWnd HANDLE)) :returning :int :module "user32")
(def-win32-function ("GetWindowTextA" getwindowtext-i) ((hWnd HANDLE) (lpString LPCSTR) (nMaxCount :int)) :returning :int :module "user32")
(defun getwindowtext (hnd)
(let ((len (1+ (getwindowtextlength hnd))))
(with-cstring (s (make-string len))
(getwindowtext-i hnd s len)
(subseq s 0 (1- len)))))
(def-win32-function ("GetWindowTextLengthA" getwindowtextlength) ((hWnd HANDLE)) :returning :int :module "user32")
(def-win32-function ("SetWindowTextA" setwindowtext) ((hWnd HANDLE) (lpString LPCSTR)) :returning :int :module "user32")
(def-win32-function ("GetParent" getparent) ((hWnd HANDLE)) :returning HANDLE :module "user32")
(def-win32-function ("GetClientRect" getclientrect) ((hWnd HANDLE) (lpRect (* RECT))) :returning :int :module "user32")
(def-win32-function ("GetWindowRect" getwindowrect) ((hWnd HANDLE) (lpRect (* RECT))) :returning :int :module "user32")
(def-win32-function ("InvalidateRect" invalidaterect) ((hWnd HANDLE) (lpRect (* RECT)) (bErase :int)) :returning :int :module "user32")
(def-win32-function ("SetRect" setrect) ((lpRect (* RECT)) (xLeft :int) (yTop :int) (xRight :int) (yBottom :int)) :returning :int :module "user32")
;(def-win32-function ("GetTitleBarInfo" gettitlebarinfo) ((hWnd HANDLE) (pti (* TITLEBARINFO))) :returning :int)
(def-win32-function ("SetFocus" setfocus) ((hWnd HANDLE)) :returning HANDLE :module "user32")
(def-win32-function ("PostQuitMessage" postquitmessage) ((nExitCode :int)) :returning :void :module "user32")
(def-win32-function ("SendMessageA" sendmessage) ((hWnd HANDLE) (uMsg :unsigned-int) (wParam :unsigned-int) (lParam :int)) :returning :int :module "user32")
(def-win32-function ("PostMessageA" postmessage) ((hWnd HANDLE) (uMsg :unsigned-int) (wParam :unsigned-int) (lParam :int)) :returning :int :module "user32")
(def-win32-function ("RegisterWindowMessageA" registerwindowmessage) ((lpString LPCSTR)) :returning :unsigned-int :module "user32")
(def-win32-function ("IsDialogMessageA" isdialogmessage) ((hDlg HANDLE) (lpMsg (* MSG))) :returning :int :module "user32")
(def-win32-function ("DefWindowProcA" defwindowproc) ((hWnd HANDLE) (uMsg :unsigned-int) (wParam :unsigned-int) (lParam :int)) :returning :int :module "user32")
(def-win32-function ("CallWindowProcA" callwindowproc) ((wndProc HANDLE) (hWnd HANDLE) (uMsg :unsigned-int) (wParam :unsigned-int) (lParam :int)) :returning :int :module "user32")
(defun loword (x) (logand x #xffff))
(defun hiword (x) (logand (floor x 65536) #xffff))
(defun get-x-lparam (x) (loword x))
(defun get-y-lparam (x) (hiword x))
(def-win32-function ("ScreenToClient" screentoclient) ((hWnd HANDLE) (pt (* POINT))) :returning :int :module "user32")
(def-win32-function ("MessageBoxA" messagebox) ((hWnd HANDLE) (lpText LPCSTR) (lpCaption LPCSTR) (uType :unsigned-int)) :returning :int :module "user32")
(def-win32-function ("GetOpenFileNameA" getopenfilename) ((lpofn (* OPENFILENAME))) :returning :int :module "comdlg32")
(def-win32-function ("GetSaveFileNameA" getsavefilename) ((lpofn (* OPENFILENAME))) :returning :int :module "comdlg32")
(def-win32-function ("FindTextA" findtext) ((lpfr (* FINDREPLACE))) :returning HANDLE :module "comdlg32")
(def-win32-function ("ReplaceTextA" replacetext) ((lpfr (* FINDREPLACE))) :returning HANDLE :module "comdlg32")
(def-win32-function ("GetMessageA" getmessage) ((lpMsg (* MSG)) (hWnd HANDLE) (wMsgFitlerMin :unsigned-int) (wMsgFilterMax :unsigned-int)) :returning :int :module "user32")
(def-win32-function ("TranslateMessage" translatemessage) ((lpMsg (* MSG))) :returning :int :module "user32")
(def-win32-function ("DispatchMessageA" dispatchmessage) ((lpMsg (* MSG))) :returning :int :module "user32")
(def-win32-function ("CreateMenu" createmenu) nil :returning HANDLE :module "user32")
(def-win32-function ("CreatePopupMenu" createpopupmenu) nil :returning HANDLE :module "user32")
(def-win32-function ("DestroyMenu" destroymenu) ((hMenu HANDLE)) :returning :int :module "user32")
(def-win32-function ("AppendMenuA" appendmenu) ((hMenu HANDLE) (uFlags :unsigned-int) (uIDNewItem :unsigned-int) (lpNewItem LPCSTR)) :returning :int :module "user32")
(def-win32-function ("GetSubMenu" getsubmenu) ((hMenu HANDLE) (nPos :int)) :returning HANDLE :module "user32")
(def-win32-function ("DeleteMenu" deletemenu) ((hMenu HANDLE) (uPosition :unsigned-int) (uFlags :unsigned-int)) :returning :int :module "user32")
(def-win32-function ("RemoveMenu" removemenu) ((hMenu HANDLE) (uPosition :unsigned-int) (uFlags :unsigned-int)) :returning :int :module "user32")
(def-win32-function ("GetMenuItemCount" getmenuitemcount) ((hMenu HANDLE)) :returning :int :module "user32")
(def-win32-function ("CheckMenuItem" checkmenuitem) ((hMenu HANDLE) (uIDCheckItem :unsigned-int) (uCheck :unsigned-int)) :returning :int :module "user32")
(def-win32-function ("EnableMenuItem" enablemenuitem) ((hMenu HANDLE) (uIDCheckItem :unsigned-int) (uCheck :unsigned-int)) :returning :int :module "user32")
(def-win32-function ("TrackPopupMenu" trackpopupmenu) ((hMenu HANDLE) (uFlags :unsigned-int) (x :int) (y :int)
(nReserved :int) (hWnd HANDLE) (prcRect HANDLE)) :returning :int :module "user32")
(def-win32-function ("TrackPopupMenuEx" trackpopupmenuex) ((hMenu HANDLE) (fuFlags :unsigned-int) (x :int) (y :int)
(hWnd HANDLE) (lptpl (* TPMPARAMS))) :returning :int :module "user32")
(def-win32-function ("CreateAcceleratorTableA" createacceleratortable) ((lpaccl (* ACCEL)) (cEntries :int)) :returning HANDLE :module "user32")
(def-win32-function ("TranslateAcceleratorA" translateaccelerator) ((hWnd HANDLE) (hAccTable HANDLE) (lpMsg (* MSG))) :returning :int :module "user32")
(def-win32-function ("DestroyAcceleratorTable" destroyacceleratortable) ((hAccTable HANDLE)) :returning :int :module "user32")
(def-win32-function ("InitCommonControls" initcommoncontrols) () :returning :void :module "comctl32")
(defun event-loop (&key (accelTable *NULL*) (accelMain *NULL*) (dlgSym nil))
(with-foreign-object (msg 'MSG)
(loop for bRet = (getmessage msg *NULL* 0 0)
when (= bRet 0) return bRet
if (= bRet -1)
do (error "GetMessage failed!!!")
else
do (or (and (not (null-pointer-p accelTable))
(not (null-pointer-p accelMain))
(/= (translateaccelerator accelMain accelTable msg) 0))
(and dlgSym
(not (null-pointer-p (symbol-value dlgSym)))
(/= (isdialogmessage (symbol-value dlgSym) msg) 0))
(progn
(translatemessage msg)
(dispatchmessage msg))))))
(defun y-or-no-p (&optional control &rest args)
(let ((s (coerce (apply #'format nil control args) 'simple-string)))
(= (messagebox *NULL* s "ECL Dialog" (logior *MB_YESNO* *MB_ICONQUESTION*))
*IDYES*)))
(defun get-open-filename (&key (owner *NULL*) initial-dir filter (dlgfn #'getopenfilename)
(flags 0) &aux (max-fn-size 1024))
(flet ((null-concat (x &optional y &aux (xx (if y x (car x))) (yy (if y y (cdr x))))
(concatenate 'string xx (string #\Null) yy)))
(when filter
(setq filter (format nil "~A~C~C" (reduce #'null-concat (mapcar #'null-concat filter)) #\Null #\Null)))
(with-foreign-object (ofn 'OPENFILENAME)
(with-cstrings ((fn (make-string max-fn-size :initial-element #\Null))
(filter filter))
(zeromemory ofn (size-of-foreign-type 'OPENFILENAME))
(setf (get-slot-value ofn 'OPENFILENAME 'lStructSize) (size-of-foreign-type 'OPENFILENAME))
(setf (get-slot-value ofn 'OPENFILENAME 'hwndOwner) owner)
(setf (get-slot-value ofn 'OPENFILENAME 'lpstrFile) fn)
(setf (get-slot-value ofn 'OPENFILENAME 'nMaxFile) max-fn-size)
(setf (get-slot-value ofn 'OPENFILENAME 'Flags) flags)
(when filter
(setf (get-slot-value ofn 'OPENFILENAME 'lpstrFilter) filter))
(unless (= (funcall dlgfn ofn) 0)
(pathname (string-trim (string #\Null) fn)))))))
(defun find-text (&key (owner *NULL*) &aux (max-txt-size 1024))
(with-foreign-object (fr 'FINDREPLACE)
(with-cstring (txt (make-string max-txt-size :initial-element #\Null))
(zeromemory fr (size-of-foreign-type 'FINDREPLACE))
(setf (get-slot-value fr 'FINDREPLACE 'lStructSize) (size-of-foreign-type 'FINDREPLACE))
(setf (get-slot-value fr 'FINDREPLACE 'hwndOwner) owner)
(setf (get-slot-value fr 'FINDREPLACE 'wFindWhatLen) max-txt-size)
;(setf (get-slot-value fr 'FINDREPLACE 'Flags) 1)
(let ((result (findtext fr)))
(print result)
txt))))
#|
(defun set-wndproc (obj fun)
(let ((cb (si:make-dynamic-callback fun (read-from-string (format nil "~A-WNDPROC" (gensym))) :int '(:pointer-void :unsigned-int :unsigned-int :int)))
(old-wndproc (make-pointer (getwindowlong obj *GWL_WNDPROC*) 'HANDLE)))
(setwindowlong obj *GWL_WNDPROC* (make-lparam cb))
old-wndproc))
|#
(provide "WIN32")
;;; Test code
(defconstant *HELLO_ID* 100)
(defconstant *OK_ID* 101)
(defparameter hBtn nil)
(defparameter hOk nil)
(defun button-min-size (hnd)
(let ((fnt (make-pointer (sendmessage hnd *WM_GETFONT* 0 0) :pointer-void))
(hdc (getdc hnd))
(txt (getwindowtext hnd)))
(unless (null-pointer-p fnt)
(selectobject hdc fnt))
(with-foreign-objects ((sz 'SIZE)
(tm 'TEXTMETRIC))
(gettextextentpoint32 hdc txt (length txt) sz)
(gettextmetrics hdc tm)
(releasedc hnd hdc)
(list (+ (get-slot-value sz 'SIZE 'cx) 20)
(+ (get-slot-value tm 'TEXTMETRIC 'tmHeight) 10)))))
(defun get-titlebar-rect (hnd)
(with-foreign-object (ti 'TITLEBARINFO)
(setf (get-slot-value ti 'TITLEBARINFO 'cbSize) (size-of-foreign-type 'TITLEBARINFO))
(gettitlebarinfo hnd ti)
(let ((rc (get-slot-value ti 'TITLEBARINFO 'rcTitlebar)))
(list (get-slot-value rc 'RECT 'left)
(get-slot-value rc 'RECT 'top)
(get-slot-value rc 'RECT 'right)
(get-slot-value rc 'RECT 'bottom)))))
(defun test-wndproc (hwnd umsg wparam lparam)
(cond ((= umsg *WM_DESTROY*)
(setq hBtn nil hOk nil)
(postquitmessage 0)
0)
((= umsg *WM_CREATE*)
(setq hBtn (createwindowex 0 "BUTTON" "Hello World!" (logior *WS_VISIBLE* *WS_CHILD* *BS_PUSHBUTTON*)
0 0 50 20 hwnd (make-ID *HELLO_ID*) *NULL* *NULL*))
(setq hOk (createwindowex 0 "BUTTON" "Close" (logior *WS_VISIBLE* *WS_CHILD* *BS_PUSHBUTTON*)
0 0 50 20 hwnd (make-ID *OK_ID*) *NULL* *NULL*))
(sendmessage hBtn *WM_SETFONT* (make-wparam (getstockobject *DEFAULT_GUI_FONT*)) 0)
(sendmessage hOk *WM_SETFONT* (make-wparam (getstockobject *DEFAULT_GUI_FONT*)) 0)
0)
((= umsg *WM_SIZE*)
(let* ((new-w (loword lparam))
(new-h (hiword lparam))
(wb (- new-w 20))
(hb (/ (- new-h 30) 2)))
(movewindow hBtn 10 10 wb hb *TRUE*)
(movewindow hOk 10 (+ 20 hb) wb hb *TRUE*))
0)
((= umsg *WM_GETMINMAXINFO*)
(let* ((btn1-sz (and hBtn (button-min-size hBtn)))
(btn2-sz (and hOk (button-min-size hOk)))
#|(rc (get-titlebar-rect hWnd))|#
(titleH #|(1+ (- (fourth rc) (second rc)))|# 30))
(when (and btn1-sz btn2-sz (> titleH 0))
(with-foreign-object (minSz 'POINT)
(setf (get-slot-value minSz 'POINT 'x) (+ (max (first btn1-sz) (first btn2-sz)) 20))
(setf (get-slot-value minSz 'POINT 'y) (+ (second btn1-sz) (second btn2-sz) 30 titleH))
(with-cast-int-pointer (lparam MINMAXINFO)
(setf (get-slot-value lparam 'MINMAXINFO 'ptMinTrackSize) minSz)))))
0)
((= umsg *WM_COMMAND*)
(let ((n (hiword wparam))
(id (loword wparam)))
(cond ((= n *BN_CLICKED*)
(cond ((= id *HELLO_ID*)
(format t "~&Hellow World!~%")
(get-open-filename :owner hwnd))
((= id *OK_ID*)
(destroywindow hwnd))))
(t
(format t "~&Un-handled notification: ~D~%" n))))
0)
(t
(defwindowproc hwnd umsg wparam lparam))))
(defun do-test ()
(make-wndclass "MyClass"
:lpfnWndProc #'test-wndproc)
(let* ((hwnd (createwindowex
0
"MyClass"
"ECL/Win32 test"
*WS_OVERLAPPEDWINDOW*
*CW_USEDEFAULT*
*CW_USEDEFAULT*
130
120
*NULL*
*NULL*
*NULL*
*NULL*)))
(when (si::null-pointer-p hwnd)
(error "Unable to create window"))
(showwindow hwnd *SW_SHOWNORMAL*)
(updatewindow hwnd)
(event-loop)
(unregisterclass "MyClass" *NULL*)))