206 lines
6.8 KiB
Racket
206 lines
6.8 KiB
Racket
#lang racket/base
|
|
(require ffi/unsafe
|
|
ffi/unsafe/define
|
|
ffi/unsafe/alloc
|
|
"../common/utils.rkt"
|
|
"../../lock.rkt"
|
|
"types.rkt"
|
|
"const.rkt")
|
|
|
|
(provide
|
|
define-mz
|
|
(protect-out define-gdi32
|
|
define-user32
|
|
define-kernel32
|
|
define-comctl32
|
|
define-comdlg32
|
|
define-shell32
|
|
define-uxtheme
|
|
define-winmm
|
|
failed
|
|
is-win64?
|
|
|
|
GetLastError
|
|
|
|
GetWindowLongPtrW
|
|
SetWindowLongPtrW
|
|
SendMessageW SendMessageW/str SendMessageW/ptr
|
|
GetSysColor GetRValue GetGValue GetBValue make-COLORREF
|
|
CreateBitmap
|
|
CreateCompatibleBitmap
|
|
DeleteObject
|
|
CreateCompatibleDC
|
|
DeleteDC
|
|
MoveWindow
|
|
ShowWindow
|
|
EnableWindow
|
|
SetWindowTextW
|
|
SetCursor
|
|
GetDC
|
|
ReleaseDC
|
|
InvalidateRect
|
|
ValidateRect
|
|
GetMenuState
|
|
CheckMenuItem
|
|
ModifyMenuW
|
|
RemoveMenu
|
|
SelectObject
|
|
WideCharToMultiByte
|
|
GetDeviceCaps
|
|
strip-&
|
|
->screen
|
|
->screen*
|
|
->normal))
|
|
|
|
(define gdi32-lib (ffi-lib "gdi32.dll"))
|
|
(define user32-lib (ffi-lib "user32.dll"))
|
|
(define kernel32-lib (ffi-lib "kernel32.dll"))
|
|
(define comctl32-lib (ffi-lib "comctl32.dll"))
|
|
(define comdlg32-lib (ffi-lib "comdlg32.dll"))
|
|
(define shell32-lib (ffi-lib "shell32.dll"))
|
|
(define uxtheme-lib (ffi-lib "uxtheme.dll"))
|
|
(define winmm-lib (ffi-lib "winmm.dll"))
|
|
|
|
(define-ffi-definer define-gdi32 gdi32-lib)
|
|
(define-ffi-definer define-user32 user32-lib)
|
|
(define-ffi-definer define-kernel32 kernel32-lib)
|
|
(define-ffi-definer define-comctl32 comctl32-lib)
|
|
(define-ffi-definer define-comdlg32 comdlg32-lib)
|
|
(define-ffi-definer define-shell32 shell32-lib)
|
|
(define-ffi-definer define-uxtheme uxtheme-lib)
|
|
(define-ffi-definer define-winmm winmm-lib)
|
|
|
|
(define-kernel32 GetLastError (_wfun -> _DWORD))
|
|
|
|
(define (failed who)
|
|
;; There's a race condition between this use of GetLastError()
|
|
;; and other Racket threads that may have run since
|
|
;; the call in this thread that we're reporting as failed.
|
|
;; In the rare case that we lose a race, though, it just
|
|
;; means a bad report for an error that shouldn't have happened
|
|
;;; anyway.
|
|
(error who "call failed (~s)"
|
|
(GetLastError)))
|
|
|
|
(define is-win64?
|
|
(equal? "win32\\x86_64"
|
|
(path->string (system-library-subpath #f))))
|
|
|
|
(define GetWindowLongPtrW
|
|
(get-ffi-obj (if is-win64? 'GetWindowLongPtrW 'GetWindowLongW) user32-lib
|
|
(_wfun _HWND _int -> _pointer)))
|
|
(define SetWindowLongPtrW
|
|
(get-ffi-obj (if is-win64? 'SetWindowLongPtrW 'SetWindowLongW) user32-lib
|
|
(_wfun _HWND _int _pointer -> _pointer)))
|
|
|
|
(define-user32 SendMessageW (_wfun _HWND _UINT _WPARAM _LPARAM -> _LRESULT))
|
|
(define-user32 SendMessageW/str (_wfun _HWND _UINT _WPARAM _string/utf-16 -> _LRESULT)
|
|
#:c-id SendMessageW)
|
|
(define-user32 SendMessageW/ptr (_wfun _HWND _UINT _WPARAM _pointer -> _LRESULT)
|
|
#:c-id SendMessageW)
|
|
|
|
(define-user32 GetSysColor (_wfun _int -> _DWORD))
|
|
|
|
(define (GetRValue v) (bitwise-and v #xFF))
|
|
(define (GetGValue v) (bitwise-and (arithmetic-shift v -8) #xFF))
|
|
(define (GetBValue v) (bitwise-and (arithmetic-shift v -16) #xFF))
|
|
(define (make-COLORREF r g b) (bitwise-ior
|
|
r
|
|
(arithmetic-shift g 8)
|
|
(arithmetic-shift b 16)))
|
|
|
|
(define-user32 MoveWindow(_wfun _HWND _int _int _int _int _BOOL -> (r : _BOOL)
|
|
-> (unless r (failed 'MoveWindow))))
|
|
|
|
(define-user32 ShowWindow (_wfun _HWND _int -> (previously-shown? : _BOOL) -> (void)))
|
|
(define-user32 EnableWindow (_wfun _HWND _BOOL -> _BOOL))
|
|
|
|
(define-user32 SetWindowTextW (_wfun _HWND _string/utf-16 -> (r : _BOOL)
|
|
-> (unless r (failed 'SetWindowText))))
|
|
|
|
(define-user32 SetCursor (_wfun _HCURSOR -> _HCURSOR))
|
|
|
|
(define-user32 _GetDC (_wfun _HWND -> _HDC)
|
|
#:c-id GetDC)
|
|
(define (GetDC hwnd)
|
|
(((allocator (lambda (hdc) (ReleaseDC hwnd hdc)))
|
|
_GetDC)
|
|
hwnd))
|
|
|
|
(define-user32 ReleaseDC (_wfun _HWND _HDC -> _int)
|
|
#:wrap (deallocator cadr))
|
|
|
|
(define-gdi32 DeleteObject (_wfun _pointer -> (r : _BOOL)
|
|
-> (unless r (failed 'DeleteObject)))
|
|
#:wrap (deallocator))
|
|
|
|
(define-gdi32 CreateCompatibleBitmap (_wfun _HDC _int _int -> _HBITMAP)
|
|
#:wrap (allocator DeleteObject))
|
|
(define-gdi32 CreateBitmap (_wfun _int _int _UINT _UINT _pointer -> _HBITMAP)
|
|
#:wrap (allocator DeleteObject))
|
|
|
|
(define-gdi32 DeleteDC (_wfun _HDC -> (r : _BOOL)
|
|
-> (unless r (failed 'DeleteDC)))
|
|
#:wrap (deallocator))
|
|
(define-gdi32 CreateCompatibleDC (_wfun _HDC -> _HDC)
|
|
#:wrap (allocator DeleteDC))
|
|
|
|
(define-user32 InvalidateRect (_wfun _HWND (_or-null _RECT-pointer) _BOOL -> (r : _BOOL)
|
|
-> (unless r (failed 'InvalidateRect))))
|
|
(define-user32 ValidateRect (_wfun _HWND (_or-null _RECT-pointer) -> (r : _BOOL)
|
|
-> (unless r (failed 'ValidateRect))))
|
|
|
|
(define-user32 GetMenuState (_wfun _HMENU _UINT _UINT -> _UINT))
|
|
(define-user32 CheckMenuItem (_wfun _HMENU _UINT _UINT -> _DWORD))
|
|
(define-user32 ModifyMenuW (_wfun _HMENU _UINT _UINT _UINT_PTR _string/utf-16
|
|
-> (r : _BOOL)
|
|
-> (unless r (failed 'ModifyMenuW))))
|
|
(define-user32 RemoveMenu (_wfun _HMENU _UINT _UINT -> (r : _BOOL)
|
|
-> (unless r (failed 'RemoveMenu))))
|
|
|
|
(define-gdi32 SelectObject (_wfun _HDC _pointer -> _pointer))
|
|
|
|
(define-kernel32 WideCharToMultiByte (_wfun _UINT _DWORD _pointer _int
|
|
_pointer _int _pointer _pointer
|
|
-> _int))
|
|
;; ----------------------------------------
|
|
|
|
(define (strip-& s)
|
|
(if (string? s)
|
|
(regexp-replace* #rx"&(.)" s "\\1")
|
|
s))
|
|
|
|
;; ----------------------------------------
|
|
|
|
(define-gdi32 GetDeviceCaps (_wfun _HDC _int -> _int))
|
|
|
|
(define screen-dpi
|
|
(atomically
|
|
(let ([hdc (GetDC #f)])
|
|
(begin0
|
|
(GetDeviceCaps hdc LOGPIXELSX)
|
|
(ReleaseDC #f hdc)))))
|
|
|
|
;; Convert a normalized (conceptually 96-dpi) measure into a screen measure
|
|
(define (->screen x)
|
|
(and x
|
|
(if (= screen-dpi 96)
|
|
x
|
|
(if (exact? x)
|
|
(ceiling (/ (* x screen-dpi) 96))
|
|
(/ (* x screen-dpi) 96)))))
|
|
(define (->screen* x)
|
|
(if (and (not (= screen-dpi 96))
|
|
(exact? x))
|
|
(floor (/ (* x screen-dpi) 96))
|
|
(->screen x)))
|
|
|
|
;; Convert a screen measure to a normalize (conceptually 96-dpi) measure
|
|
(define (->normal x)
|
|
(and x
|
|
(if (= screen-dpi 96)
|
|
x
|
|
(if (exact? x)
|
|
(floor (/ (* x 96) screen-dpi))
|
|
(/ (* x 96) screen-dpi)))))
|