├── .mgit └── winapi.exclude ├── media └── www │ └── winapi_demo.png ├── winapi.lua ├── winapi.md ├── winapi ├── accelerator.lua ├── arrays_test.lua ├── basebuttonclass.lua ├── basebuttonclass.md ├── basewindowclass.lua ├── basewindowclass.md ├── bitmap.lua ├── bitmappanel.lua ├── bitmappanel.md ├── bitmask.lua ├── button.lua ├── buttonclass.lua ├── buttonclass.md ├── checkboxclass.lua ├── checkboxclass.md ├── class.lua ├── clipboard.lua ├── color.lua ├── colorchooser.lua ├── combobox.lua ├── comboboxclass.lua ├── comboboxclass.md ├── comboboxex.lua ├── comctl.lua ├── comdlg.lua ├── controlclass.lua ├── controlclass.md ├── cursor.lua ├── ddev.lua ├── debug.lua ├── devcaps.lua ├── dibitmap.lua ├── dpiaware.lua ├── dragdrop.lua ├── dsound.lua ├── edit.lua ├── editclass.lua ├── editclass.md ├── filedialogs.lua ├── filemapping.lua ├── font.lua ├── fontex.lua ├── gdi.lua ├── groupboxclass.lua ├── groupboxclass.md ├── handlelist.lua ├── headercontrol.lua ├── icon.lua ├── idataobject.lua ├── ienumformatetc.lua ├── imagelist.lua ├── imagelistclass.lua ├── init.lua ├── itemlist.lua ├── keyboard.lua ├── labelclass.lua ├── labelclass.md ├── listbox.lua ├── listboxclass.lua ├── listboxclass.md ├── listview.lua ├── listviewclass.lua ├── logfonttype.lua ├── memory.lua ├── menu.lua ├── menuclass.lua ├── messagebox.lua ├── mmdevice.lua ├── mmdevice_test.lua ├── mmdeviceclass.lua ├── mmsystem.lua ├── module.lua ├── monitor.lua ├── mouse.lua ├── namespace.lua ├── notifyiconclass.lua ├── ole.lua ├── panelclass.lua ├── panelclass.md ├── process.lua ├── propsys.lua ├── radiobuttonclass.lua ├── radiobuttonclass.md ├── rawinput.lua ├── registry.lua ├── resource.lua ├── richedit.lua ├── rpc.lua ├── shellapi.lua ├── showcase.lua ├── spi.lua ├── sstorage.lua ├── static.lua ├── struct.lua ├── sync.lua ├── sysinfo.lua ├── systemmetrics.lua ├── tabcontrol.lua ├── tabcontrolclass.lua ├── thread.lua ├── time.lua ├── toolbar.lua ├── toolbarclass.lua ├── tooltip.lua ├── tooltipclass.lua ├── trackbar.lua ├── trackbarclass.lua ├── treeview.lua ├── types.lua ├── util.lua ├── uuid.lua ├── vobject.lua ├── vobject.md ├── volman.lua ├── waitemlistclass.lua ├── wcs.lua ├── winbase.lua ├── window.lua ├── windowclass.lua ├── windowclass.md ├── windowclasses.lua ├── winnt.lua ├── winuser.lua └── wmapp.lua ├── winapi_binding.md ├── winapi_demo.lua ├── winapi_design.md └── winapi_history.md /.mgit/winapi.exclude: -------------------------------------------------------------------------------- 1 | * 2 | !winapi/ 3 | !winapi/** 4 | winapi/wgl* 5 | winapi/gl* 6 | winapi/cairo* 7 | -------------------------------------------------------------------------------- /media/www/winapi_demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luapower/winapi/84c32de365a6eb8281f5e3192c83744a04af11ad/media/www/winapi_demo.png -------------------------------------------------------------------------------- /winapi.lua: -------------------------------------------------------------------------------- 1 | --binding/winapi: loader for winapi.init (or the demo if run standalone) 2 | if not ... then require'winapi_demo'; return end 3 | return require'winapi.init' 4 | -------------------------------------------------------------------------------- /winapi.md: -------------------------------------------------------------------------------- 1 | --- 2 | tagline: win32 windows & controls 3 | platforms: mingw64 4 | --- 5 | 6 | ## Scope 7 | 8 | Windows, common controls and dialogs, message loop and system APIs. 9 | 10 | ## Features 11 | 12 | * UTF8 Lua strings everywhere (also works with wide char buffers) 13 | * bitmap widget for custom painting 14 | * OpenGL and cairo custom-painting widgets (in separate packages) 15 | * anchor-based layout model for all controls 16 | * object system with virtual properties (`win.title = 'hello'` sets the title) 17 | * binding helpers for easy binding of new and future APIs 18 | * all calls are error-checked 19 | * automatic memory management (ownership; buffers) 20 | * flags can be passed as `'FLAG1 FLAG2'` 21 | * counting from 1 everywhere. 22 | 23 | ## Status 24 | 25 | [Current status](https://github.com/luapower/winapi/issues/26) 26 | and [issues](https://github.com/luapower/winapi/issues). 27 | 28 | ## Hello World 29 | 30 | ~~~{.lua} 31 | local winapi = require'winapi' 32 | require'winapi.windowclass' 33 | 34 | local win = winapi.Window{ 35 | w = 500, --all these are "initial fields" 36 | h = 300, 37 | title = 'Lua rulez', 38 | autoquit = true, --this is to quit app when the window is closed 39 | visible = false, --this field is from BaseWindow 40 | } 41 | 42 | function win:on_close() --this is an event handler 43 | print'Bye' 44 | end 45 | 46 | print(win.title) --this is how to read the value of a property 47 | win.title = 'Lua rulez!' --this is how to set the value of a property 48 | win:show() --this is a method call 49 | 50 | os.exit(winapi.MessageLoop()) --start the message loop 51 | ~~~ 52 | 53 | ## Demos 54 | 55 | Check out [winapi_demo] to see all the controls in action: 56 | 57 | ![screnshot](/files/luapower/media/www/winapi_demo.png) 58 | 59 | Also, many modules can be run as standalone scripts, which will 60 | showcase their functionality, so there's lots of little demos there too. 61 | 62 | [winapi_demo]: https://github.com/luapower/winapi/blob/master/winapi_demo.lua 63 | 64 | ## Documentation 65 | 66 | ### Architecture 67 | 68 | * [winapi_design] - hi-level overview of the library 69 | * [winapi_binding] - how the binding works, aka developer documentation 70 | * [winapi_history] - the reasoning behind various design decisions 71 | 72 | ### Classes 73 | 74 | * [VObject][winapi.vobject] - objects with virtual properties 75 | * [BaseWindow][winapi.basewindowclass] - base class for top-level windows and controls 76 | * [Window][winapi.windowclass] - final class for top level windows 77 | * [Control][winapi.controlclass] - base class for controls 78 | * [Panel][winapi.panelclass] - custom-painted child windows 79 | * [BitmapPanel][winapi.bitmappanel] - RGBA [bitmap] panels 80 | * [CairoPanel][winapi.cairopanel] - [cairo] panels 81 | * [WGLPanel][winapi.wglpanel] - [OpenGL][opengl] panels 82 | * [Label][winapi.labelclass] - labels 83 | * [BaseButton][winapi.basebuttonclass] - base class for buttons 84 | * [Button][winapi.buttonclass] - push-buttons 85 | * [CheckBox][winapi.checkboxclass] - checkboxes 86 | * [RadioButton][winapi.radiobuttonclass] - radio buttons 87 | * [GroupBox][winapi.groupboxclass] - group boxes 88 | * [Edit][winapi.editclass] - edit boxes 89 | * [ComboBox][winapi.comboboxclass] - combo boxes and drop-down lists 90 | * [ListBox][winapi.listboxclass] - list boxes 91 | * [ListView][winapi.listviewclass] - list views 92 | * [TabControl][winapi.tabcontrolclass] - tab bars 93 | * [Toolbar][winapi.toolbarclass] - toolbars 94 | * [Tooltip][winapi.tooltipclass] - tooltips 95 | * [Menu][winapi.menuclass] - menus and menu bars 96 | * [NotifyIcon][winapi.notifyiconclass] - system tray icons 97 | 98 | ### Functions 99 | 100 | The "proc" layer is documented in the code, including API quirks 101 | and empirical knowledge, so do check out the source code. 102 | 103 | ## Modules 104 | 105 | {{{module_list}}} 106 | 107 | -------------------------------------------------------------------------------- /winapi/accelerator.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/controls/accelerator: accelerator tables 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.winuser' 7 | 8 | ffi.cdef[[ 9 | typedef struct tagACCEL { 10 | BYTE fVirt; 11 | WORD key; 12 | WORD id; 13 | } ACCEL, *LPACCEL; 14 | 15 | HACCEL CreateAcceleratorTableW(LPACCEL paccel, int cAccel); 16 | BOOL DestroyAcceleratorTable(HACCEL hAccel); 17 | int CopyAcceleratorTableW(HACCEL hAccelSrc, LPACCEL lpAccelDst, int cAccelEntries); 18 | ]] 19 | 20 | FVIRTKEY = 0x01 --without this flag, FCONTROL doesn't work; with this flag, lowercase letters don't work. 21 | FSHIFT = 0x04 22 | FCONTROL = 0x08 23 | FALT = 0x10 24 | 25 | function ACCEL(t) 26 | if type(t) == 'table' then 27 | local is_char = type(t.key) == 'string' and not t.key:find'^VK_' 28 | t = { 29 | key = is_char and wcs(t.key:upper())[0] or flags(t.key), 30 | fVirt = bit.bor(flags(t.modifiers), FVIRTKEY), 31 | id = t.id, 32 | } 33 | end 34 | return types.ACCEL(t) 35 | end 36 | 37 | function CreateAcceleratorTable(accel) 38 | local accel, sz = arrays.ACCEL(accel) 39 | return own(checkh(C.CreateAcceleratorTableW(accel, sz)), DestroyAcceleratorTable) 40 | end 41 | 42 | function DestroyAcceleratorTable(haccel) 43 | checknz(C.DestroyAcceleratorTable(haccel)) 44 | disown(haccel) 45 | end 46 | 47 | function AcceleratorTableSize(haccel) 48 | return C.CopyAcceleratorTableW(haccel, nil, 0) 49 | end 50 | 51 | function CopyAcceleratorTable(haccel, buf) 52 | local buf, sz = arrays.ACCEL(buf or AcceleratorTableSize(haccel)) 53 | C.CopyAcceleratorTableW(haccel, buf, sz) 54 | return buf 55 | end 56 | 57 | -------------------------------------------------------------------------------- /winapi/arrays_test.lua: -------------------------------------------------------------------------------- 1 | setfenv(1, require'winapi') 2 | 3 | local a = arrays.int32_t(2) --n 4 | assert(ffi.sizeof(a) == 2 * 4) 5 | assert(a[0] == 0) 6 | assert(a[1] == 0) 7 | 8 | local a = arrays.int32_t(3, 2) --n, a1 repeated 9 | assert(ffi.sizeof(a) == 3 * 4) 10 | assert(a[0] == 2) 11 | assert(a[1] == 2) 12 | assert(a[2] == 2) 13 | 14 | --when given a list of args, VLAs _are_ cleared past initial values. 15 | 16 | local a = arrays.int32_t(3, 2, 3) --n, a1, ...; rest is 0 padded 17 | assert(ffi.sizeof(a) == 3 * 4) 18 | assert(a[0] == 2) 19 | assert(a[1] == 3) 20 | assert(a[2] == 0) --zeroed 21 | 22 | --when initialized with a table, VLAs are not cleared past initial values. 23 | 24 | local a = arrays.int32_t(4, {2,nil,3}) --n, a1, ...; from first nil we get garbage 25 | assert(ffi.sizeof(a) == 4 * 4) 26 | assert(a[0] == 2) 27 | --assert(a[1] == 0) --garbage 28 | --assert(a[2] == 0) --garbage 29 | --assert(a[3] == 0) --garbage 30 | 31 | --table initializers are recursive for arrays of structs. 32 | 33 | ffi.cdef'typedef struct point_ { int x, y; } point;' 34 | 35 | local a = arrays.point(3, {{2,3},{3,2}}) --n, t; from first nil we get garbage 36 | assert(a[0].x == 2) 37 | assert(a[0].y == 3) 38 | assert(a[1].x == 3) 39 | assert(a[1].y == 2) 40 | --assert(a[2].x == 0) --garbage 41 | --assert(a[2].y == 0) --garbage 42 | 43 | local a = arrays.point(2, {{2,3}}) 44 | assert(a[0].x == 2) 45 | assert(a[0].y == 3) 46 | --assert(a[1].x == 0) --garbage 47 | --assert(a[1].y == 0) --garbage 48 | 49 | --this is our extension to the VLA initializer: 50 | --you don't have to pass the length as first arg when initialized with a table. 51 | 52 | local a = arrays.int32_t{2,3} --t, size is assumed #t 53 | assert(ffi.sizeof(a) == 2 * 4) 54 | assert(a[0] == 2) 55 | assert(a[1] == 3) 56 | 57 | local a = arrays.point{{2,3},{3,2}} --t, size is assumed #t 58 | assert(ffi.sizeof(a) == 2 * ffi.sizeof'point') 59 | assert(a[0].x == 2) 60 | assert(a[0].y == 3) 61 | assert(a[1].x == 3) 62 | assert(a[1].y == 2) 63 | 64 | -------------------------------------------------------------------------------- /winapi/basebuttonclass.lua: -------------------------------------------------------------------------------- 1 | 2 | --oo/controls/basebutton: base class for button-like controls 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.controlclass' 7 | require'winapi.button' 8 | require'winapi.imagelistclass' 9 | 10 | BaseButton = subclass({ 11 | __style_bitmask = bitmask{ 12 | tabstop = WS_TABSTOP, 13 | halign = { 14 | left = BS_LEFT, 15 | right = BS_RIGHT, 16 | center = BS_CENTER, 17 | }, 18 | valign = { 19 | top = BS_TOP, 20 | bottom = BS_BOTTOM, 21 | center = BS_VCENTER, 22 | }, 23 | word_wrap = BS_MULTILINE, 24 | flat = BS_FLAT, 25 | double_clicks = BS_NOTIFY, --wait for a double click instead of clicking again (also for focus/blur events) 26 | }, 27 | __defaults = { 28 | tabstop = true, 29 | }, 30 | __wm_command_handler_names = index{ 31 | on_click = BN_CLICKED, 32 | on_double_click = BN_DOUBLECLICKED, 33 | on_focus = BN_SETFOCUS, 34 | on_blur = BN_KILLFOCUS, 35 | }, 36 | __init_properties = { 37 | 'image_list', 'icon', 'bitmap' 38 | }, 39 | }, Control) 40 | 41 | function BaseButton:after___before_create(info, args) 42 | args.class = WC_BUTTON 43 | args.text = info.text 44 | end 45 | 46 | function BaseButton:__checksize() end --signal content change (for autosize feature of push-buttons) 47 | 48 | function BaseButton:click() Button_Click(self.hwnd) end 49 | 50 | local iml_align = { 51 | left = BUTTON_IMAGELIST_ALIGN_LEFT, 52 | right = BUTTON_IMAGELIST_ALIGN_RIGHT, 53 | top = BUTTON_IMAGELIST_ALIGN_TOP, 54 | bottom = BUTTON_IMAGELIST_ALIGN_BOTTOM, 55 | center = BUTTON_IMAGELIST_ALIGN_CENTER, 56 | } 57 | local iml_align_names = index(iml_align) 58 | function BaseButton:set_image_list(iml) 59 | local imls = BUTTON_IMAGELIST() 60 | imls.imagelist = iml.image_list.himl 61 | imls.align = iml_align[iml.align] 62 | if iml.margin then imls.margin = iml.margin end 63 | Button_SetImageList(self.hwnd, imls) 64 | self:__checksize() 65 | end 66 | function BaseButton:get_image_list() 67 | local iml = Button_GetImageList(self.hwnd) 68 | return { 69 | image_list = ImageList(iml.imagelist), 70 | align = iml_align_names[iml.align], 71 | margin = iml.margin, 72 | } 73 | end 74 | 75 | function BaseButton:set_icon(icon) 76 | SetWindowStyle(self.hwnd, setbit(GetWindowStyle(self.hwnd), BS_ICON, icon)) 77 | Button_SetIcon(self.hwnd, icon) 78 | self:__checksize() 79 | end 80 | function BaseButton:get_icon() return Button_GetIcon(self.hwnd) end 81 | 82 | function BaseButton:set_bitmap(bitmap) 83 | SetWindowStyle(self.hwnd, setbit(GetWindowStyle(self.hwnd), BS_BITMAP, bitmap)) 84 | Button_SetBitmap(self.hwnd, bitmap) 85 | self:__checksize() 86 | end 87 | function BaseButton:get_bitmap() return Button_GetBitmap(self.hwnd) end 88 | 89 | function BaseButton:after_set_text(text) 90 | self:__checksize() 91 | end 92 | 93 | -------------------------------------------------------------------------------- /winapi/basebuttonclass.md: -------------------------------------------------------------------------------- 1 | --- 2 | tagline: base class for button-like controls 3 | --- 4 | 5 | ## `require'winapi.basebuttonclass'` 6 | 7 | This module implements the `BaseButton` class which is the base class 8 | for buttons and button-like controls. `BaseButton` is for subclassing, 9 | not for instantiation. Nevertheless, it contains properties and methods 10 | that are common to all buttons and button-like controls which are 11 | documented here. 12 | 13 | ## BaseButton 14 | 15 | ### Hierarchy 16 | 17 | * [VObject][winapi.vobject] 18 | * [BaseWindow][winapi.basewindowclass] 19 | * [Control][winapi.controlclass] 20 | * BaseButton 21 | 22 | ### Initial fields and properties 23 | 24 | __NOTE:__ in the table below `i` means initial field, `r` means property 25 | which can be read, `w` means property which can be set. 26 | 27 | ----------------------- -------- ----------------------------------------- -------------- --------------------- 28 | __field/property__ __irw__ __description__ __default__ __reference__ 29 | tabstop irw focus on tab true WS_TABSTOP 30 | halign irw horiz. align: 'left', 'right', 'center' BS_LEFT,... 31 | valign irw vert. align: 'top', 'bottom', 'center' BS_TOP,... 32 | word_wrap irw word wrapping BS_MULTILINE 33 | flat irw flat appearance BS_FLAT 34 | double_clicks irw enable double-click events BS_NOTIFY 35 | image_list irw see below (*) BCM_SETIMAGELIST 36 | icon irw icon BM_SETIMAGE 37 | bitmap irw bitmap BM_SETIMAGE 38 | ----------------------- -------- ----------------------------------------- -------------- --------------------- 39 | 40 | (*) the `image_list` property is a table with the fields: 41 | 42 | * `image_list`: a `HIMAGELIST` 43 | * `align`: 'left', 'right', 'top', 'bottom', 'center' 44 | * `margin`: the margin around the image 45 | 46 | 47 | ### Events 48 | 49 | -------------------------------- -------------------------------------------- ---------------------- 50 | __event__ __description__ __reference__ 51 | on_click() clicked BN_CLICKED 52 | on_double_click() double clicked BN_DOUBLECLICKED 53 | on_focus() focused BN_SETFOCUS 54 | on_blur() unfocused BN_KILLFOCUS 55 | -------------------------------- -------------------------------------------- --------------------- 56 | -------------------------------------------------------------------------------- /winapi/bitmappanel.lua: -------------------------------------------------------------------------------- 1 | 2 | --oo/controls/bitmappanel: RGBA bitmap control 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | local ffi = require'ffi' 6 | local bit = require'bit' 7 | setfenv(1, require'winapi') 8 | require'winapi.bitmap' 9 | require'winapi.panelclass' 10 | require'winapi.dibitmap' 11 | 12 | BitmapPanel = class(Panel) 13 | 14 | function BitmapPanel:on_paint(hdc) 15 | local bmp = self.__bmp 16 | 17 | if not bmp then 18 | local w, h = self.client_w, self.client_h 19 | if w <= 0 or h <= 0 then return end 20 | bmp = DIBitmap(w, h, self.hwnd) 21 | self.__bmp = bmp 22 | self:on_bitmap_create(bmp) 23 | end 24 | 25 | GdiFlush() 26 | self:on_bitmap_paint(bmp) 27 | 28 | bmp:paint(hdc) 29 | end 30 | 31 | function BitmapPanel:WM_ERASEBKGND() 32 | return not self.__bmp --we draw our own background (prevent flicker) 33 | end 34 | 35 | function BitmapPanel:on_resized() 36 | local bmp = self.__bmp 37 | if not bmp then return end 38 | 39 | local w, h = self.client_w, self.client_h 40 | if bmp.w == w and bmp.h == h then return end 41 | 42 | self:on_bitmap_free(bmp) 43 | bmp:free() 44 | self.__bmp = nil 45 | 46 | self:invalidate() 47 | end 48 | 49 | function BitmapPanel:on_bitmap_create(bitmap) end 50 | function BitmapPanel:on_bitmap_free(bitmap) end 51 | function BitmapPanel:on_bitmap_paint(bitmap) end 52 | 53 | --showcase 54 | 55 | if not ... then 56 | require'winapi.showcase' 57 | local win = ShowcaseWindow() 58 | local bp = BitmapPanel{ 59 | x = 20, 60 | y = 20, 61 | w = win.client_w - 40, 62 | h = win.client_h - 40, 63 | parent = win, 64 | anchors = {left = true, top = true, right = true, bottom = true}, 65 | } 66 | function bp:on_bitmap_paint(bmp) 67 | local pixels = ffi.cast('int32_t*', bmp.data) 68 | for y = 0, bmp.h - 1 do 69 | for x = 0, bmp.w - 1 do 70 | pixels[y * bmp.w + x] = y * 2^8 + x * 2^16 71 | end 72 | end 73 | end 74 | win:invalidate() 75 | MessageLoop() 76 | end 77 | 78 | return BitmapPanel 79 | -------------------------------------------------------------------------------- /winapi/bitmappanel.md: -------------------------------------------------------------------------------- 1 | --- 2 | tagline: RGBA bitmap panels 3 | --- 4 | 5 | ## `require'winapi.bitmappanel'` 6 | 7 | This module implements the `BitmapPanel` class which allows 8 | accessing a panel's pixels as an bgra8-type [bitmap] with 9 | pre-multiplied alpha. 10 | 11 | ## BitmapPanel 12 | 13 | ### Hierarchy 14 | 15 | * [Object][winapi.object] 16 | * [VObject][winapi.vobject] 17 | * [BaseWindow][winapi.basewindowclass] 18 | * [Control][winapi.controlclass] 19 | * [Panel][winapi.panelclass] 20 | * BitmapPanel 21 | 22 | ### Events 23 | 24 | -------------------------------------------- -------------------------------------- ------------------------- 25 | __painting__ __description__ __reference__ 26 | on_bitmap_create(bitmap) bitmap was created 27 | on_bitmap_free(bitmap) bitmap will be freed 28 | on_bitmap_paint(bitmap) panel needs repainting WM_PAINT 29 | -------------------------------------------- -------------------------------------- ------------------------- 30 | -------------------------------------------------------------------------------- /winapi/bitmask.lua: -------------------------------------------------------------------------------- 1 | 2 | --binding/bitmask: bitmask encoding and decoding 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi.namespace') 6 | require'winapi.util' 7 | 8 | local bitmask_class = {} 9 | local bitmask_meta = {__index = bitmask_class} 10 | 11 | function bitmask(fields) 12 | return setmetatable({fields = fields}, bitmask_meta) 13 | end 14 | 15 | function negate(mask) 16 | return {[true] = 0, [false] = mask} 17 | end 18 | 19 | function bitmask_class:compute_mask(t) --compute total mask for use with setbits() 20 | t = t or self.fields 21 | local v = 0 22 | for _, mask in pairs(t) do 23 | if type(mask) == 'table' then --choice mask 24 | v = bit.bor(v, self:compute_mask(mask)) 25 | else 26 | v = bit.bor(v, mask) 27 | end 28 | end 29 | return v 30 | end 31 | 32 | local setbit, setbits = setbit, setbits 33 | 34 | function bitmask_class:setbit(over, k, v) 35 | local mask = self.fields[k] --def: {name = mask | choicemask}; choicemask: {name = mask} 36 | assert(mask, 'unknown bitmask field "%s"', k) 37 | if type(mask) == 'table' then --choicemask 38 | over = setbits(over, self:compute_mask(mask), mask[v] or 0) 39 | else 40 | over = setbit(over, mask, v) 41 | end 42 | return over 43 | end 44 | 45 | function bitmask_class:set(over, t) 46 | if not t then return over end --no table is an empty table 47 | for k in pairs(self.fields) do 48 | if t[k] ~= nil then 49 | over = self:setbit(over, k, t[k]) 50 | end 51 | end 52 | return over 53 | end 54 | 55 | function bitmask_class:getbit(from, k) 56 | local mask = self.fields[k] 57 | assert(mask, 'unknown bitmask field "%s"', k) 58 | if type(mask) == 'table' then --choicemask 59 | local default_choice 60 | for choice, choicemask in pairs(mask) do 61 | if choicemask == 0 then default_choice = choice end 62 | if bit.band(from, choicemask) ~= 0 then --return the first found choice 63 | return choice 64 | end 65 | end 66 | return default_choice 67 | end 68 | return bit.band(from, mask) == mask 69 | end 70 | 71 | function bitmask_class:get(from, into) 72 | local t = into or {} 73 | for k in pairs(self.fields) do 74 | t[k] = self:getbit(from, k) 75 | end 76 | return t 77 | end 78 | 79 | -------------------------------------------------------------------------------- /winapi/buttonclass.lua: -------------------------------------------------------------------------------- 1 | 2 | --oo/controls/button: push-button control 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.basebuttonclass' 7 | 8 | Button = { 9 | __style_bitmask = bitmask{ 10 | default = BS_DEFPUSHBUTTON, 11 | }, 12 | __defaults = { 13 | text = '&OK', 14 | w = 100, h = 24, 15 | text_margin = {20,5}, --applied when autosize = true 16 | }, 17 | __init_properties = { 18 | 'text_margin', 'pushed', 'autosize' 19 | }, 20 | } 21 | 22 | subclass(Button, BaseButton) 23 | 24 | function Button:after___before_create(info, args) 25 | args.style = bit.bor(args.style, BS_PUSHBUTTON) 26 | end 27 | 28 | function Button:get_ideal_size(w, h) --fixing w or h work on Vista+ 29 | local size = SIZE() 30 | size.w = w or 0 31 | size.h = h or 0 32 | size = Button_GetIdealSize(self.hwnd, size) 33 | return {w = size.w, h = size.h} 34 | end 35 | 36 | function Button:__checksize() 37 | if self.autosize then 38 | local size = self.ideal_size 39 | self:resize(size.w, size.h) 40 | end 41 | end 42 | 43 | function Button:get_autosize(yes) 44 | return self._autosize 45 | end 46 | 47 | function Button:set_autosize(yes) 48 | self._autosize = yes 49 | self:__checksize() 50 | end 51 | 52 | function Button:set_text_margin(margin) --only works when autosize = true 53 | local rect = RECT() 54 | rect.x1 = margin.w or margin[1] 55 | rect.y1 = margin.h or margin[2] 56 | Button_SetTextMargin(self.hwnd, rect) 57 | self:__checksize() 58 | end 59 | function Button:get_text_margin() 60 | local rect = Button_GetTextMargin(self.hwnd) 61 | return {w = rect.x1, h = rect.y1} 62 | end 63 | 64 | function Button:set_pushed(pushed) Button_SetState(self.hwnd, pushed) end 65 | function Button:get_pushed() return Button_GetState(self.hwnd) end 66 | 67 | 68 | --showcase 69 | 70 | if not ... then 71 | require'winapi.showcase' 72 | require'winapi.icon' 73 | local window = ShowcaseWindow{w=300, h=300, max_cw=600, max_ch=600} 74 | local b1 = Button{parent = window, default = true} 75 | b1:focus() 76 | function b1:on_click() print'b1 clicked' end 77 | --b1:__inspect() 78 | 79 | local b2 = Button{parent = window, y = 30, h = 40, 80 | double_clicks = true, valign = 'bottom', halign = 'right', 81 | image_list = {image_list = ShowcaseImageList(), align = 'center'}} 82 | function b2:on_click() print'b2 clicked' end 83 | function b2:on_focus() print'b2 focused' end 84 | function b2:on_blur() print'b2 blured' end 85 | function b2:on_double_click() print'b2 dbl-clicked' end 86 | b2.pushed = true 87 | 88 | b3 = Button{parent = window, y = 90, w = 100, h = 100, autosize = true, text_margin = {30,30}} 89 | b3.icon = LoadIconFromInstance(IDI_INFORMATION) 90 | b3:click() 91 | 92 | b4 = Button{parent = window, y = 200, flat = true, 93 | anchors = {top=false, left=true, right=true, bottom=true}, 94 | min_w = 100, 95 | } 96 | b5 = Button{parent = window, x = 110, h = 70, w = 120, 97 | anchors = {top=true, left=true, right=true, bottom=true}, 98 | min_w = 80, min_h = 24, 99 | text = 'I live in a society where pizza gets to my house before the police', 100 | word_wrap = true, autosize = false} 101 | 102 | b5.word_wrap = true 103 | 104 | MessageLoop() 105 | end 106 | 107 | -------------------------------------------------------------------------------- /winapi/buttonclass.md: -------------------------------------------------------------------------------- 1 | --- 2 | tagline: push-buttons 3 | --- 4 | 5 | ## `require'winapi.buttonclass'` 6 | 7 | This module implements the `Button` class for creating buttons. 8 | 9 | ## Button 10 | 11 | ### Hierarchy 12 | 13 | * [VObject][winapi.vobject] 14 | * [BaseWindow][winapi.basewindowclass] 15 | * [Control][winapi.controlclass] 16 | * [BaseButton][winapi.basebuttonclass] 17 | * Button 18 | 19 | ### Initial fields and properties 20 | 21 | __NOTE:__ in the table below `i` means initial field, `r` means property 22 | which can be read, `w` means property which can be set. 23 | 24 | ----------------------- -------- ----------------------------------------- -------------- --------------------- 25 | __field/property__ __irw__ __description__ __default__ __reference__ 26 | text irw button's label '&OK' Get/SetWindowText 27 | w, h irw size 100, 24 28 | text_margin irw margins that go with `autosize` {20,5} BCM_GET/SETTEXTMARGIN 29 | autosize irw set size based on text false 30 | pushed irw pushed state BM_GET/SETSTATE 31 | ideal_size r get ideal size for text (`{w=, h=}`) BCM_GETIDEALSIZE 32 | ----------------------- -------- ----------------------------------------- -------------- --------------------- 33 | -------------------------------------------------------------------------------- /winapi/checkboxclass.lua: -------------------------------------------------------------------------------- 1 | 2 | --oo/controls/checkbox: checkbox control 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.basebuttonclass' 7 | 8 | CheckBox = subclass({ 9 | __style_bitmask = bitmask{ 10 | box_align = { 11 | left = 0, 12 | right = BS_LEFTTEXT, 13 | }, 14 | pushlike = BS_PUSHLIKE, 15 | type = { --TODO: make two orthogonal properties out of these: autocheck and allow_grayed 16 | twostate = BS_CHECKBOX, 17 | threestate = BS_3STATE, 18 | twostate_autocheck = BS_AUTOCHECKBOX, 19 | threestate_autocheck = BS_AUTO3STATE, 20 | }, 21 | }, 22 | __defaults = { 23 | type = 'twostate_autocheck', 24 | text = 'Option', 25 | w = 100, h = 24, 26 | }, 27 | __init_properties = { 28 | 'checked' 29 | }, 30 | }, BaseButton) 31 | 32 | local button_states = { 33 | [false] = BST_UNCHECKED, 34 | [true] = BST_CHECKED, 35 | indeterminate = BST_INDETERMINATE, 36 | } 37 | local button_state_names = index(button_states) 38 | function CheckBox:set_checked(checked) 39 | Button_SetCheck(self.hwnd, button_states[checked]) 40 | end 41 | function CheckBox:get_checked() 42 | return button_state_names[bit.band(Button_GetCheck(self.hwnd), 3)] 43 | end 44 | 45 | --showcase 46 | 47 | if not ... then 48 | require'winapi.showcase' 49 | local window = ShowcaseWindow{w=300,h=200} 50 | local cb1 = CheckBox{parent = window, w = 200, text = 'I am The Ocean', 51 | checked = 'indeterminate', image_list = {image_list = ShowcaseImageList()}, 52 | type = 'threestate_autocheck', align = 'left', halign = 'center', 53 | box_align = 'right', flat = true} 54 | function cb1:on_click() print'b1 clicked' end 55 | 56 | local cb2 = CheckBox{parent = window, y = 30, type = 'threestate_autocheck', pushlike = true} 57 | 58 | local cb3 = CheckBox{parent = window, y = 60, w = 150, h = 50, 59 | word_wrap = true, valign = 'top', double_clicks = true, 60 | text = "I'm a cheeeckbox and I'm ok. I sleep all night and I work all day."} 61 | function cb3:on_double_click() print 'b3 dbl-clicked' end 62 | 63 | MessageLoop() 64 | end 65 | 66 | -------------------------------------------------------------------------------- /winapi/checkboxclass.md: -------------------------------------------------------------------------------- 1 | --- 2 | tagline: checkboxes 3 | --- 4 | 5 | ## `require'winapi.checkboxclass'` 6 | 7 | This module implements the `CheckBox` class for creating checkboxes. 8 | 9 | ## Button 10 | 11 | ### Hierarchy 12 | 13 | * [VObject][winapi.vobject] 14 | * [BaseWindow][winapi.basewindowclass] 15 | * [Control][winapi.controlclass] 16 | * [BaseButton][winapi.basebuttonclass] 17 | * CheckBox 18 | 19 | ### Initial fields and properties 20 | 21 | __NOTE:__ in the table below `i` means initial field, `r` means property 22 | which can be read, `w` means property which can be set. 23 | 24 | ----------------------- -------- ----------------------------------------- ----------------------- --------------------- 25 | __field/property__ __irw__ __description__ __default__ __reference__ 26 | 27 | text irw checkbox's label 'Option' Get/SetWindowText 28 | 29 | w, h irw size 100, 24 30 | 31 | box_align irw 'left', 'right' 'left' BS_LEFTTEXT 32 | 33 | pushlike irw push-like appearance false BS_PUSHLIKE 34 | 35 | checked irw true, false, 'indeterminate' false BST_UNCHECKED, 36 | BST_CHECKED, 37 | BST_INDETERMINATE 38 | 39 | type irw 'twostate', 'threestate', 'twostate_autocheck' BS_CHECKBOX, 40 | 'twostate_autocheck', BS_3STATE, 41 | 'threestate_autocheck' BS_AUTOCHECKBOX, 42 | BS_AUTO3STATE 43 | ----------------------- -------- ----------------------------------------- ----------------------- --------------------- 44 | -------------------------------------------------------------------------------- /winapi/class.lua: -------------------------------------------------------------------------------- 1 | 2 | --oo/oo-system/class: single inheritance object model 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | --subclassing defined by super:__subclass(derived). 6 | --introspection is in terms of class:__super(). 7 | setfenv(1, require'winapi') 8 | 9 | function subclass(class, super) 10 | if super and super.__subclass then super:__subclass(class) end 11 | return class 12 | end 13 | 14 | function class(super) 15 | return subclass({}, super) 16 | end 17 | 18 | function isinstance(object, class) --defined in terms of object:__super() 19 | if type(object) ~= 'table' then return false end 20 | if not object.__super then return false end 21 | local super = object:__super() 22 | if super == nil then return false end 23 | if super == class then return true end 24 | return isinstance(super, class) 25 | end 26 | -------------------------------------------------------------------------------- /winapi/color.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/resources/color: standard color brushes 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.winuser' 7 | 8 | CTLCOLOR_MSGBOX = ffi.cast('HBRUSH', 0) 9 | CTLCOLOR_EDIT = ffi.cast('HBRUSH', 1) 10 | CTLCOLOR_LISTBOX = ffi.cast('HBRUSH', 2) 11 | CTLCOLOR_BTN = ffi.cast('HBRUSH', 3) 12 | CTLCOLOR_DLG = ffi.cast('HBRUSH', 4) 13 | CTLCOLOR_SCROLLBAR = ffi.cast('HBRUSH', 5) 14 | CTLCOLOR_STATIC = ffi.cast('HBRUSH', 6) 15 | CTLCOLOR_MAX = ffi.cast('HBRUSH', 7) 16 | 17 | COLOR_SCROLLBAR = ffi.cast('HBRUSH', 0) 18 | COLOR_BACKGROUND = ffi.cast('HBRUSH', 1) 19 | COLOR_ACTIVECAPTION = ffi.cast('HBRUSH', 2) 20 | COLOR_INACTIVECAPTION = ffi.cast('HBRUSH', 3) 21 | COLOR_MENU = ffi.cast('HBRUSH', 4) 22 | COLOR_WINDOW = ffi.cast('HBRUSH', 5) 23 | COLOR_WINDOWFRAME = ffi.cast('HBRUSH', 6) 24 | COLOR_MENUTEXT = ffi.cast('HBRUSH', 7) 25 | COLOR_WINDOWTEXT = ffi.cast('HBRUSH', 8) 26 | COLOR_CAPTIONTEXT = ffi.cast('HBRUSH', 9) 27 | COLOR_ACTIVEBORDER = ffi.cast('HBRUSH', 10) 28 | COLOR_INACTIVEBORDER = ffi.cast('HBRUSH', 11) 29 | COLOR_APPWORKSPACE = ffi.cast('HBRUSH', 12) 30 | COLOR_HIGHLIGHT = ffi.cast('HBRUSH', 13) 31 | COLOR_HIGHLIGHTTEXT = ffi.cast('HBRUSH', 14) 32 | COLOR_BTNFACE = ffi.cast('HBRUSH', 15) 33 | COLOR_BTNSHADOW = ffi.cast('HBRUSH', 16) 34 | COLOR_GRAYTEXT = ffi.cast('HBRUSH', 17) 35 | COLOR_BTNTEXT = ffi.cast('HBRUSH', 18) 36 | COLOR_INACTIVECAPTIONTEXT= ffi.cast('HBRUSH', 19) 37 | COLOR_BTNHIGHLIGHT = ffi.cast('HBRUSH', 20) 38 | 39 | COLOR_3DDKSHADOW = ffi.cast('HBRUSH', 21) 40 | COLOR_3DLIGHT = ffi.cast('HBRUSH', 22) 41 | COLOR_INFOTEXT = ffi.cast('HBRUSH', 23) 42 | COLOR_INFOBK = ffi.cast('HBRUSH', 24) 43 | 44 | COLOR_HOTLIGHT = ffi.cast('HBRUSH', 26) 45 | COLOR_GRADIENTACTIVECAPTION = ffi.cast('HBRUSH', 27) 46 | COLOR_GRADIENTINACTIVECAPTION = ffi.cast('HBRUSH', 28) 47 | 48 | COLOR_MENUHILIGHT = ffi.cast('HBRUSH', 29) 49 | COLOR_MENUBAR = ffi.cast('HBRUSH', 30) 50 | 51 | COLOR_DESKTOP = COLOR_BACKGROUND 52 | COLOR_3DFACE = COLOR_BTNFACE 53 | COLOR_3DSHADOW = COLOR_BTNSHADOW 54 | COLOR_3DHIGHLIGHT = COLOR_BTNHIGHLIGHT 55 | COLOR_3DHILIGHT = COLOR_BTNHIGHLIGHT 56 | COLOR_BTNHILIGHT = COLOR_BTNHIGHLIGHT 57 | 58 | -------------------------------------------------------------------------------- /winapi/colorchooser.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/dialogs/colorchooser: color chooser dialog 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.comdlg' 7 | 8 | ffi.cdef[[ 9 | typedef UINT_PTR (__stdcall *LPCCHOOKPROC)(HWND, UINT, WPARAM, LPARAM); 10 | 11 | typedef struct tagCHOOSECOLORW { 12 | DWORD lStructSize; 13 | HWND hwndOwner; 14 | HWND hInstance; 15 | COLORREF rgbResult; 16 | COLORREF* lpCustColors; 17 | DWORD Flags; 18 | LPARAM lCustData; 19 | LPCCHOOKPROC lpfnHook; 20 | LPCWSTR lpTemplateName; 21 | } CHOOSECOLORW, *LPCHOOSECOLORW; 22 | 23 | BOOL ChooseColorW(LPCHOOSECOLORW); 24 | ]] 25 | 26 | CC_RGBINIT = 0x00000001 27 | CC_FULLOPEN = 0x00000002 28 | CC_PREVENTFULLOPEN = 0x00000004 29 | CC_SHOWHELP = 0x00000008 30 | CC_ENABLEHOOK = 0x00000010 31 | CC_ENABLETEMPLATE = 0x00000020 32 | CC_ENABLETEMPLATEHANDLE = 0x00000040 33 | CC_SOLIDCOLOR = 0x00000080 34 | CC_ANYCOLOR = 0x00000100 35 | 36 | COLORREF16 = function() return ffi.new('COLORREF[16]') end 37 | 38 | CHOOSECOLOR = struct{ 39 | ctype = 'CHOOSECOLORW', size = 'lStructSize', 40 | fields = sfields{ 41 | 'result', 'rgbResult', pass, pass, 42 | 'custom_colors', 'lpCustColors', pass, pass, 43 | 'flags', 'Flags', flags, pass, 44 | }, 45 | } 46 | 47 | function ChooseColor(cc, cust) --reusing the cc preserves the custom colors 48 | cc = CHOOSECOLOR(cc) 49 | cust = cc.custom_colors ~= nil and cc.custom_colors or COLORREF16(cust) 50 | cc.custom_colors = cust 51 | checkcomdlg(comdlg.ChooseColorW(ffi.cast('LPCHOOSECOLORW', cc))) 52 | return cc, cust 53 | end 54 | 55 | 56 | if not ... then 57 | require'winapi.showcase' 58 | local window = ShowcaseWindow() 59 | local cc, cust = CHOOSECOLOR{} 60 | cc = ChooseColor(cc) 61 | end 62 | -------------------------------------------------------------------------------- /winapi/combobox.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/controls/combobox: old combobox control 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.window' 7 | 8 | --creation 9 | 10 | CB_OKAY = 0 11 | CB_ERR = -1 12 | CB_ERRSPACE = -2 13 | 14 | CBS_SIMPLE = 0x0001 15 | CBS_DROPDOWN = 0x0002 16 | CBS_DROPDOWNLIST = 0x0003 17 | CBS_OWNERDRAWFIXED = 0x0010 18 | CBS_OWNERDRAWVARIABLE = 0x0020 19 | CBS_AUTOHSCROLL = 0x0040 20 | CBS_OEMCONVERT = 0x0080 21 | CBS_SORT = 0x0100 22 | CBS_HASSTRINGS = 0x0200 23 | CBS_NOINTEGRALHEIGHT = 0x0400 24 | CBS_DISABLENOSCROLL = 0x0800 25 | CBS_UPPERCASE = 0x2000 26 | CBS_LOWERCASE = 0x4000 27 | 28 | --commands 29 | 30 | CB_GETEDITSEL = 0x0140 31 | CB_LIMITTEXT = 0x0141 32 | CB_SETEDITSEL = 0x0142 33 | CB_ADDSTRING = 0x0143 34 | CB_DELETESTRING = 0x0144 35 | CB_DIR = 0x0145 36 | CB_GETCOUNT = 0x0146 37 | CB_GETCURSEL = 0x0147 38 | CB_GETLBTEXT = 0x0148 --don't look for CB_SETLBTEXT :) 39 | CB_GETLBTEXTLEN = 0x0149 40 | CB_INSERTSTRING = 0x014A 41 | CB_RESETCONTENT = 0x014B 42 | CB_FINDSTRING = 0x014C 43 | CB_SELECTSTRING = 0x014D 44 | CB_SETCURSEL = 0x014E 45 | CB_SHOWDROPDOWN = 0x014F 46 | CB_GETITEMDATA = 0x0150 47 | CB_SETITEMDATA = 0x0151 48 | CB_GETDROPPEDCONTROLRECT = 0x0152 49 | CB_SETITEMHEIGHT = 0x0153 50 | CB_GETITEMHEIGHT = 0x0154 51 | CB_SETEXTENDEDUI = 0x0155 52 | CB_GETEXTENDEDUI = 0x0156 53 | CB_GETDROPPEDSTATE = 0x0157 54 | CB_FINDSTRINGEXACT = 0x0158 55 | CB_SETLOCALE = 0x0159 56 | CB_GETLOCALE = 0x015A 57 | CB_GETTOPINDEX = 0x015b 58 | CB_SETTOPINDEX = 0x015c 59 | CB_GETHORIZONTALEXTENT = 0x015d 60 | CB_SETHORIZONTALEXTENT = 0x015e 61 | CB_GETDROPPEDWIDTH = 0x015f 62 | CB_SETDROPPEDWIDTH = 0x0160 63 | CB_INITSTORAGE = 0x0161 64 | CB_MULTIPLEADDSTRING = 0x0163 65 | CB_GETCOMBOBOXINFO = 0x0164 66 | CB_MSGMAX = 0x0165 67 | 68 | function ComboBox_AddString(hwnd, s) --returns index 69 | return countfrom1(checkpoz(SNDMSG(hwnd, CB_ADDSTRING, 0, wcs(s)))) 70 | end 71 | 72 | function ComboBox_InsertString(hwnd, i, s) --returns index 73 | return countfrom1(checkpoz(SNDMSG(hwnd, CB_INSERTSTRING, countfrom0(i), wcs(s)))) 74 | end 75 | 76 | function ComboBox_DeleteString(hwnd, i) --returns count 77 | return checkpoz(SNDMSG(hwnd, CB_DELETESTRING, countfrom0(i))) 78 | end 79 | 80 | function ComboBox_GetString(hwnd, i, buf) --there's no SetString 81 | local ws = WCS(buf or checkpoz(SNDMSG(hwnd, CB_GETLBTEXTLEN, countfrom0(i)))) 82 | checkpoz(SNDMSG(hwnd, CB_GETLBTEXT, countfrom0(i), ws)) 83 | return buf or mbs(ws) 84 | end 85 | 86 | function ComboBox_GetCount(hwnd) 87 | return checkpoz(SNDMSG(hwnd, CB_GETCOUNT)) 88 | end 89 | 90 | function ComboBox_Reset(hwnd) --clears the listbox and the edit box 91 | return checkz(SNDMSG(hwnd, CB_RESETCONTENT)) 92 | end 93 | 94 | function ComboBox_SetCurSel(hwnd, i) --returns index 95 | return countfrom1(checkpoz(SNDMSG(hwnd, CB_SETCURSEL, countfrom0(i)))) 96 | end 97 | 98 | function ComboBox_GetCurSel(hwnd) 99 | return countfrom1(SNDMSG(hwnd, CB_GETCURSEL)) 100 | end 101 | 102 | function ComboBox_SetExtendedUI(hwnd, extended) 103 | return checkz(SNDMSG(hwnd, CB_SETEXTENDEDUI, extended)) 104 | end 105 | 106 | function ComboBox_LimitText(hwnd, cchMax) 107 | return checktrue(SNDMSG(hwnd, CB_LIMITTEXT, cchMax)) 108 | end 109 | 110 | function ComboBox_SetItemHeight(hwnd, item, height) 111 | item = (item == 'edit' and -1) or (item == 'list' and 0) or countfrom0(item) 112 | checkpoz(SNDMSG(hwnd, CB_SETITEMHEIGHT, item, height)) --all we know is that -1 is an error 113 | end 114 | 115 | function ComboBox_GetItemHeight(hwnd, item) 116 | item = (item == 'edit' and -1) or (item == 'list' and 0) or countfrom0(item) 117 | return checkpoz(SNDMSG(hwnd, CB_GETITEMHEIGHT, item)) 118 | end 119 | 120 | function ComboBox_GetEditSel(hwnd) 121 | local p1, p2 = ffi.new'DWORD[1]', ffi.new'DWORD[1]' 122 | SNDMSG(hwnd, CB_GETEDITSEL, p1, p2) 123 | return countfrom1(p1[0]), countfrom1(p2[0]) 124 | end 125 | 126 | function CheckBox_SetEditSel(hwnd, i, j) 127 | checktrue(SNDMSG(hwnd, CB_SETEDITSEL, 0, MAKELPARAM(countfrom0(i), countfrom0(j)))) 128 | end 129 | 130 | function ComboBox_ShowDropdown(hwnd, show) 131 | checktrue(SNDMSG(hwnd, CB_SHOWDROPDOWN, show)) 132 | end 133 | 134 | function ComboBox_DroppedDown(hwnd) 135 | return SNDMSG(hwnd, CB_GETDROPPEDSTATE) == 1 136 | end 137 | 138 | function ComboBox_SetDroppedWidth(hwnd, w) --returns width 139 | checkpoz(SNDMSG(hwnd, CB_SETDROPPEDWIDTH, w)) 140 | end 141 | 142 | function ComboBox_GetDroppedWidth(hwnd) 143 | return checkpoz(SNDMSG(hwnd, CB_GETDROPPEDWIDTH)) 144 | end 145 | 146 | --notifications 147 | 148 | CBN_ERRSPACE = -1 149 | CBN_SELCHANGE = 1 150 | CBN_DBLCLK = 2 151 | CBN_SETFOCUS = 3 152 | CBN_KILLFOCUS = 4 153 | CBN_EDITCHANGE = 5 154 | CBN_EDITUPDATE = 6 155 | CBN_DROPDOWN = 7 156 | CBN_CLOSEUP = 8 157 | CBN_SELENDOK = 9 158 | CBN_SELENDCANCEL = 10 159 | 160 | --TODO 161 | --[[ 162 | WM_COMPAREITEM 163 | WM_DRAWITEM 164 | WM_MEASUREITEM 165 | ]] 166 | 167 | -------------------------------------------------------------------------------- /winapi/comboboxclass.md: -------------------------------------------------------------------------------- 1 | --- 2 | tagline: combo boxes and drop-down lists 3 | --- 4 | 5 | ## `require'winapi.comboboxclass'` 6 | 7 | This module implements the `ComboBox` class for creating combo boxes 8 | and drop-down lists. 9 | 10 | ## ComboBox 11 | 12 | ### Hierarchy 13 | 14 | * [VObject][winapi.vobject] 15 | * [BaseWindow][winapi.basewindowclass] 16 | * [Control][winapi.controlclass] 17 | * ComboBox 18 | 19 | ### Initial fields and properties 20 | 21 | __NOTE:__ in the table below `i` means initial field, `r` means property 22 | which can be read, `w` means property which can be set. 23 | 24 | ----------------------- -------- ----------------------------------------- -------------- --------------------- 25 | __field/property__ __irw__ __description__ __default__ __reference__ 26 | w, h irw size 100, 100 27 | tabstop irw focus on tab true WS_TABSTOP 28 | type irw 'simple', 'dropdown', 'dropdownlist' 'simple' CBS_SIMPLE/DROPDOWN/DROPDOWNLIST 29 | autohscroll irw auto horizontal scroll true CBS_AUTOHSCROLL 30 | vscroll irw always show vertical scroll false CBS_DISABLENOSCROLL 31 | fixedheight irw fixed height false CBS_NOINTEGRALHEIGHT 32 | sort irw sort items false CBS_SORT 33 | case_sensitive irw 'normal', 'upper', 'lower' 'normal' CBS_UPPER/LOWERCASE 34 | __dropdowns__ 35 | no_edit_image irw TODO CBES_EX_NOEDITIMAGE 36 | no_edit_image2 irw TODO CBES_EX_NOEDITIMAGEINDENT 37 | path_word_break irw TODO CBES_EX_PATHWORDBREAKPROC 38 | no_size_limit irw TODO CBES_EX_NOSIZELIMIT 39 | case_sensitive irw TODO CBES_EX_CASESENSITIVE 40 | ----------------------- -------- ----------------------------------------- -------------- --------------------- 41 | 42 | ### Events 43 | 44 | -------------------------------- -------------------------------------------- ---------------------- 45 | __event__ __description__ __reference__ 46 | on_memory_error() TODO CBN_ERRSPACE 47 | on_selection_change() TODO CBN_SELCHANGE 48 | on_double_click() TODO CBN_DBLCLK 49 | on_focus() TODO CBN_SETFOCUS 50 | on_blur() TODO CBN_KILLFOCUS 51 | on_edit_change() TODO CBN_EDITCHANGE 52 | on_edit_update() TODO CBN_EDITUPDATE 53 | on_dropdown() TODO CBN_DROPDOWN 54 | on_closeup() TODO CBN_CLOSEUP 55 | on_select() TODO CBN_SELENDOK 56 | on_cancel() TODO CBN_SELENDCANCEL 57 | -------------------------------- -------------------------------------------- --------------------- 58 | -------------------------------------------------------------------------------- /winapi/comctl.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/controls/comctl: common controls API 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.winuser' 7 | 8 | comctl = ffi.load'comctl32' 9 | 10 | --common types 11 | 12 | ffi.cdef[[ 13 | struct IStream; 14 | typedef struct _HIMAGELIST; 15 | typedef struct _HIMAGELIST* HIMAGELIST; 16 | ]] 17 | 18 | --initialization 19 | 20 | ffi.cdef[[ 21 | typedef struct tagINITCOMMONCONTROLSEX { 22 | DWORD dwSize; 23 | DWORD dwICC; 24 | } INITCOMMONCONTROLSEX, *LPINITCOMMONCONTROLSEX; 25 | 26 | BOOL InitCommonControlsEx(LPINITCOMMONCONTROLSEX); 27 | ]] 28 | 29 | ICC_LISTVIEW_CLASSES = 0x00000001 -- listview, header 30 | ICC_TREEVIEW_CLASSES = 0x00000002 -- treeview, tooltips 31 | ICC_BAR_CLASSES = 0x00000004 -- toolbar, statusbar, trackbar, tooltips 32 | ICC_TAB_CLASSES = 0x00000008 -- tab, tooltips 33 | ICC_UPDOWN_CLASS = 0x00000010 -- updown 34 | ICC_PROGRESS_CLASS = 0x00000020 -- progress 35 | ICC_HOTKEY_CLASS = 0x00000040 -- hotkey 36 | ICC_ANIMATE_CLASS = 0x00000080 -- animate 37 | ICC_WIN95_CLASSES = 0x000000FF 38 | ICC_DATE_CLASSES = 0x00000100 -- month picker, date picker, time picker, updown 39 | ICC_USEREX_CLASSES = 0x00000200 -- comboex 40 | ICC_COOL_CLASSES = 0x00000400 -- rebar (coolbar) control 41 | ICC_INTERNET_CLASSES = 0x00000800 42 | ICC_PAGESCROLLER_CLASS = 0x00001000 -- page scroller 43 | ICC_NATIVEFNTCTL_CLASS = 0x00002000 -- native font control 44 | ICC_STANDARD_CLASSES = 0x00004000 45 | ICC_LINK_CLASS = 0x00008000 46 | 47 | function InitCommonControlsEx(ICC) 48 | local icex = types.INITCOMMONCONTROLSEX() 49 | icex.dwSize = ffi.sizeof(icex) 50 | icex.dwICC = flags(ICC) 51 | checknz(comctl.InitCommonControlsEx(icex)) 52 | end 53 | 54 | InitCommonControlsEx() 55 | 56 | --common styles for rebar controls, toolbar controls, and status windows 57 | 58 | CCS_TOP = 0x00000001 59 | CCS_BOTTOM = 0x00000003 --default on statusbar 60 | CCS_VERT = 0x00000080 61 | CCS_LEFT = bit.bor(CCS_VERT, CCS_TOP) 62 | CCS_RIGHT = bit.bor(CCS_VERT, CCS_BOTTOM) 63 | CCS_NOMOVEY = 0x00000002 64 | CCS_NOMOVEX = bit.bor(CCS_VERT, CCS_NOMOVEY) 65 | CCS_NORESIZE = 0x00000004 66 | CCS_NOPARENTALIGN = 0x00000008 67 | CCS_NODIVIDER = 0x00000040 --remove the top highlight line 68 | CCS_ADJUSTABLE = 0x00000020 --customizable 69 | 70 | --commands 71 | 72 | CCM_FIRST = 0x2000 73 | CCM_SETBKCOLOR = (CCM_FIRST + 1) -- lParam is bkColor 74 | CCM_SETCOLORSCHEME = (CCM_FIRST + 2) -- lParam is color scheme 75 | CCM_GETCOLORSCHEME = (CCM_FIRST + 3) -- fills in COLORSCHEME pointed to by lParam 76 | CCM_GETDROPTARGET = (CCM_FIRST + 4) 77 | CCM_SETUNICODEFORMAT = (CCM_FIRST + 5) 78 | CCM_GETUNICODEFORMAT = (CCM_FIRST + 6) 79 | CCM_SETVERSION = (CCM_FIRST + 0x7) 80 | CCM_GETVERSION = (CCM_FIRST + 0x8) 81 | CCM_SETNOTIFYWINDOW = (CCM_FIRST + 0x9) -- wParam == hwndParent. 82 | CCM_SETWINDOWTHEME = (CCM_FIRST + 0xb) 83 | CCM_DPISCALE = (CCM_FIRST + 0xc) -- wParam == Awareness 84 | 85 | --assorted consants 86 | 87 | I_IMAGECALLBACK = -1 88 | I_IMAGENONE = -2 89 | 90 | ODT_MENU = 1 91 | ODT_LISTBOX = 2 92 | ODT_COMBOBOX = 3 93 | ODT_BUTTON = 4 94 | ODT_STATIC = 5 95 | 96 | --showcase 97 | 98 | if not ... then 99 | InitCommonControlsEx(0xFFFF) --init all 100 | end 101 | 102 | -------------------------------------------------------------------------------- /winapi/comdlg.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/dialogs/comdlg: common dialogs API 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.winuser' 7 | 8 | comdlg = ffi.load'comdlg32' 9 | 10 | COMMDLG_ERROR_NAMES = constants{ 11 | CDERR_DIALOGFAILURE = 0xFFFF, 12 | CDERR_GENERALCODES = 0x0000, 13 | CDERR_STRUCTSIZE = 0x0001, 14 | CDERR_INITIALIZATION = 0x0002, 15 | CDERR_NOTEMPLATE = 0x0003, 16 | CDERR_NOHINSTANCE = 0x0004, 17 | CDERR_LOADSTRFAILURE = 0x0005, 18 | CDERR_FINDRESFAILURE = 0x0006, 19 | CDERR_LOADRESFAILURE = 0x0007, 20 | CDERR_LOCKRESFAILURE = 0x0008, 21 | CDERR_MEMALLOCFAILURE = 0x0009, 22 | CDERR_MEMLOCKFAILURE = 0x000A, 23 | CDERR_NOHOOK = 0x000B, 24 | CDERR_REGISTERMSGFAIL = 0x000C, 25 | PDERR_PRINTERCODES = 0x1000, 26 | PDERR_SETUPFAILURE = 0x1001, 27 | PDERR_PARSEFAILURE = 0x1002, 28 | PDERR_RETDEFFAILURE = 0x1003, 29 | PDERR_LOADDRVFAILURE = 0x1004, 30 | PDERR_GETDEVMODEFAIL = 0x1005, 31 | PDERR_INITFAILURE = 0x1006, 32 | PDERR_NODEVICES = 0x1007, 33 | PDERR_NODEFAULTPRN = 0x1008, 34 | PDERR_DNDMMISMATCH = 0x1009, 35 | PDERR_CREATEICFAILURE = 0x100A, 36 | PDERR_PRINTERNOTFOUND = 0x100B, 37 | PDERR_DEFAULTDIFFERENT = 0x100C, 38 | CFERR_CHOOSEFONTCODES = 0x2000, 39 | CFERR_NOFONTS = 0x2001, 40 | CFERR_MAXLESSTHANMIN = 0x2002, 41 | FNERR_FILENAMECODES = 0x3000, 42 | FNERR_SUBCLASSFAILURE = 0x3001, 43 | FNERR_INVALIDFILENAME = 0x3002, 44 | FNERR_BUFFERTOOSMALL = 0x3003, 45 | FRERR_FINDREPLACECODES = 0x4000, 46 | FRERR_BUFFERLENGTHZERO = 0x4001, 47 | CCERR_CHOOSECOLORCODES = 0x5000, 48 | } 49 | 50 | ffi.cdef[[ 51 | DWORD CommDlgExtendedError(void); 52 | ]] 53 | 54 | CommDlgExtendedError = comdlg.CommDlgExtendedError 55 | 56 | function checkcomdlg(ret) 57 | if ret == 0 then 58 | local err = CommDlgExtendedError() 59 | assert(err == 0, 'comdlg32 error: %s', COMMDLG_ERROR_NAMES[err]) 60 | return false --user canceled 61 | end 62 | return true 63 | end 64 | 65 | -------------------------------------------------------------------------------- /winapi/controlclass.md: -------------------------------------------------------------------------------- 1 | --- 2 | tagline: base class for controls 3 | --- 4 | 5 | ## `require'winapi.controlclass'` 6 | 7 | This module implements the `Control` class which is the base class for 8 | controls. `Control` is for subclassing, not for instantiation. 9 | Nevertheless, it contains properties that are common to all controls 10 | which are documented here. 11 | 12 | ## Control 13 | 14 | ### Hierarchy 15 | 16 | * [VObject][winapi.vobject] 17 | * [BaseWindow][winapi.basewindowclass] 18 | * Control 19 | 20 | ### Initial fields and properties 21 | 22 | __NOTE:__ in the table below `i` means initial field, `r` means property 23 | which can be read, `w` means property which can be set. 24 | 25 | ----------------------- -------- ----------------------------------------- -------------- --------------------- 26 | __field/property__ __irw__ __description__ __default__ __reference__ 27 | anchors irw anchors see below 28 | anc irw anchors (string form) see below 29 | parent irw control's parent Get/SetParent 30 | ----------------------- -------- ----------------------------------------- -------------- --------------------- 31 | 32 | ### Anchors 33 | 34 | Anchors are a simple but very powerful way of doing layouting. 35 | This is how they work: there's four possible anchors, 36 | one for each side of a control. 37 | Setting an anchor on one side fixates the distance between that side 38 | and the same side of the parent control, so that when the parent is 39 | moved/resized, the child is also moved/resized in order to preserve 40 | the initial distance. With anchors alone you can define pretty much 41 | every elastic layout that you see in typical desktop apps and you can 42 | do that without having to be explicit about the relationships 43 | between controls or having to specify percentages. 44 | 45 | The default value of `anchors` is `{left = true, top = true}`. 46 | 47 | Anchors can also be set and read in short form using the `anc` property: 48 | each anchored side is represented by one of the letters 'ltrb' 49 | (the default value of `anc` is thus 'lt': `anc` always reflects 50 | the value of `anchors`). 51 | -------------------------------------------------------------------------------- /winapi/cursor.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/resources/cursor: cursor resources 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.winuser' 7 | 8 | ffi.cdef[[ 9 | typedef struct { 10 | DWORD cbSize; 11 | DWORD flags; 12 | HCURSOR hCursor; 13 | POINT ptScreenPos; 14 | } CURSORINFO, *PCURSORINFO, *LPCURSORINFO; 15 | 16 | HCURSOR LoadCursorW(HINSTANCE hInstance, LPCWSTR lpCursorName); 17 | int ShowCursor(BOOL bShow); 18 | BOOL SetCursorPos(int X, int Y); 19 | BOOL SetPhysicalCursorPos(int X, int Y); 20 | HCURSOR SetCursor(HCURSOR hCursor); 21 | BOOL GetCursorPos(LPPOINT lpPoint); 22 | BOOL GetPhysicalCursorPos(LPPOINT lpPoint); 23 | DWORD GetMessagePos(void); 24 | BOOL ClipCursor(const RECT *lpRect); 25 | BOOL GetClipCursor(LPRECT lpRect); 26 | HCURSOR GetCursor(void); 27 | BOOL GetCursorInfo(PCURSORINFO pci); 28 | UINT GetCaretBlinkTime(); 29 | ]] 30 | 31 | IDC_ARROW = 32512 32 | IDC_IBEAM = 32513 33 | IDC_WAIT = 32514 34 | IDC_CROSS = 32515 35 | IDC_UPARROW = 32516 36 | IDC_SIZE = 32640 37 | IDC_ICON = 32641 38 | IDC_SIZENWSE = 32642 39 | IDC_SIZENESW = 32643 40 | IDC_SIZEWE = 32644 41 | IDC_SIZENS = 32645 42 | IDC_SIZEALL = 32646 43 | IDC_NO = 32648 44 | IDC_HAND = 32649 45 | IDC_APPSTARTING = 32650 46 | IDC_HELP = 32651 47 | 48 | function LoadCursor(hInstance, name) 49 | if not name then hInstance, name = nil, hInstance end 50 | return checkh(C.LoadCursorW(hInstance, 51 | ffi.cast('LPCWSTR', wcs(MAKEINTRESOURCE(name))))) 52 | end 53 | 54 | function SetCursor(cursor) 55 | return ptr(C.SetCursor(cursor)) 56 | end 57 | 58 | function GetMessagePos() 59 | return splitsigned(C.GetMessagePos()) 60 | end 61 | 62 | CURSOR_SHOWING = 1 63 | CURSOR_SUPPRESSED = 2 --Win8+ 64 | 65 | CURSORINFO = struct{ctype = 'CURSORINFO', size = 'cbSize'} 66 | 67 | function GetCursorInfo(pci) 68 | pci = CURSORINFO(pci) 69 | checknz(C.GetCursorInfo(pci)) 70 | return pci 71 | end 72 | 73 | --NOTE: GetCursorPos() must be passed in a POINT* in the low 2GB of address 74 | --space or it will fail. This is safe with LuaJIT 2.x but to future-proof it, 75 | --we emulate GetCursorPos() with GetCursorInfo() which doesn't suffer from this. 76 | function GetCursorPos(p, pci) 77 | pci = GetCursorInfo(pci) 78 | if p then 79 | p.x = pci.ptScreenPos.x 80 | p.y = pci.ptScreenPos.y 81 | else 82 | p = POINT(pci.ptScreenPos) 83 | end 84 | return p, pci 85 | end 86 | 87 | SetCursorPos = C.SetCursorPos 88 | 89 | function GetCaretBlinkTime() 90 | local t = checknz(C.GetCaretBlinkTime()) 91 | return t ~= 0xffffffff and t 92 | end 93 | 94 | --messages 95 | 96 | function WM.WM_SETCURSOR(wParam, lParam) 97 | local HT, id = splitlong(lParam) 98 | return ffi.cast('HWND', wParam), HT, id --HT codes are in winapi.mouse 99 | end 100 | 101 | --demo 102 | 103 | if not ... then 104 | print(LoadCursor(IDC_ARROW)) 105 | assert(LoadCursor(IDC_ARROW) == LoadCursor(IDC_ARROW)) --same handle every time, no worry about freeing these 106 | print(LoadCursor(IDC_HELP)) 107 | 108 | local p1 = GetCursorPos() 109 | local p2 = GetCursorInfo().ptScreenPos 110 | assert(p1.x == p2.x and p1.y == p2.y) 111 | local p3 = GetCursorPos(p1) 112 | assert(p1 == p3) 113 | end 114 | 115 | -------------------------------------------------------------------------------- /winapi/ddev.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/gdi/ddev: Display Devices API 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | 7 | DISPLAY_DEVICE_ATTACHED_TO_DESKTOP = 0x00000001 8 | DISPLAY_DEVICE_MULTI_DRIVER = 0x00000002 9 | DISPLAY_DEVICE_PRIMARY_DEVICE = 0x00000004 10 | DISPLAY_DEVICE_MIRRORING_DRIVER = 0x00000008 11 | DISPLAY_DEVICE_VGA_COMPATIBLE = 0x00000010 12 | DISPLAY_DEVICE_REMOVABLE = 0x00000020 13 | DISPLAY_DEVICE_MODESPRUNED = 0x08000000 14 | DISPLAY_DEVICE_REMOTE = 0x04000000 15 | DISPLAY_DEVICE_DISCONNECT = 0x02000000 16 | DISPLAY_DEVICE_TS_COMPATIBLE = 0x00200000 17 | DISPLAY_DEVICE_UNSAFE_MODES_ON = 0x00080000 18 | DISPLAY_DEVICE_ACTIVE = 0x00000001 19 | DISPLAY_DEVICE_ATTACHED = 0x00000002 20 | 21 | EDD_GET_DEVICE_INTERFACE_NAME = 0x00000001 22 | 23 | ffi.cdef[[ 24 | typedef struct _DISPLAY_DEVICEW { 25 | DWORD cb; 26 | WCHAR DeviceName[32]; 27 | WCHAR DeviceString[128]; 28 | DWORD StateFlags; 29 | WCHAR DeviceID[128]; 30 | WCHAR DeviceKey[128]; 31 | } DISPLAY_DEVICEW, *PDISPLAY_DEVICEW, *LPDISPLAY_DEVICEW; 32 | 33 | BOOL EnumDisplayDevicesW( 34 | LPCWSTR lpDevice, 35 | DWORD iDevNum, 36 | PDISPLAY_DEVICEW lpDisplayDevice, 37 | DWORD dwFlags); 38 | ]] 39 | 40 | DISPLAY_DEVICE = struct{ctype = 'DISPLAY_DEVICEW', size = 'cb', 41 | fields = sfields{ 42 | 'device_name', '', wc_set'DeviceName', wc_get'DeviceName', 43 | 'device_string', '', wc_set'DeviceString', wc_get'DeviceString', 44 | 'state_flags', 'StateFlags', flags, pass, 45 | 'device_id', '', wc_set'DeviceID', wc_get'DeviceID', 46 | 'device_key', '', wc_set'DeviceKey', wc_get'DeviceKey', 47 | } 48 | } 49 | 50 | --if devname_or_index is nil, returns an iterator instead! 51 | function EnumDisplayDevices(devname_or_index, dd, EDD) 52 | dd = DISPLAY_DEVICE(dd) 53 | if not devname_or_index then 54 | local i = 0 55 | return function() 56 | local ret = EnumDisplayDevices(i, dd, EDD) 57 | if not ret then return end 58 | i = i + 1 59 | return ret 60 | end 61 | end 62 | local devname = type(devname_or_index) == 'string' and wcs(devname_or_index) or nil 63 | local devindex = tonumber(devname_or_index) or 0 64 | local ret = C.EnumDisplayDevicesW(devname, devindex, dd, flags(EDD)) 65 | return ret ~= 0 and dd or nil 66 | end 67 | 68 | 69 | --showcase 70 | 71 | if not ... then 72 | for dd in EnumDisplayDevices() do 73 | print(dd.device_name, dd.device_string, dd.state_flags, dd.device_id, dd.device_key) 74 | end 75 | end 76 | -------------------------------------------------------------------------------- /winapi/debug.lua: -------------------------------------------------------------------------------- 1 | 2 | --binding/debug: strict mode and debug tools (optional module) 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi.namespace') 6 | 7 | --disable stdout buffering so we can print-debug stuff 8 | io.stdout:setvbuf'no' 9 | io.stderr:setvbuf'no' 10 | 11 | --set strict mode for the whole winapi namespace 12 | local _G = _G 13 | local declared = {} 14 | 15 | local getinfo = debug.getinfo 16 | local rawget, rawset = rawget, rawset 17 | 18 | function _M:__index(k) 19 | if declared[k] then return nil end 20 | if rawget(_G, k) ~= nil then return rawget(_G, k) end 21 | error(string.format('Undefined winapi global %s', k), 2) 22 | end 23 | 24 | function _M:__newindex(k,v) 25 | if declared[k] then 26 | rawset(self, k, v) 27 | else 28 | --NOTE: linedefined is always 0 for stripped bytecode, which makes 29 | --strict mode innefective if winapi is compiled and loaded as bytecode. 30 | --The reason we don't check for `what == 'main'` like strict.lua does, 31 | --is because LuaJIT sets `what` to "Lua" on stripped bytecode, while 32 | --Lua sets it to "main". 33 | local info = getinfo(2, 'S') 34 | if info and info.linedefined > 0 then 35 | error(string.format('Assignment to undeclared winapi global %s', k), 2) 36 | end 37 | declared[k] = true 38 | rawset(self, k, v) 39 | end 40 | end 41 | 42 | --utility to search the name of a constant in the winapi namespace. 43 | function findname(prefix, value) 44 | for k,v in pairs(_M) do 45 | if k:match('^'..prefix) and type(v) ~= 'cdata' and type(value) ~= 'cdata' and v == value then return k end 46 | end 47 | return tonumber(value) ~= nil and string.format('%x', value) or value 48 | end 49 | 50 | --utility to search the names of the bitmasks corresponding to the bits of a value. 51 | --eg. in a WM_WINDOWPOSCHANGING(wp) message you can print(findbits('SWP_', wp.flags)). 52 | function findbits(prefix, value) 53 | local t = {} 54 | for k,v in pairs(_M) do 55 | if k:match('^'..prefix) and getbit(value, v) then 56 | t[#t+1] = k 57 | end 58 | end 59 | return table.concat(t, ' ') 60 | end 61 | 62 | -------------------------------------------------------------------------------- /winapi/dibitmap.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/gdi/dibitmap: RGBA device independent bitmaps 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | 7 | --make a DIB that can be painted on any DC and on a WS_EX_LAYERED window. 8 | function DIBitmap(w, h, compat_hwnd) 9 | 10 | --can't create a zero-sized bitmap 11 | assert(w > 0 and h > 0, 'invalid size') 12 | 13 | --initialize a new DIB header for a top-down bgra8 bitmap. 14 | local bi = BITMAPV5HEADER() 15 | bi.bV5Width = w 16 | bi.bV5Height = -h 17 | bi.bV5Planes = 1 18 | bi.bV5BitCount = 32 19 | bi.bV5Compression = BI_BITFIELDS 20 | bi.bV5SizeImage = w * h * 4 21 | --this mask specifies a supported 32bpp alpha format for Windows XP. 22 | bi.bV5RedMask = 0x00FF0000 23 | bi.bV5GreenMask = 0x0000FF00 24 | bi.bV5BlueMask = 0x000000FF 25 | bi.bV5AlphaMask = 0xFF000000 26 | --this flag is important for making clipboard-compatible packed DIBs! 27 | bi.bV5CSType = LCS_WINDOWS_COLOR_SPACE 28 | 29 | --create a DC compatible with compat_hwnd or with the current screen, 30 | --if compat_hwnd is not given. 31 | local compat_hdc = GetDC(compat_hwnd) 32 | local hdc = CreateCompatibleDC(compat_hdc) 33 | ReleaseDC(nil, compat_hdc) 34 | 35 | local info = ffi.cast('BITMAPINFO*', bi) 36 | local hbmp, data = CreateDIBSection(hdc, info, DIB_RGB_COLORS) 37 | local old_hbmp = SelectObject(hdc, hbmp) 38 | 39 | local bitmap = { 40 | --bitmap format 41 | w = w, 42 | h = h, 43 | data = data, 44 | stride = w * 4, 45 | size = w * h * 4, 46 | format = 'bgra8', 47 | --extra stuff 48 | hbmp = hbmp, 49 | hdc = hdc, 50 | } 51 | 52 | --paint the bitmap on a DC. 53 | function bitmap:paint(dest_hdc, dx, dy, sx, sy, op) 54 | BitBlt(dest_hdc, dx or 0, dy or 0, w, h, hdc, sx or 0, sy or 0, op or SRCCOPY) 55 | end 56 | 57 | --update a WS_EX_LAYERED window with the bitmap contents and size. 58 | --the bitmap must have window's client rectangle size, otherwise 59 | --the window is resized to the size of the bitmap! 60 | --NOTE: x and y should be the window's position in screen coordinates, 61 | --otherwise the window is moved to where the x and y indicates! 62 | --NOTE: returns true/false for success/failure. 63 | --NOTE: This call fails on Remote Desktop connections. 64 | local pos = POINT() 65 | local topleft = POINT() 66 | local size = SIZE(w, h) 67 | local blendfunc = types.BLENDFUNCTION{ 68 | AlphaFormat = AC_SRC_ALPHA, 69 | BlendFlags = 0, 70 | BlendOp = AC_SRC_OVER, 71 | SourceConstantAlpha = 255, 72 | } 73 | function bitmap:update_layered(dest_hwnd, x, y) 74 | pos.x = x 75 | pos.y = y 76 | return UpdateLayeredWindow(dest_hwnd, nil, pos, size, hdc, 77 | topleft, 0, blendfunc, ULW_ALPHA) 78 | end 79 | 80 | --free the bitmap and DC. 81 | local function free() 82 | assert(hbmp, 'double free') 83 | ffi.gc(hbmp, nil) 84 | SelectObject(hdc, old_hbmp) 85 | DeleteObject(hbmp) 86 | DeleteDC(hdc) 87 | data, hbmp, hdc = nil 88 | bitmap.data = nil 89 | bitmap.hbmp = nil 90 | bitmap.hdc = nil 91 | end 92 | ffi.gc(hbmp, free) 93 | bitmap.free = free 94 | 95 | return bitmap 96 | end 97 | 98 | -------------------------------------------------------------------------------- /winapi/dpiaware.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/windows/dpiaware: DPI-awareness API 3 | 4 | setfenv(1, require'winapi') 5 | require'winapi.monitor' 6 | 7 | --Vista+ DPI awareness flag -------------------------------------------------- 8 | 9 | ffi.cdef[[ 10 | BOOL SetProcessDPIAware(void); // Vista+ 11 | BOOL IsProcessDPIAware(void); // Vista+ 12 | ]] 13 | 14 | --NOTE: call this before calling any other window or monitor-related API. 15 | --Calling it later will not return an error but it will have no effect. 16 | function SetProcessDPIAware() 17 | return checknz(C.SetProcessDPIAware()) 18 | end 19 | 20 | --NOTE: At scaling levels below 150% this function always returns 1 21 | --because DPI Virtualization is disabled at low scaling levels. 22 | function IsProcessDPIAware() 23 | return C.IsProcessDPIAware() == 1 24 | end 25 | 26 | --Win8.1+ DPI awareness flag ------------------------------------------------- 27 | 28 | PROCESS_DPI_UNAWARE = 0 29 | PROCESS_SYSTEM_DPI_AWARE = 1 30 | PROCESS_PER_MONITOR_DPI_AWARE = 2 31 | 32 | ffi.cdef[[ 33 | HRESULT SetProcessDpiAwarenessInternal(int); // Win8.1+ 34 | HRESULT GetProcessDpiAwarenessInternal(HANDLE, int*); // Win8.1+ 35 | ]] 36 | 37 | function SetProcessDPIAwareness(awareness) 38 | checknz(C.SetProcessDpiAwarenessInternal(flags(awareness))) 39 | end 40 | 41 | function GetProcessDPIAwareness(handle) 42 | local buf = ffi.new'int[1]' 43 | checknz(C.GetProcessDpiAwarenessInternal(handle, buf)) 44 | return buf[0] 45 | end 46 | 47 | --Win8.1+ per-monitor DPI setting -------------------------------------------- 48 | 49 | MDT_EFFECTIVE_DPI = 0 50 | MDT_ANGULAR_DPI = 1 51 | MDT_RAW_DPI = 2 52 | MDT_DEFAULT = MDT_EFFECTIVE_DPI 53 | 54 | ffi.cdef[[ 55 | HRESULT GetDpiForMonitor( 56 | HMONITOR hmonitor, 57 | int dpiType, // MDT_* 58 | UINT *dpiX, 59 | UINT *dpiY 60 | ); // Win8.1+ 61 | ]] 62 | 63 | local shcore 64 | function GetDPIForMonitor(hmonitor, MDT, dx, dy) 65 | shcore = shcore or ffi.load'shcore' 66 | local dx = dx or ffi.new'UINT[1]' 67 | local dy = dy or ffi.new'UINT[1]' 68 | checkz(shcore.GetDpiForMonitor(hmonitor, flags(MDT), dx, dy)) 69 | return dx[0], dy[0] 70 | end 71 | 72 | --Win8.1+ dpi-changed message ------------------------------------------------ 73 | 74 | function WM.WM_DPICHANGED(wParam, lParam) 75 | local x, y = splitlong(wParam) 76 | local r = ffi.cast('RECT*', lParam) 77 | return x, y, r.x1, r.y1, r.x2, r.y2 78 | end 79 | 80 | if not ... then 81 | local win8_1 = true --enable this if on Win8.1+ 82 | if win8_1 then 83 | local awareness = PROCESS_PER_MONITOR_DPI_AWARE 84 | SetProcessDPIAwareness(awareness) 85 | assert(GetProcessDPIAwareness() == awareness) 86 | 87 | local mon = assert(MonitorFromPoint()) 88 | print('DPI', GetDPIForMonitor(mon, MDT_EFFECTIVE_DPI)) 89 | else 90 | SetProcessDPIAware() 91 | assert(IsProcessDPIAware()) 92 | end 93 | end 94 | -------------------------------------------------------------------------------- /winapi/dragdrop.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/ole/dragdrop: drag & drop OLE API 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.ole' 7 | require'winapi.idataobject' 8 | 9 | DRAGDROP_S_FIRST = 0x00040100 10 | DRAGDROP_S_LAST = 0x0004010F 11 | DRAGDROP_S_DROP = 0x00040100 12 | DRAGDROP_S_CANCEL = 0x00040101 13 | DRAGDROP_S_USEDEFAULTCURSORS = 0x00040102 14 | 15 | DROPEFFECT_NONE = 0 16 | DROPEFFECT_COPY = 1 17 | DROPEFFECT_MOVE = 2 18 | DROPEFFECT_LINK = 4 19 | DROPEFFECT_SCROLL = 0x80000000 20 | 21 | DATADIR_GET = 1 22 | DATADIR_SET = 2 23 | 24 | TYMED_HGLOBAL = 1 25 | TYMED_FILE = 2 26 | TYMED_ISTREAM = 4 27 | TYMED_ISTORAGE = 8 28 | TYMED_GDI = 16 29 | TYMED_MFPICT = 32 30 | TYMED_ENHMF = 64 31 | TYMED_NULL = 0 32 | 33 | ffi.cdef([[ 34 | typedef struct IDropTarget IDropTarget; 35 | typedef IDropTarget *LPDROPTARGET; 36 | 37 | typedef struct IDropTargetVtbl { 38 | 39 | HRESULT ( __stdcall *QueryInterface )( 40 | IDropTarget * This, 41 | REFIID riid, 42 | void **ppvObject); 43 | 44 | ULONG ( __stdcall *AddRef )( 45 | IDropTarget * This); 46 | 47 | ULONG ( __stdcall *Release )( 48 | IDropTarget * This); 49 | 50 | HRESULT ( __stdcall *DragEnter )( 51 | IDropTarget * This, 52 | IDataObject *pDataObj, 53 | DWORD grfKeyState, 54 | ]]..(ffi.abi'32bit' and 'LONG x, LONG y' or 'POINTL pt')..[[, 55 | DWORD *pdwEffect); 56 | 57 | HRESULT ( __stdcall *DragOver )( 58 | IDropTarget * This, 59 | DWORD grfKeyState, 60 | ]]..(ffi.abi'32bit' and 'LONG x, LONG y' or 'POINTL pt')..[[, 61 | DWORD *pdwEffect); 62 | 63 | HRESULT ( __stdcall *DragLeave )( 64 | IDropTarget * This); 65 | 66 | HRESULT ( __stdcall *Drop )( 67 | IDropTarget * This, 68 | IDataObject *pDataObj, 69 | DWORD grfKeyState, 70 | ]]..(ffi.abi'32bit' and 'LONG x, LONG y' or 'POINTL pt')..[[, 71 | DWORD *pdwEffect); 72 | 73 | } IDropTargetVtbl; 74 | 75 | struct IDropTarget { 76 | struct IDropTargetVtbl *lpVtbl; 77 | int refcount; 78 | }; 79 | 80 | typedef struct IDropSource IDropSource; 81 | typedef IDropSource *LPDROPSOURCE; 82 | 83 | typedef struct IDropSourceVtbl { 84 | 85 | HRESULT ( __stdcall *QueryInterface )( 86 | IDropSource * This, 87 | REFIID riid, 88 | void **ppvObject); 89 | 90 | ULONG ( __stdcall *AddRef )( 91 | IDropSource * This); 92 | 93 | ULONG ( __stdcall *Release )( 94 | IDropSource * This); 95 | 96 | HRESULT ( __stdcall *QueryContinueDrag )( 97 | IDropSource * This, 98 | BOOL fEscapePressed, 99 | DWORD grfKeyState); 100 | 101 | HRESULT ( __stdcall *GiveFeedback )( 102 | IDropSource * This, 103 | DWORD dwEffect); 104 | 105 | } IDropSourceVtbl; 106 | 107 | struct IDropSource { 108 | struct IDropSourceVtbl *lpVtbl; 109 | }; 110 | 111 | HRESULT RegisterDragDrop(HWND hwnd, LPDROPTARGET pDropTarget); 112 | HRESULT RevokeDragDrop(HWND hwnd); 113 | HRESULT DoDragDrop(LPDATAOBJECT pDataObj, LPDROPSOURCE pDropSource, 114 | DWORD dwOKEffects, LPDWORD pdwEffect); 115 | 116 | void ReleaseStgMedium(LPSTGMEDIUM); 117 | ]]) 118 | 119 | function RegisterDragDrop(...) return checkz(ole32.RegisterDragDrop(...)) end 120 | function RevokeDragDrop(...) return checkz(ole32.RevokeDragDrop(...)) end 121 | function DoDragDrop(...) return checkz(ole32.DoDragDrop(...)) end 122 | 123 | ReleaseStgMedium = ole32.ReleaseStgMedium 124 | 125 | -------------------------------------------------------------------------------- /winapi/editclass.lua: -------------------------------------------------------------------------------- 1 | 2 | --oo/controls/edit: standard edit control 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.controlclass' 7 | require'winapi.edit' 8 | require'winapi.gdi' 9 | 10 | Edit = subclass({ 11 | __style_bitmask = bitmask{ 12 | tabstop = WS_TABSTOP, 13 | border = WS_BORDER, 14 | readonly = ES_READONLY, 15 | multiline = ES_MULTILINE, 16 | password = ES_PASSWORD, 17 | autovscroll = ES_AUTOVSCROLL, 18 | autohscroll = ES_AUTOHSCROLL, 19 | number = ES_NUMBER, 20 | dont_hide_selection = ES_NOHIDESEL, 21 | want_return = ES_WANTRETURN, 22 | align = { 23 | left = ES_LEFT, 24 | right = ES_RIGHT, 25 | center = ES_CENTER, 26 | }, 27 | case = { 28 | normal = 0, 29 | upper = ES_UPPERCASE, 30 | lower = ES_LOWERCASE, 31 | }, 32 | }, 33 | __style_ex_bitmask = bitmask{ 34 | client_edge = WS_EX_CLIENTEDGE, 35 | }, 36 | __defaults = { 37 | text = '', 38 | w = 100, h = 21, 39 | readonly = false, 40 | client_edge = true, 41 | tabstop = true, 42 | align = 'left', 43 | case = 'normal', 44 | }, 45 | __init_properties = { 46 | 'text', 'limit', 'password_char', 'tabstops', 'margins', 'cue', 47 | }, 48 | __wm_command_handler_names = index{ 49 | on_setfocus = EN_SETFOCUS, 50 | on_killfocus = EN_KILLFOCUS, 51 | on_change = EN_CHANGE, 52 | on_update = EN_UPDATE, 53 | on_errspace = EN_ERRSPACE, 54 | on_maxtext = EN_MAXTEXT, 55 | on_hscroll = EN_HSCROLL, 56 | on_vscroll = EN_VSCROLL, 57 | on_align_ltr_ec = EN_ALIGN_LTR_EC, 58 | on_align_rtl_ec = EN_ALIGN_RTL_EC, 59 | }, 60 | }, Control) 61 | 62 | function Edit:after___before_create(info, args) 63 | args.class = WC_EDIT 64 | end 65 | 66 | function Edit:get_limit() return Edit_GetLimitText(self.hwnd) end 67 | function Edit:set_limit(limit) Edit_SetLimitText(self.hwnd, limit) end 68 | 69 | function Edit:get_selection_indices() return {Edit_GetSel(self.hwnd)} end 70 | function Edit:set_selection_indices(t) Edit_SetSel(self.hwnd, unpack(t,1,2)) end 71 | function Edit:select(i,j) Edit_SetSel(self.hwnd, i, j) end 72 | 73 | function Edit:get_selection_text(s) return ':(' end --TODO: get_selection_text 74 | function Edit:set_selection_text(s) Edit_ReplaceSel(self.hwnd, s) end 75 | 76 | function Edit:get_modified() return Edit_GetModify(self.hwnd) end 77 | function Edit:set_modified(yes) Edit_SetModify(self.hwnd, yes) end 78 | 79 | function Edit:scroll_caret() Edit_ScrollCaret(self.hwnd) end 80 | 81 | function Edit:get_first_visible_line() return Edit_GetFirstVisibleLine(self.hwnd) end 82 | function Edit:line_from_char(charindex) return Edit_LineFromChar(self.hwnd, charindex) end 83 | function Edit:line_index(lineindex) return Edit_LineIndex(self.hwnd, lineindex) end 84 | function Edit:line_length(lineindex) return Edit_LineLength(self.hwnd, lineindex) end 85 | function Edit:scroll(dv, dh) return Edit_Scroll(self.hwnd, dv, dh) end 86 | 87 | function Edit:get_can_undo() return Edit_CanUndo(self.hwnd) end 88 | function Edit:undo() return Edit_Undo(self.hwnd) end 89 | function Edit:clear_undo() return Edit_EmptyUndoBuffer(self.hwnd) end 90 | 91 | function Edit:set_password_char(s) Edit_SetPasswordChar(self.hwnd, wcs(s)[0]) end 92 | function Edit:get_password_char() return mbs(ffi.new('WCHAR[1]', Edit_GetPasswordChar(self.hwnd))) end 93 | 94 | function Edit:set_tabstops(tabs) Edit_SetTabStops(self.hwnd, tabs) end --stateful 95 | 96 | function Edit:get_margins() return {Edit_GetMargins(self.hwnd)} end 97 | function Edit:set_margins(t) Edit_SetMargins(self.hwnd, unpack(t)) end 98 | 99 | function Edit:get_cue() return '' or Edit_GetCueBannerText(self.hwnd) end --TODO: returns FALSE 100 | function Edit:set_cue(s, show_when_focused) Edit_SetCueBannerText(self.hwnd, s, show_when_focused) end 101 | 102 | function Edit:show_balloon(title, text, TTI) Edit_ShowBalloonTip(self.hwnd, title, text, TTI) end 103 | function Edit:hide_balloon() Edit_HideBalloonTip(self.hwnd) end 104 | 105 | 106 | --showcase 107 | 108 | if not ... then 109 | require'winapi.showcase' 110 | local window = ShowcaseWindow{w=300,h=200} 111 | local e1 = Edit{parent = window, x = 10, y = 10, case = 'upper', limit = 8} 112 | function e1:on_change() print('changed', self.text) end 113 | e1.text = 'hello' 114 | 115 | local e2 = Edit{parent = window, x = 10, y = 40, align = 'right'} 116 | e2.text = 'hola' 117 | 118 | local e3 = Edit{x = 10, y = 70, visible = false} 119 | e3.parent = window 120 | e3.visible = true 121 | window.visible = false 122 | print('visible', e2.visible, e2.is_visible) 123 | for e in window:children() do print(e.text) end 124 | window.visible = true 125 | 126 | e1:focus() 127 | e1:select(2,4) 128 | print(unpack(e1.selection_indices)) 129 | e1.selection_text = 'xx' 130 | e1.margins = {15, 15} 131 | print(unpack(e1.margins)) 132 | 133 | e3:set_cue('Search', true) 134 | require'winapi.tooltip' 135 | e3:show_balloon('Duude', 'This is Cool!', TTI_INFO) 136 | 137 | e4 = Edit{x = 10, y = 100, parent = window, readonly = true} 138 | e4.text = "Can't touch this" 139 | 140 | MessageLoop() 141 | end 142 | 143 | -------------------------------------------------------------------------------- /winapi/editclass.md: -------------------------------------------------------------------------------- 1 | --- 2 | tagline: edit boxes 3 | --- 4 | 5 | ## `require'winapi.editclass'` 6 | 7 | This module implements the `Edit` class for creating edit boxes. 8 | 9 | ## Edit 10 | 11 | ### Hierarchy 12 | 13 | * [VObject][winapi.vobject] 14 | * [BaseWindow][winapi.basewindowclass] 15 | * [Control][winapi.controlclass] 16 | * Edit 17 | 18 | ### Initial fields and properties 19 | 20 | __NOTE:__ in the table below `i` means initial field, `r` means property 21 | which can be read, `w` means property which can be set. 22 | 23 | ----------------------- -------- ----------------------------------------- -------------- --------------------- 24 | __field/property__ __irw__ __description__ __default__ __reference__ 25 | text irw text to edit '' Get/SetWindowText 26 | w, h irw size 100, 21 27 | tabstop irw focus on tab true WS_TABSTOP 28 | border irw TODO false WS_BORDER 29 | readonly irw TODO false ES_READONLY 30 | multiline irw TODO false ES_MULTILINE 31 | password irw TODO false ES_PASSWORD 32 | autovscroll irw TODO false ES_AUTOVSCROLL 33 | autohscroll irw TODO false ES_AUTOHSCROLL 34 | number irw TODO false ES_NUMBER 35 | dont_hide_selection irw TODO false ES_NOHIDESEL 36 | want_return irw TODO false ES_WANTRETURN 37 | align irw 'left', 'right', 'center' 'left' ES_LEFT/RIGHT/CENTER 38 | case irw 'normal', 'uppwer', 'lower' 'normal' ES_UPPER/LOWERCASE 39 | client_edge irw double-border true WS_EX_CLIENTEDGE 40 | limit irw TODO 41 | password_char TODO 42 | tabstops TODO 43 | margins TODO 44 | cue TODO 45 | ----------------------- -------- ----------------------------------------- -------------- --------------------- 46 | 47 | ### Events 48 | 49 | -------------------------------- -------------------------------------------- ---------------------- 50 | __event__ __description__ __reference__ 51 | on_setfocus() TODO EN_SETFOCUS 52 | on_killfocus() TODO EN_KILLFOCUS 53 | on_change() TODO EN_CHANGE 54 | on_update() TODO EN_UPDATE 55 | on_errspace() TODO EN_ERRSPACE 56 | on_maxtext() TODO EN_MAXTEXT 57 | on_hscroll() TODO EN_HSCROLL 58 | on_vscroll() TODO EN_VSCROLL 59 | on_align_ltr_ec() TODO EN_ALIGN_LTR_EC 60 | on_align_rtl_ec() TODO EN_ALIGN_RTL_EC 61 | -------------------------------- -------------------------------------------- --------------------- 62 | -------------------------------------------------------------------------------- /winapi/filemapping.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/system/filemapping: memory mapped files 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.winbase' 7 | require'winapi.winnt' 8 | 9 | ffi.cdef[[ 10 | HANDLE CreateFileMappingW( 11 | HANDLE hFile, 12 | LPSECURITY_ATTRIBUTES lpFileMappingAttributes, 13 | DWORD flProtect, 14 | DWORD dwMaximumSizeHigh, 15 | DWORD dwMaximumSizeLow, 16 | LPCWSTR lpName 17 | ); 18 | 19 | LPVOID MapViewOfFileEx( 20 | HANDLE hFileMappingObject, 21 | DWORD dwDesiredAccess, 22 | DWORD dwFileOffsetHigh, 23 | DWORD dwFileOffsetLow, 24 | SIZE_T dwNumberOfBytesToMap, 25 | LPVOID lpBaseAddress 26 | ); 27 | 28 | BOOL UnmapViewOfFile( 29 | LPCVOID lpBaseAddress 30 | ); 31 | 32 | BOOL FlushViewOfFile(LPCVOID lpBaseAddress, SIZE_T dwNumberOfBytesToFlush); 33 | ]] 34 | 35 | FILE_MAP_WRITE = SECTION_MAP_WRITE 36 | FILE_MAP_READ = SECTION_MAP_READ 37 | FILE_MAP_ALL_ACCESS = SECTION_ALL_ACCESS 38 | FILE_MAP_COPY = 0x00000001 39 | FILE_MAP_RESERVE = 0x80000000 40 | FILE_MAP_EXECUTE = SECTION_MAP_EXECUTE_EXPLICIT --XP SP2+ 41 | 42 | function CreateFileMapping(hfile, secattrs, protect, maxsize, name) 43 | hfile = hfile or INVALID_HANDLE_VALUE 44 | local mhi, mlo = split_uint64(maxsize) 45 | return reth(C.CreateFileMappingW( 46 | hfile, secattrs, flags(protect), mhi, mlo, wcs(name))) 47 | end 48 | 49 | function MapViewOfFile(hfilemap, access, offset, sz, baseaddr) 50 | local ohi, olo = split_uint64(offset) 51 | return reth(C.MapViewOfFileEx(hfilemap, flags(access), ohi, olo, sz, baseaddr)) 52 | end 53 | 54 | function UnmapViewOfFile(baseaddr) 55 | checknz(C.UnmapViewOfFile(baseaddr)) 56 | end 57 | 58 | function FlushViewOfFile(baseaddr, sz) 59 | return retnz(C.FlushViewOfFile(baseaddr, sz)) 60 | end 61 | 62 | if not ... then 63 | for i=1,100 do 64 | local sz = 100*1024^2 65 | local fm = assert(CreateFileMapping(nil, nil, 'PAGE_READWRITE', sz, 'big_shm')) 66 | print(fm) 67 | local p = MapViewOfFile(fm, 'FILE_MAP_WRITE', 0, sz) 68 | print(p) 69 | assert(FlushViewOfFile(p, sz)) 70 | UnmapViewOfFile(p) 71 | assert(CloseHandle(fm)) 72 | end 73 | end 74 | -------------------------------------------------------------------------------- /winapi/font.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/resources/font: font resources (the old API) 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.winuser' 7 | require'winapi.gdi' 8 | require'winapi.logfonttype' 9 | 10 | ffi.cdef[[ 11 | HFONT CreateFontIndirectW(const LOGFONTW *); 12 | ]] 13 | 14 | --weights 15 | FW_DONTCARE = 0 16 | FW_THIN = 100 17 | FW_EXTRALIGHT = 200 18 | FW_LIGHT = 300 19 | FW_NORMAL = 400 20 | FW_MEDIUM = 500 21 | FW_SEMIBOLD = 600 22 | FW_BOLD = 700 23 | FW_EXTRABOLD = 800 24 | FW_HEAVY = 900 25 | FW_ULTRALIGHT = FW_EXTRALIGHT 26 | FW_REGULAR = FW_NORMAL 27 | FW_DEMIBOLD = FW_SEMIBOLD 28 | FW_ULTRABOLD = FW_EXTRABOLD 29 | FW_BLACK = FW_HEAVY 30 | --charsets 31 | ANSI_CHARSET = 0 32 | DEFAULT_CHARSET = 1 33 | SYMBOL_CHARSET = 2 34 | SHIFTJIS_CHARSET = 128 35 | HANGEUL_CHARSET = 129 36 | HANGUL_CHARSET = 129 37 | GB2312_CHARSET = 134 38 | CHINESEBIG5_CHARSET = 136 39 | OEM_CHARSET = 255 40 | JOHAB_CHARSET = 130 41 | HEBREW_CHARSET = 177 42 | ARABIC_CHARSET = 178 43 | GREEK_CHARSET = 161 44 | TURKISH_CHARSET = 162 45 | VIETNAMESE_CHARSET = 163 46 | THAI_CHARSET = 222 47 | EASTEUROPE_CHARSET = 238 48 | RUSSIAN_CHARSET = 204 49 | MAC_CHARSET = 77 50 | BALTIC_CHARSET = 186 51 | --styles 52 | FS_LATIN1 = 0x00000001 53 | FS_LATIN2 = 0x00000002 54 | FS_CYRILLIC = 0x00000004 55 | FS_GREEK = 0x00000008 56 | FS_TURKISH = 0x00000010 57 | FS_HEBREW = 0x00000020 58 | FS_ARABIC = 0x00000040 59 | FS_BALTIC = 0x00000080 60 | FS_VIETNAMESE = 0x00000100 61 | FS_THAI = 0x00010000 62 | FS_JISJAPAN = 0x00020000 63 | FS_CHINESESIMP = 0x00040000 64 | FS_WANSUNG = 0x00080000 65 | FS_CHINESETRAD = 0x00100000 66 | FS_JOHAB = 0x00200000 67 | FS_SYMBOL = 0x80000000 68 | --output precisions 69 | OUT_DEFAULT_PRECIS = 0 70 | OUT_STRING_PRECIS = 1 71 | OUT_CHARACTER_PRECIS = 2 72 | OUT_STROKE_PRECIS = 3 73 | OUT_TT_PRECIS = 4 74 | OUT_DEVICE_PRECIS = 5 75 | OUT_RASTER_PRECIS = 6 76 | OUT_TT_ONLY_PRECIS = 7 77 | OUT_OUTLINE_PRECIS = 8 78 | OUT_SCREEN_OUTLINE_PRECIS = 9 79 | OUT_PS_ONLY_PRECIS = 10 80 | --clip precisions 81 | CLIP_DEFAULT_PRECIS = 0 82 | CLIP_CHARACTER_PRECIS = 1 83 | CLIP_STROKE_PRECIS = 2 84 | CLIP_MASK = 0xf 85 | CLIP_LH_ANGLES = bit.lshift(1,4) 86 | CLIP_TT_ALWAYS = bit.lshift(2,4) 87 | CLIP_DFA_DISABLE = bit.lshift(4,4) 88 | CLIP_EMBEDDED = bit.lshift(8,4) 89 | --qualities 90 | DEFAULT_QUALITY = 0 91 | DRAFT_QUALITY = 1 92 | PROOF_QUALITY = 2 93 | NONANTIALIASED_QUALITY = 3 94 | ANTIALIASED_QUALITY = 4 95 | CLEARTYPE_QUALITY = 5 96 | CLEARTYPE_NATURAL_QUALITY = 6 97 | --pitches 98 | DEFAULT_PITCH = 0 99 | FIXED_PITCH = 1 100 | VARIABLE_PITCH = 2 101 | --families 102 | FF_DONTCARE = bit.lshift(0,4) -- Don't care or don't know. 103 | FF_ROMAN = bit.lshift(1,4) -- Variable stroke width, serifed. Times Roman, Century Schoolbook, etc. 104 | FF_SWISS = bit.lshift(2,4) -- Variable stroke width, sans-serifed. Helvetica, Swiss, etc. 105 | FF_MODERN = bit.lshift(3,4) -- Constant stroke width, serifed or sans-serifed. Pica, Elite, Courier, etc. 106 | FF_SCRIPT = bit.lshift(4,4) -- Cursive, etc. 107 | FF_DECORATIVE = bit.lshift(5,4) -- Old English, etc. 108 | 109 | local function setpitch(v, cdata) --it's in the first 2 low bits 110 | return bit.bor(v, bit.band(cdata.lfPitchAndFamily, 0xff-3)) 111 | end 112 | 113 | local function setfamily(v, cdata) --it's in the high 6 bits 114 | return bit.bor(v, bit.band(cdata.lfPitchAndFamily, 3)) 115 | end 116 | 117 | local function getpitch(v, cdata) --it's in the first 2 low bits 118 | return bit.band(cdata.lfPitchAndFamily, 3) 119 | end 120 | 121 | local function getfamily(v, cdata) --it's in the high 6 bits 122 | return bit.band(cdata.lfPitchAndFamily, 0xff-3) 123 | end 124 | 125 | LOGFONT = struct{ 126 | ctype = 'LOGFONTW', 127 | fields = sfields{ 128 | 'weight', 'lfWeight', flags, pass, --FW_* 129 | 'charset', 'lfCharSet', flags, pass, --*_CHARSET 130 | 'precision', 'lfOutPrecision', flags, pass, --OUT_* 131 | 'clip_precision', 'lfClipPrecision', flags, pass, --CLIP_* 132 | 'quality', 'lfQuality', flags, pass, --*_QUALITY 133 | 'pitch', 'lfPitchAndFamily', setpitch, getpitch, --*_PITCH 134 | 'family', 'lfPitchAndFamily', setfamily, getfamily, --FF_* 135 | 'facename', '', wc_set'lfFaceName', wc_get'lfFaceName', 136 | } 137 | } 138 | 139 | function CreateFont(lf) 140 | return own(checkh(C.CreateFontIndirectW(LOGFONT(lf))), DeleteObject) 141 | end 142 | 143 | --showcase 144 | 145 | if not ... then 146 | local logfont = LOGFONT{facename = 'Arial'} 147 | assert(logfont.facename == 'Arial') 148 | print('CreateFont:', CreateFont(logfont)) 149 | end 150 | 151 | -------------------------------------------------------------------------------- /winapi/fontex.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/resources/fontex: font resources (the new API) 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.font' 7 | 8 | ffi.cdef[[ 9 | typedef struct tagENUMLOGFONTEXW 10 | { 11 | LOGFONTW elfLogFont; 12 | WCHAR elfFullName[64]; 13 | WCHAR elfStyle[32]; 14 | WCHAR elfScript[32]; 15 | } ENUMLOGFONTEXW, *LPENUMLOGFONTEXW; 16 | 17 | typedef struct tagDESIGNVECTOR 18 | { 19 | DWORD dvReserved; 20 | DWORD dvNumAxes; 21 | LONG dvValues[16]; 22 | } DESIGNVECTOR, *PDESIGNVECTOR, *LPDESIGNVECTOR; 23 | 24 | typedef struct tagENUMLOGFONTEXDVW 25 | { 26 | ENUMLOGFONTEXW elfEnumLogfontEx; 27 | DESIGNVECTOR elfDesignVector; 28 | } ENUMLOGFONTEXDVW, *PENUMLOGFONTEXDVW, *LPENUMLOGFONTEXDVW; 29 | 30 | HFONT CreateFontIndirectExW(const ENUMLOGFONTEXDVW *); 31 | ]] 32 | 33 | ENUMLOGFONTEXDVW = struct{ 34 | ctype = 'ENUMLOGFONTEXDVW', 35 | } 36 | 37 | function CreateFontEx(lfex) 38 | lfex = ENUMLOGFONTEXDVW(lfex) 39 | return own(checkh(C.CreateFontIndirectExW(lfex)), DeleteObject) 40 | end 41 | 42 | if not ... then 43 | local font = print(CreateFontEx{ 44 | 45 | }) 46 | end 47 | -------------------------------------------------------------------------------- /winapi/groupboxclass.lua: -------------------------------------------------------------------------------- 1 | 2 | --oo/controls/groupbox: groupbox control 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.basebuttonclass' 7 | 8 | GroupBox = subclass({ 9 | __style_bitmask = bitmask{ 10 | tabstop = WS_TABSTOP, 11 | align = { 12 | left = BS_LEFT, 13 | right = BS_RIGHT, 14 | center = BS_CENTER, 15 | }, 16 | flat = BS_FLAT, 17 | }, 18 | __defaults = { 19 | --transparent = true, 20 | --window properties 21 | text = 'Group', 22 | w = 200, h = 100, 23 | }, 24 | }, BaseButton) 25 | 26 | function GroupBox:after___before_create(info, args) 27 | --BS_NOTIFY gives us focus/blur events; WS_EX_TRANSPARENT avoids incompatibility with parent having WS_CLIPCHILDREN 28 | args.style = bit.bor(args.style, BS_GROUPBOX, BS_NOTIFY) 29 | args.style_ex = bit.bor(args.style_ex, WS_EX_TRANSPARENT) 30 | end 31 | 32 | --showcase 33 | if not ... then 34 | require'winapi.showcase' 35 | local window = ShowcaseWindow{w=300,h=300} 36 | local gb1 = GroupBox{parent = window, style = {align = 'right', flat = true}} 37 | local gb2 = GroupBox{parent = window, style = {}, y = 100} 38 | function gb1:on_focus() print'gb1 focused' end 39 | function gb2:on_focus() print'gb2 focused' end 40 | MessageLoop() 41 | end 42 | -------------------------------------------------------------------------------- /winapi/groupboxclass.md: -------------------------------------------------------------------------------- 1 | --- 2 | tagline: group boxes 3 | --- 4 | 5 | ## `require'winapi.groupboxclass'` 6 | 7 | This module implements the `GroupBox` class for creating group boxes. 8 | 9 | ## GroupBox 10 | 11 | ### Hierarchy 12 | 13 | * [VObject][winapi.vobject] 14 | * [BaseWindow][winapi.basewindowclass] 15 | * [Control][winapi.controlclass] 16 | * [BaseButton][winapi.basebuttonclass] 17 | * GroupBox 18 | 19 | ### Initial fields and properties 20 | 21 | __NOTE:__ in the table below `i` means initial field, `r` means property 22 | which can be read, `w` means property which can be set. 23 | 24 | ----------------------- -------- ----------------------------------------- ----------------------- --------------------- 25 | __field/property__ __irw__ __description__ __default__ __reference__ 26 | text irw group box's title 'Group' Get/SetWindowText 27 | w, h irw size 200, 100 28 | tabstop irw focus on tab false WS_TABSTOP 29 | align irw 'left', 'right', 'center' 'left' BS_LEFT/RIGHT/CENTER 30 | flat irw flat appearance false BS_FLAT 31 | ----------------------- -------- ----------------------------------------- ----------------------- --------------------- 32 | -------------------------------------------------------------------------------- /winapi/handlelist.lua: -------------------------------------------------------------------------------- 1 | 2 | --oo/abstract/handlelist: handle to Lua object mapping 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.vobject' 7 | 8 | HandleList = class(VObject) 9 | 10 | function HandleList:__init(handle_property) 11 | self.handle_property = handle_property 12 | self.items = {} --{ptonumber(handler) = object}; object is also pinned (table is not weak) 13 | end 14 | 15 | function HandleList:add(obj) 16 | self.items[ptonumber(obj[self.handle_property])] = obj 17 | end 18 | 19 | function HandleList:remove(obj) 20 | self.items[ptonumber(obj[self.handle_property])] = nil 21 | end 22 | 23 | function HandleList:find(handle) 24 | return self.items[ptonumber(handle)] 25 | end 26 | 27 | -------------------------------------------------------------------------------- /winapi/icon.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/resources/icon: icon resources 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.winuser' 7 | 8 | ffi.cdef[[ 9 | HICON LoadIconW( 10 | HINSTANCE hInstance, 11 | LPCWSTR lpIconName); 12 | 13 | BOOL DestroyIcon(HICON hIcon); 14 | 15 | typedef struct _ICONINFO { 16 | BOOL fIcon; 17 | DWORD xHotspot; 18 | DWORD yHotspot; 19 | HBITMAP hbmMask; 20 | HBITMAP hbmColor; 21 | } ICONINFO; 22 | typedef ICONINFO *PICONINFO; 23 | 24 | HICON CreateIconIndirect(PICONINFO piconinfo); 25 | ]] 26 | 27 | IDI_APPLICATION = 32512 28 | IDI_INFORMATION = 32516 29 | IDI_QUESTION = 32514 30 | IDI_WARNING = 32515 31 | IDI_ERROR = 32513 32 | IDI_WINLOGO = 32517 --same as IDI_APPLICATION in XP 33 | IDI_SHIELD = 32518 --not found in XP 34 | 35 | function LoadIconFromInstance(hInstance, name) 36 | if not name then hInstance, name = nil, hInstance end --hInstance is optional 37 | return own(checkh(C.LoadIconW(hInstance, 38 | ffi.cast('LPCWSTR', wcs(MAKEINTRESOURCE(flags(name)))))), DestroyIcon) 39 | end 40 | 41 | function DestroyIcon(hicon) 42 | checknz(C.DestroyIcon(hicon)) 43 | end 44 | 45 | ICONINFO = types.ICONINFO 46 | 47 | function CreateIconIndirect(info) 48 | info = ICONINFO(info) 49 | return checkh(C.CreateIconIndirect(info)) 50 | end 51 | 52 | --WM_SETICON flags 53 | ICON_BIG = 1 54 | ICON_SMALL = 0 55 | 56 | if not ... then 57 | print(LoadIconFromInstance(IDI_APPLICATION)) 58 | print(LoadIconFromInstance(IDI_INFORMATION)) 59 | end 60 | 61 | -------------------------------------------------------------------------------- /winapi/idataobject.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/ole/dataobject: IDataObject interface 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.ole' 7 | require'winapi.ienumformatetc' 8 | 9 | ffi.cdef[[ 10 | typedef void *HMETAFILEPICT; 11 | 12 | typedef struct tagSTGMEDIUM { 13 | DWORD tymed; 14 | union { 15 | HBITMAP hBitmap; 16 | HMETAFILEPICT hMetaFilePict; 17 | HENHMETAFILE hEnhMetaFile; 18 | HGLOBAL hGlobal; 19 | LPOLESTR lpszFileName; 20 | IStream *pstm; 21 | IStorage *pstg; 22 | }; 23 | IUnknown *pUnkForRelease; 24 | } uSTGMEDIUM; 25 | 26 | typedef uSTGMEDIUM STGMEDIUM; 27 | typedef STGMEDIUM* LPSTGMEDIUM; 28 | ]] 29 | 30 | ffi.cdef[[ 31 | typedef struct IDataObject IDataObject; 32 | typedef IDataObject *LPDATAOBJECT; 33 | 34 | typedef struct IDataObjectVtbl { 35 | 36 | HRESULT ( __stdcall *QueryInterface )( 37 | IDataObject * This, 38 | REFIID riid, 39 | void **ppvObject); 40 | 41 | ULONG ( __stdcall *AddRef )( 42 | IDataObject * This); 43 | 44 | ULONG ( __stdcall *Release )( 45 | IDataObject * This); 46 | 47 | HRESULT ( __stdcall *GetData )( 48 | IDataObject * This, 49 | FORMATETC *pformatetcIn, 50 | STGMEDIUM *pmedium); 51 | 52 | HRESULT ( __stdcall *GetDataHere )( 53 | IDataObject * This, 54 | FORMATETC *pformatetc, 55 | STGMEDIUM *pmedium); 56 | 57 | HRESULT ( __stdcall *QueryGetData )( 58 | IDataObject * This, 59 | FORMATETC *pformatetc); 60 | 61 | HRESULT ( __stdcall *GetCanonicalFormatEtc )( 62 | IDataObject * This, 63 | FORMATETC *pformatectIn, 64 | FORMATETC *pformatetcOut); 65 | 66 | HRESULT ( __stdcall *SetData )( 67 | IDataObject * This, 68 | FORMATETC *pformatetc, 69 | STGMEDIUM *pmedium, 70 | BOOL fRelease); 71 | 72 | HRESULT ( __stdcall *EnumFormatEtc )( 73 | IDataObject * This, 74 | DWORD dwDirection, 75 | IEnumFORMATETC **ppenumFormatEtc); 76 | 77 | HRESULT ( __stdcall *DAdvise )( 78 | IDataObject * This, 79 | FORMATETC *pformatetc, 80 | DWORD advf, 81 | IAdviseSink *pAdvSink, 82 | DWORD *pdwConnection); 83 | 84 | HRESULT ( __stdcall *DUnadvise )( 85 | IDataObject * This, 86 | DWORD dwConnection); 87 | 88 | HRESULT ( __stdcall *EnumDAdvise )( 89 | IDataObject * This, 90 | IEnumSTATDATA **ppenumAdvise); 91 | 92 | } IDataObjectVtbl; 93 | 94 | struct IDataObject { 95 | struct IDataObjectVtbl *lpVtbl; 96 | }; 97 | ]] 98 | 99 | -------------------------------------------------------------------------------- /winapi/ienumformatetc.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/ole/enumformatetc: IEnumFormatETC interface 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.ole' 7 | 8 | ffi.cdef[[ 9 | typedef WORD CLIPFORMAT; 10 | 11 | typedef struct tagDVTARGETDEVICE { 12 | DWORD tdSize; 13 | WORD tdDriverNameOffset; 14 | WORD tdDeviceNameOffset; 15 | WORD tdPortNameOffset; 16 | WORD tdExtDevmodeOffset; 17 | BYTE tdData[1]; 18 | } DVTARGETDEVICE; 19 | 20 | typedef struct tagFORMATETC { 21 | CLIPFORMAT cfFormat; 22 | DVTARGETDEVICE *ptd; 23 | DWORD dwAspect; 24 | LONG lindex; 25 | DWORD tymed; 26 | } FORMATETC; 27 | 28 | typedef struct tagFORMATETC *LPFORMATETC; 29 | 30 | typedef struct IEnumFORMATETC IEnumFORMATETC; 31 | 32 | typedef struct IEnumFORMATETCVtbl { 33 | 34 | HRESULT ( __stdcall *QueryInterface )( 35 | IEnumFORMATETC * This, 36 | REFIID riid, 37 | void **ppvObject); 38 | 39 | ULONG ( __stdcall *AddRef )( 40 | IEnumFORMATETC * This); 41 | 42 | ULONG ( __stdcall *Release )( 43 | IEnumFORMATETC * This); 44 | 45 | HRESULT ( __stdcall *Next )( 46 | IEnumFORMATETC * This, 47 | ULONG celt, 48 | FORMATETC *rgelt, 49 | ULONG *pceltFetched); 50 | 51 | HRESULT ( __stdcall *Skip )( 52 | IEnumFORMATETC * This, 53 | ULONG celt); 54 | 55 | HRESULT ( __stdcall *Reset )( 56 | IEnumFORMATETC * This); 57 | 58 | HRESULT ( __stdcall *Clone )( 59 | IEnumFORMATETC * This, 60 | IEnumFORMATETC **ppenum); 61 | 62 | } IEnumFORMATETCVtbl; 63 | 64 | struct IEnumFORMATETC { 65 | struct IEnumFORMATETCVtbl *lpVtbl; 66 | }; 67 | ]] 68 | 69 | -------------------------------------------------------------------------------- /winapi/imagelistclass.lua: -------------------------------------------------------------------------------- 1 | 2 | --oo/resources/imagelist: image lists 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.itemlist' 7 | require'winapi.handlelist' 8 | require'winapi.imagelist' 9 | 10 | ImageLists = HandleList'himl' 11 | 12 | ImageList = subclass({ 13 | __defaults = { 14 | w=32, h=32, 15 | initial_size = 0, --if > 0 you'll have to use set() instead of add() 16 | grow_size = 1, --if > 1 you'll have to use set() instead of add() 17 | }, 18 | __flags_bitmask = bitmask{ 19 | masked = ILC_MASK, 20 | colors = { 21 | default = ILC_COLOR, 22 | ddb = ILC_COLORDDB, 23 | ['16bit'] = ILC_COLOR4, 24 | ['256bit'] = ILC_COLOR8, 25 | ['16bit'] = ILC_COLOR16, 26 | ['24bit'] = ILC_COLOR24, 27 | ['32bit'] = ILC_COLOR32, 28 | }, 29 | mirror = { 30 | none = 0, 31 | all = ILC_MIRROR, 32 | item = ILC_PERITEMMIRROR, 33 | }, 34 | preserve_size = ILC_ORIGINALSIZE, --vista+ 35 | }, 36 | }, ItemList) 37 | 38 | function ImageList:__init(t) 39 | if ffi.istype('HIMAGELIST', t) then 40 | self.himl = t 41 | else 42 | self.himl = ImageList_Create{ 43 | w = t.w or t[1], h = t.h or t[2], 44 | flags = self.__flags_bitmask:set(bit.bor(ILC_COLOR32, ILC_MASK), t), 45 | initial_size = t.initial_size or self.__defaults.initial_size, 46 | grow_size = t.grow_size or self.__defaults.grow_size, 47 | } 48 | if t.bk_color then self.bk_color = t.bk_color end 49 | end 50 | ImageLists:add(self) 51 | end 52 | function ImageList:destroy() 53 | ImageList_Destroy(self.himl) 54 | ImageLists:remove(self) 55 | self.himl = nil 56 | end 57 | 58 | function ImageList:set(i,t) 59 | if t.icon then 60 | ImageList_ReplaceIcon(self.himl, i, t.icon) 61 | elseif t.transparent_color then --there's no ImageList_ReplaceMasked 62 | ImageList_AddMasked(self.himl, t.image, t.transparent_color) 63 | ImageList_Copy(self.himl, i, self.count, ILCF_MOVE) 64 | ImageList_Remove(self.himl, self.count) 65 | else 66 | ImageList_Replace(self.himl, i, t.image, t.mask_image) 67 | end 68 | end 69 | 70 | function ImageList:move(to, from) 71 | if to == from then return end 72 | if to < from then 73 | for k=from,to+1,-1 do 74 | ImageList_Copy(self.himl, k, k-1, ILCF_SWAP) 75 | end 76 | else 77 | for k=to,from-1 do 78 | ImageList_Copy(self.himl, k, k+1, ILCF_SWAP) 79 | end 80 | end 81 | end 82 | 83 | function ImageList:add(i,t) --mask is an image or a color number 84 | if not t then i,t = nil,i end 85 | if t.icon then 86 | ImageList_AddIcon(self.himl, t.icon) 87 | elseif t.transparent_color then 88 | ImageList_AddMasked(self.himl, t.image, t.transparent_color) 89 | else 90 | ImageList_Add(self.himl, t.image, t.mask_image) 91 | end 92 | if i then self:move(self.count, i) end 93 | end 94 | 95 | function ImageList:remove(i) 96 | return ImageList_Remove(self.himl, i) 97 | end 98 | 99 | function ImageList:get(i, ILD) 100 | return {icon = ImageList_GetIcon(self.himl, i, ILD)} 101 | end 102 | 103 | function ImageList:clear() return 104 | ImageList_RemoveAll(self.himl) 105 | end 106 | 107 | function ImageList:get_count() 108 | return ImageList_GetImageCount(self.himl) 109 | end 110 | 111 | function ImageList:set_count(count) 112 | return ImageList_SetImageCount(self.himl, count) 113 | end 114 | 115 | function ImageList:get_bk_color() return ImageList_GetBkColor(self.himl) end 116 | function ImageList:set_bk_color(color) ImageList_SetBkColor(self.himl, color) end 117 | 118 | function ImageList:set_overlay(i, ioverlay) 119 | return ImageList_SetOverlayImage(self.himl, i, ioverlay) 120 | end 121 | 122 | function ImageList:get_size() 123 | local w,h = ImageList_GetIconSize(self.himl) 124 | return {w=w,h=h} 125 | end 126 | function ImageList:set_size(size) 127 | ImageList_SetIconSize(self.himl, size.w, size.h) 128 | end 129 | 130 | function ImageList:draw(i, dc, x, y, IDL) 131 | ImageList_Draw(self.himl, i, dc, x, y, IDL) 132 | end 133 | 134 | 135 | --showcase 136 | 137 | if not ... then 138 | require'winapi.showcase' 139 | require'winapi.icon' 140 | require'winapi.resource' 141 | local window = ShowcaseWindow{w=300,h=200} 142 | local m = ImageList{w=32,h=32,colors='32bit'} 143 | --m.bk_color = 234234 144 | m:add{icon = LoadIconFromInstance(IDI_WARNING)} 145 | m:add{icon = LoadIconFromInstance(IDI_INFORMATION)} 146 | m:add(2, {icon = LoadIconFromInstance(IDI_ERROR)}) 147 | m:set(3, {icon = LoadIconFromInstance(IDI_ERROR)}) 148 | m.count = m.count + 1 149 | print(m.count) 150 | print(m.size) 151 | function window:WM_PAINT() 152 | local p = ffi.new'PAINTSTRUCT' 153 | local hdc = C.BeginPaint(window.hwnd, p) 154 | for i=1,m.count do 155 | m:draw(i, hdc, 50+i*34, 50, ILD_NORMAL) 156 | end 157 | C.EndPaint(window.hwnd, p) 158 | end 159 | window:invalidate() 160 | MessageLoop() 161 | m:destroy() 162 | end 163 | -------------------------------------------------------------------------------- /winapi/init.lua: -------------------------------------------------------------------------------- 1 | 2 | --binding/winapi: main winapi module 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | if not ... then require'winapi_demo'; return end 6 | 7 | setfenv(1, require'winapi.namespace') 8 | require'winapi.types' 9 | require'winapi.util' 10 | require'winapi.struct' 11 | require'winapi.wcs' 12 | require'winapi.bitmask' 13 | return _M 14 | -------------------------------------------------------------------------------- /winapi/itemlist.lua: -------------------------------------------------------------------------------- 1 | 2 | --oo/abstract/itemlist: base class for lists of objects 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.vobject' 7 | 8 | ItemList = class(VObject) 9 | 10 | function ItemList:__init(window, items) --stub 11 | self.window = window 12 | self.hwnd = window.hwnd 13 | self:add_items(items) 14 | end 15 | 16 | function ItemList:add_items(items) 17 | if not items then return end 18 | for i=1,#items do self:add(items[i]) end 19 | end 20 | 21 | function ItemList:add(i, item) 22 | if not item then i,item = nil,i end --i is optional 23 | end 24 | 25 | function ItemList:remove(i) 26 | end 27 | 28 | function ItemList:set(i, item) 29 | end 30 | 31 | function ItemList:get(i) 32 | end 33 | 34 | function ItemList:get_count() 35 | end 36 | 37 | local function remove_all(self) 38 | for i=self.count,1,-1 do 39 | self:remove(i) 40 | end 41 | end 42 | function ItemList:clear() --default impl. in case there's no API for it 43 | self.window:batch_update(remove_all, self) 44 | end 45 | -------------------------------------------------------------------------------- /winapi/labelclass.lua: -------------------------------------------------------------------------------- 1 | 2 | --oo/controls/label: standard label control 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.controlclass' 7 | require'winapi.static' 8 | 9 | Label = subclass({ 10 | __style_bitmask = bitmask{ 11 | align = { 12 | left = SS_LEFT, 13 | center = SS_CENTER, 14 | right = SS_RIGHT, 15 | simple = SS_SIMPLE, 16 | left_nowrap = SS_LEFTNOWORDWRAP, 17 | }, 18 | accelerator_prefix = negate(SS_NOPREFIX), --don't do "&" character translation 19 | events = SS_NOTIFY, --send notifications 20 | owner_draw = SS_OWNERDRAW, 21 | simulate_edit = SS_EDITCONTROL, 22 | ellipsis = { 23 | [false] = 0, 24 | char = SS_ENDELLIPSIS, 25 | path = SS_PATHELLIPSIS, 26 | word = SS_WORDELLIPSIS, 27 | }, 28 | }, 29 | __defaults = { 30 | text = 'Text', 31 | w = 100, h = 21, 32 | events = true, 33 | accelerator_prefix = true, 34 | }, 35 | __init_properties = {}, 36 | __wm_command_handler_names = index{ 37 | on_click = STN_CLICKED, 38 | on_double_click = STN_DBLCLK, 39 | on_enable = STN_ENABLE, 40 | on_disable = STN_DISABLE, 41 | }, 42 | }, Control) 43 | 44 | function Label:after___before_create(info, args) 45 | args.text = info.text 46 | args.class = WC_STATIC 47 | end 48 | 49 | --showcase 50 | 51 | if not ... then 52 | require'winapi.showcase' 53 | local window = ShowcaseWindow{w=300,h=200} 54 | local s1 = Label{ 55 | parent = window, 56 | x = 10, y = 10, w = 100, h = 60, 57 | text = 'Hi there my sweet lemon drops!', 58 | align = 'right', 59 | } 60 | function s1:on_click() 61 | print'clicked' 62 | end 63 | MessageLoop() 64 | end 65 | 66 | -------------------------------------------------------------------------------- /winapi/labelclass.md: -------------------------------------------------------------------------------- 1 | --- 2 | tagline: text labels 3 | --- 4 | 5 | ## `require'winapi.labelclass'` 6 | 7 | This module implements the `Label` class for creating text labels. 8 | 9 | ## Label 10 | 11 | ### Hierarchy 12 | 13 | * [VObject][winapi.vobject] 14 | * [BaseWindow][winapi.basewindowclass] 15 | * [Control][winapi.controlclass] 16 | * Label 17 | 18 | ### Initial fields and properties 19 | 20 | __NOTE:__ in the table below `i` means initial field, `r` means property 21 | which can be read, `w` means property which can be set. 22 | 23 | ----------------------- -------- ----------------------------------------- -------------- --------------------- 24 | __field/property__ __irw__ __description__ __default__ __reference__ 25 | 26 | align irw 'left', 'center', 'right', 'left' SS_LEFT, SS_CENTER, 27 | 'simple', 'left_nowrap' SS_RIGHT, SS_SIMPLE, 28 | SS_LEFTNOWORDWRAP 29 | 30 | accelerator_prefix irw don't do "&" character translation true SS_NOPREFIX 31 | 32 | events irw enable events true SS_NOTIFY 33 | 34 | owner_draw irw owner drawn false SS_OWNERDRAW 35 | 36 | simulate_edit irw display text like an edit would false SS_EDITCONTROL 37 | 38 | ellipsis false, 'char', 'path', 'word' false SS_ENDELLIPSIS, 39 | SS_PATHELLIPSIS, 40 | SS_WORDELLIPSIS 41 | 42 | 43 | text irw the text to display 'Text' Get/SetWindowText 44 | 45 | w, h irw size 100, 21 46 | ----------------------- -------- ----------------------------------------- -------------- --------------------- 47 | 48 | ### Events 49 | 50 | -------------------------------- -------------------------------------------- ---------------------- 51 | __event__ __description__ __reference__ 52 | on_click() clicked STN_CLICKED 53 | on_double_click() double-clicked STN_DBLCLK 54 | on_enable() was enabled STN_ENABLE 55 | on_disable() was disabled STN_DISABLE 56 | -------------------------------- -------------------------------------------- --------------------- 57 | -------------------------------------------------------------------------------- /winapi/listboxclass.lua: -------------------------------------------------------------------------------- 1 | 2 | --oo/controls/listbox: standard listbox control 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.controlclass' 7 | require'winapi.itemlist' 8 | require'winapi.listbox' 9 | 10 | LBItemList = class(ItemList) 11 | 12 | function LBItemList:add(i,s) --returns index 13 | if not s then i,s = nil,i end 14 | if i then 15 | return ListBox_InsertString(self.hwnd, i, s) 16 | else 17 | return ListBox_AddString(self.hwnd, s) 18 | end 19 | end 20 | 21 | function LBItemList:remove(i) --returns count 22 | return ListBox_DeleteString(self.hwnd, i) 23 | end 24 | 25 | local function setitem(hwnd, i, s) 26 | ListBox_InsertString(hwnd, i, s) 27 | ListBox_DeleteString(hwnd, i+1) 28 | end 29 | function LBItemList:set(i,s) --there's no ListBox_SetString so we have to improvize 30 | self.window:batch_update(setitem, self.hwnd, i, s) 31 | end 32 | 33 | function LBItemList:get(i) 34 | return ListBox_GetString(self.hwnd, i) 35 | end 36 | 37 | function LBItemList:get_count() 38 | return ListBox_GetCount(self.hwnd) 39 | end 40 | 41 | function LBItemList:select(i) ListBox_SetCurSel(self.hwnd, i) end 42 | function LBItemList:get_selected_index() return ListBox_GetCurSel(self.hwnd) end 43 | function LBItemList:get_selected() 44 | local si = self:get_selected_index() 45 | return si and self:get(si) 46 | end 47 | 48 | --for ownerdraw lists only 49 | function LBItemList:set_height(i, h) ListBox_SetItemHeight(self.hwnd, i, h) end 50 | function LBItemList:get_height(i) return ListBox_GetItemHeight(self.hwnd, i) end 51 | 52 | 53 | ListBox = subclass({ 54 | __style_bitmask = bitmask{ 55 | border = WS_BORDER, 56 | sort = LBS_SORT, 57 | select = { 58 | single = 0, 59 | multiple = LBS_MULTIPLESEL, 60 | extended = LBS_EXTENDEDSEL, 61 | }, 62 | tabstops = LBS_USETABSTOPS, 63 | free_height = LBS_NOINTEGRALHEIGHT, 64 | multicolumn = LBS_MULTICOLUMN, 65 | vscroll = WS_VSCROLL, 66 | hscroll = WS_HSCROLL, 67 | always_show_scrollbars = LBS_DISABLENOSCROLL, 68 | allow_select = negate(LBS_NOSEL), 69 | }, 70 | __style_ex_bitmask = bitmask{ 71 | client_edge = WS_EX_CLIENTEDGE, 72 | }, 73 | __defaults = { 74 | client_edge = true, 75 | free_height = true, 76 | vscroll = true, 77 | hscroll = true, 78 | always_show_scrollbars = true, --if disabled, either vscroll or hscroll must be disabled too! 79 | --window properties 80 | w = 100, h = 100, 81 | }, 82 | __init_properties = {'sort', 'hextent'}, --LBS_SORT is not set initially. why? 83 | __wm_command_handler_names = index{ 84 | on_memory_error = LBN_ERRSPACE, 85 | on_select = LBN_SELCHANGE, 86 | on_double_click = LBN_DBLCLK, 87 | on_cancel = LBN_SELCANCEL, 88 | on_focus = LBN_SETFOCUS, 89 | on_blur = LBN_KILLFOCUS, 90 | }, 91 | }, Control) 92 | 93 | function ListBox:after___before_create(info, args) 94 | args.class = WC_LISTBOX 95 | args.style = bit.bor(args.style, LBS_NOTIFY, LBS_HASSTRINGS, LBS_WANTKEYBOARDINPUT) 96 | args.text = info.text 97 | end 98 | 99 | function ListBox:after___init(info) 100 | self.items = LBItemList(self) 101 | end 102 | 103 | function ListBox:get_hextent() 104 | return ListBox_GetHorizontalExtent(self.hwnd) 105 | end 106 | 107 | function ListBox:set_hextent(width) 108 | ListBox_SetHorizontalExtent(self.hwnd, width) 109 | end 110 | 111 | 112 | if not ... then 113 | require'winapi.showcase' 114 | local window = ShowcaseWindow{w=300,h=200} 115 | local lb = ListBox{parent = window, x = 10, y = 10, hextent = 120} 116 | for i = 1,100 do 117 | lb.items:add('xxxxxxxxxx test '..i) 118 | end 119 | MessageLoop() 120 | end 121 | -------------------------------------------------------------------------------- /winapi/listboxclass.md: -------------------------------------------------------------------------------- 1 | --- 2 | tagline: list boxes 3 | --- 4 | 5 | ## `require'winapi.listboxclass'` 6 | 7 | This module implements the `ListBox` class for creating list boxes. 8 | 9 | ## ListBox 10 | 11 | ### Hierarchy 12 | 13 | * [VObject][winapi.vobject] 14 | * [BaseWindow][winapi.basewindowclass] 15 | * [Control][winapi.controlclass] 16 | * ListBox 17 | 18 | ### Initial fields and properties 19 | 20 | __NOTE:__ in the table below `i` means initial field, `r` means property 21 | which can be read, `w` means property which can be set. 22 | 23 | ----------------------- -------- ----------------------------------------- -------------- --------------------- 24 | __field/property__ __irw__ __description__ __default__ __reference__ 25 | w, h irw size 100, 100 26 | border irw TODO false WS_BORDER 27 | sort irw sort items false LBS_SORT 28 | select irw 'single', 'multiple', 'extended' 'single' LBS_MULTIPLE/EXTENDEDSEL 29 | tabstops irw focus on tab false LBS_USETABSTOPS 30 | free_height irw TODO true LBS_NOINTEGRALHEIGHT 31 | multicolumn irw TODO false LBS_MULTICOLUMN 32 | vscroll irw show vertical scrollbar true WS_VSCROLL 33 | hscroll irw show horizontal scrollbar true WS_HSCROLL 34 | always_show_scrollbars irw always show scrollbars true LBS_DISABLENOSCROLL 35 | hextent irw horizontal extent 0 LB_GET/SETHORIZONTALEXTENT 36 | allow_select irw allow select true LBS_NOSEL 37 | client_edge irw bordered true WS_EX_CLIENTEDGE 38 | ----------------------- -------- ----------------------------------------- -------------- --------------------- 39 | 40 | ### Events 41 | 42 | -------------------------------- -------------------------------------------- ---------------------- 43 | __event__ __description__ __reference__ 44 | on_memory_error() TODO LBN_ERRSPACE 45 | on_select() TODO LBN_SELCHANGE 46 | on_double_click() TODO LBN_DBLCLK 47 | on_cancel() TODO LBN_SELCANCEL 48 | on_focus() TODO LBN_SETFOCUS 49 | on_blur() TODO LBN_KILLFOCUS 50 | -------------------------------- -------------------------------------------- --------------------- 51 | -------------------------------------------------------------------------------- /winapi/logfonttype.lua: -------------------------------------------------------------------------------- 1 | 2 | --types/logfonttype: LOGFONTW type 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | --It was separated from winapi.font because it's needed by cairo_win32_h.lua. 6 | 7 | setfenv(1, require'winapi.namespace') 8 | require'winapi.types' 9 | 10 | local ffi = require'ffi' 11 | ffi.cdef[[ 12 | typedef struct tagLOGFONTW 13 | { 14 | LONG height; 15 | LONG width; 16 | LONG escapement; 17 | LONG orientation; 18 | LONG lfWeight; 19 | bool italic; 20 | bool underline; 21 | bool strikeout; 22 | BYTE lfCharSet; 23 | BYTE lfOutPrecision; 24 | BYTE lfClipPrecision; 25 | BYTE lfQuality; 26 | BYTE lfPitchAndFamily; 27 | WCHAR lfFaceName[32]; 28 | } LOGFONTW, *PLOGFONTW, *NPLOGFONTW, *LPLOGFONTW; 29 | ]] 30 | -------------------------------------------------------------------------------- /winapi/memory.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/system/memory: Memory Management API 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.winnt' 7 | 8 | -- Global Memory Flags 9 | GMEM_FIXED = 0x0000 10 | GMEM_MOVEABLE = 0x0002 11 | GMEM_NOCOMPACT = 0x0010 12 | GMEM_NODISCARD = 0x0020 13 | GMEM_ZEROINIT = 0x0040 14 | GMEM_MODIFY = 0x0080 15 | GMEM_DISCARDABLE = 0x0100 16 | GMEM_NOT_BANKED = 0x1000 17 | GMEM_SHARE = 0x2000 18 | GMEM_DDESHARE = 0x2000 19 | GMEM_NOTIFY = 0x4000 20 | GMEM_LOWER = GMEM_NOT_BANKED 21 | GMEM_VALID_FLAGS = 0x7F72 22 | GMEM_INVALID_HANDLE = 0x8000 23 | GHND = bit.bor(GMEM_MOVEABLE, GMEM_ZEROINIT) 24 | GPTR = bit.bor(GMEM_FIXED, GMEM_ZEROINIT) 25 | -- Flags returned by GlobalFlags (in addition to GMEM_DISCARDABLE) 26 | GMEM_DISCARDED = 0x4000 27 | GMEM_LOCKCOUNT = 0x00FF 28 | 29 | ffi.cdef[[ 30 | LPVOID GlobalLock(HGLOBAL hMem); 31 | BOOL GlobalUnlock(HGLOBAL hMem); 32 | SIZE_T GlobalSize(HGLOBAL hMem); 33 | HGLOBAL GlobalAlloc(UINT uFlags, SIZE_T dwBytes); 34 | HGLOBAL GlobalFree(HGLOBAL hMem); 35 | 36 | LPVOID VirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect); 37 | BOOL VirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect); 38 | BOOL VirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType); 39 | 40 | HANDLE GetProcessHeap(void); 41 | HANDLE HeapCreate(DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaximumSize); 42 | BOOL HeapDestroy(HANDLE hHeap); 43 | LPVOID HeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes); 44 | LPVOID HeapReAlloc(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem, SIZE_T dwBytes); 45 | BOOL HeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem); 46 | BOOL HeapValidate(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem); 47 | ]] 48 | 49 | function GlobalLock(hmem) 50 | return ptr(ffi.C.GlobalLock(hmem)) 51 | end 52 | 53 | function GlobalUnlock(hmem) 54 | return callnz2(ffi.C.GlobalUnlock, hmem) 55 | end 56 | 57 | function GlobalSize(hmem) 58 | return checknz(ffi.C.GlobalSize(hmem)) 59 | end 60 | 61 | function GlobalAlloc(GMEM, sz) 62 | return checkh(ffi.C.GlobalAlloc(flags(GMEM), sz)) 63 | end 64 | 65 | function GlobalFree(h) 66 | return checknz(ffi.C.GlobalFree(h) == nil and 1 or 0) 67 | end 68 | 69 | MEM_COMMIT = 0x00001000 70 | MEM_RESERVE = 0x00002000 71 | MEM_DECOMMIT = 0x00004000 72 | MEM_RELEASE = 0x00008000 73 | MEM_FREE = 0x00010000 74 | MEM_PRIVATE = 0x00020000 75 | MEM_MAPPED = 0x00040000 76 | MEM_RESET = 0x00080000 77 | MEM_TOP_DOWN = 0x00100000 78 | MEM_WRITE_WATCH = 0x00200000 79 | MEM_PHYSICAL = 0x00400000 80 | MEM_ROTATE = 0x00800000 81 | MEM_LARGE_PAGES = 0x20000000 82 | MEM_4MB_PAGES = 0x80000000 83 | 84 | MEM_IMAGE = SEC_IMAGE 85 | 86 | WRITE_WATCH_FLAG_RESET = 0x01 87 | 88 | function VirtualAlloc(addr, size, MEM, PAGE) 89 | return checkh(C.VirtualAlloc(addr, size, flags(MEM), flags(PAGE))) 90 | end 91 | 92 | function VirtualProtect(addr, size, newprotect, oldprotect) 93 | oldprotect = oldprotect or ffi.new'DWORD[1]' 94 | checknz(C.VirtualProtect(addr, size, flags(newprotect), oldprotect)) 95 | return oldprotect 96 | end 97 | 98 | MEM_DECOMMIT = 0x4000 99 | MEM_RELEASE = 0x8000 --size must be 0 with this flag 100 | 101 | function VirtualFree(addr, size, freetype) 102 | checknz(C.VirtualFree(addr, size or 0, flags(freetype or MEM_RELEASE))) 103 | end 104 | 105 | HEAP_NO_SERIALIZE = 0x00000001 106 | HEAP_GENERATE_EXCEPTIONS = 0x00000004 107 | HEAP_ZERO_MEMORY = 0x00000008 108 | HEAP_REALLOC_IN_PLACE_ONLY = 0x00000010 109 | HEAP_CREATE_ENABLE_EXECUTE = 0x00040000 110 | 111 | GetProcessHeap = C.GetProcessHeap 112 | 113 | function HeapCreate(HEAP, initsz, maxsz) 114 | return checkh(C.HeapCreate(flags(HEAP), initsz or 0, maxsz or 0)) 115 | end 116 | 117 | function HeapDestroy(heap) 118 | checknz(C.HeapDestroy(heap)) 119 | end 120 | 121 | function HeapAlloc(heap, HEAP, bytes) 122 | return checkh(C.HeapAlloc(heap, flags(HEAP), bytes)) 123 | end 124 | 125 | function HeapReAlloc(heap, HEAP, mem, bytes) 126 | return checkh(C.HeapReAlloc(heap, flags(HEAP), mem, bytes)) 127 | end 128 | 129 | function HeapFree(heap, HEAP, mem) 130 | return checknz(C.HeapFree(heap, flags(HEAP), mem)) 131 | end 132 | 133 | function HeapValidate(heap, HEAP, mem) 134 | return checknz(C.HeapValidate(heap, flags(HEAP), mem)) 135 | end 136 | 137 | -------------------------------------------------------------------------------- /winapi/messagebox.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/controls/messagebox: standard message box dialog 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.winuser' 7 | require'winapi.comctl' 8 | 9 | ffi.cdef[[ 10 | int MessageBoxExW( 11 | HWND hWnd, 12 | LPCWSTR lpText, 13 | LPCWSTR lpCaption, 14 | UINT uType, 15 | WORD wLanguageId); 16 | 17 | LONG GetDialogBaseUnits(); 18 | ]] 19 | 20 | MB_OK = 0x00000000 21 | MB_OKCANCEL = 0x00000001 22 | MB_ABORTRETRYIGNORE = 0x00000002 23 | MB_YESNOCANCEL = 0x00000003 24 | MB_YESNO = 0x00000004 25 | MB_RETRYCANCEL = 0x00000005 26 | MB_CANCELTRYCONTINUE = 0x00000006 27 | MB_ICONHAND = 0x00000010 28 | MB_ICONQUESTION = 0x00000020 29 | MB_ICONEXCLAMATION = 0x00000030 30 | MB_ICONASTERISK = 0x00000040 31 | MB_USERICON = 0x00000080 32 | MB_ICONWARNING = MB_ICONEXCLAMATION 33 | MB_ICONERROR = MB_ICONHAND 34 | MB_ICONINFORMATION = MB_ICONASTERISK 35 | MB_ICONSTOP = MB_ICONHAND 36 | MB_DEFBUTTON1 = 0x00000000 37 | MB_DEFBUTTON2 = 0x00000100 38 | MB_DEFBUTTON3 = 0x00000200 39 | MB_DEFBUTTON4 = 0x00000300 40 | MB_APPLMODAL = 0x00000000 41 | MB_SYSTEMMODAL = 0x00001000 42 | MB_TASKMODAL = 0x00002000 43 | MB_HELP = 0x00004000 44 | MB_NOFOCUS = 0x00008000 45 | MB_SETFOREGROUND = 0x00010000 46 | MB_DEFAULT_DESKTOP_ONLY = 0x00020000 47 | MB_TOPMOST = 0x00040000 48 | MB_RIGHT = 0x00080000 49 | MB_RTLREADING = 0x00100000 50 | MB_SERVICE_NOTIFICATION = 0x00200000 51 | MB_SERVICE_NOTIFICATION_NT3X = 0x00040000 52 | MB_TYPEMASK = 0x0000000F 53 | MB_ICONMASK = 0x000000F0 54 | MB_DEFMASK = 0x00000F00 55 | MB_MODEMASK = 0x00003000 56 | MB_MISCMASK = 0x0000C000 57 | 58 | IDOK = 1 59 | IDCANCEL = 2 60 | IDABORT = 3 61 | IDRETRY = 4 62 | IDIGNORE = 5 63 | IDYES = 6 64 | IDNO = 7 65 | IDCLOSE = 8 66 | IDHELP = 9 67 | IDTRYAGAIN = 10 68 | IDCONTINUE = 11 69 | IDTIMEOUT = 32000 70 | 71 | function MessageBox(text, title, MB, parent, langid) 72 | return checknz(C.MessageBoxExW(parent, wcs(text), wcs(title), flags(MB), langid or 0)) 73 | end 74 | 75 | function GetDialogBaseUnits() 76 | local long = C.GetDialogBaseUnits() 77 | return bit.band(long, 0xFFFF), bit.rshift(long, 16) 78 | end 79 | 80 | if not ... then 81 | MessageBox('Noisy whippersnappers', 'Alert', 'MB_ICONEXCLAMATION | MB_CANCELTRYCONTINUE') 82 | end 83 | -------------------------------------------------------------------------------- /winapi/mmdevice_test.lua: -------------------------------------------------------------------------------- 1 | setfenv(1, require'winapi') 2 | require'winapi.mmdevice' 3 | 4 | local CO_E_FIRST = 0x800401F0 5 | local CO_E_LAST = 0x800401FF 6 | 7 | -- Create an instance of the enumeration interface 8 | local pEnumerator = ffi.new("IMMDeviceEnumerator *[1]") 9 | 10 | CoCreateInstance(CLSID_MMDeviceEnumerator, 11 | nil, 12 | CLSCTX_INPROC_SERVER, 13 | IID_IMMDeviceEnumerator, 14 | ffi.cast("void**",pEnumerator)); 15 | 16 | --pEnumerator = pEnumerator[0]; 17 | --print("pEnumerator: ", pEnumerator[0]) 18 | local ppDevices = ffi.new("IMMDeviceCollection *[1]") 19 | 20 | --[[ 21 | print("About To EnumAudioEndpoints") 22 | print(" pEnumerator: ", pEnumerator[0]) 23 | print(" eAll: ", ffi.C.eAll) 24 | print("DEVICE_STATE_ACTIVE: ", ffi.C.DEVICE_STATE_ACTIVE) 25 | print(" ppDevices: ", ppDevices) 26 | --]] 27 | 28 | hr = pEnumerator[0].EnumAudioEndpoints(pEnumerator[0], ffi.C.eAll, ffi.C.DEVICE_STATE_ACTIVE, ppDevices) 29 | 30 | --print("EnumAudioEndpoints: ", HRESULT_PARTS(hr)) 31 | 32 | if hr ~= 0 then 33 | return false, hr 34 | end 35 | ppDevices = ppDevices[0] 36 | 37 | -- get the count of devices 38 | local pcDevices = ffi.new("UINT[1]") 39 | hr = ppDevices:GetCount(pcDevices) 40 | 41 | --print("GetCount: ", HRESULT_PARTS(hr)) 42 | --print("Count of devices: ", pcDevices[0]) 43 | 44 | local deviceCount = pcDevices[0]; 45 | local ppDevice = ffi.new("IMMDevice * [1]") 46 | for i=0,deviceCount-1 do 47 | local hr = ppDevices:Item(i, ppDevice) 48 | --print("Item: ", ppDevice[0], HRESULT_PARTS(hr)) 49 | 50 | if hr == 0 then 51 | pEndPoint = ppDevice[0] 52 | local ppstrId = ffi.new("PWSTR [1]") 53 | hr = pEndPoint:GetId(ppstrId) 54 | local deviceID = mbs(ppstrId[0]) 55 | --print("Device ID: ", deviceID) 56 | 57 | -- open property store 58 | local pProps = ffi.new("IPropertyStore * [1]"); 59 | hr = pEndPoint:OpenPropertyStore(ffi.C.STGM_READ, pProps); 60 | --print("Open Property Store: ", HRESULT_PARTS(hr)) 61 | 62 | if hr ~= 0 then 63 | break 64 | end 65 | 66 | local pStore = pProps[0]; 67 | -- How many properties 68 | local cProps = ffi.new("DWORD[1]") 69 | hr = pStore.lpVtbl.GetCount(pStore,cProps); 70 | --print("PropertyStore:GetCount: ", cProps[0]) 71 | 72 | -- for each of the properties, get the key 73 | -- then the value 74 | local propVar = ffi.new("PROPVARIANT"); 75 | hr = pStore.lpVtbl.GetValue(pStore, PKEY_Device_FriendlyName, propVar); 76 | local value = mbs(propVar.pwszVal) 77 | print("Value: ", value) 78 | 79 | end 80 | end 81 | -------------------------------------------------------------------------------- /winapi/mmdeviceclass.lua: -------------------------------------------------------------------------------- 1 | 2 | --oo/system/mmdevice: Windows Multimedia Device API 3 | --Written by William Adams. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.mmdevice' 7 | 8 | MMDevice = {} 9 | MMDevice_mt = { 10 | __index = MMDevice, 11 | } 12 | 13 | function MMDevice.init(self, immdevice) 14 | -- open property store 15 | local pProps = ffi.new("IPropertyStore * [1]"); 16 | local hr = immdevice:OpenPropertyStore(ffi.C.STGM_READ, pProps); 17 | 18 | local cProps = ffi.new("DWORD[1]") 19 | hr = pProps[0].lpVtbl.GetCount(pProps[0],cProps); 20 | 21 | local obj = { 22 | Device = immdevice, 23 | PropertyStore = pProps[0], 24 | PropertyCount = cProps[0], 25 | } 26 | setmetatable(obj, MMDevice_mt) 27 | 28 | return obj; 29 | end 30 | 31 | function MMDevice.create(self, ...) 32 | return self:init(...); 33 | end 34 | 35 | --[[ 36 | Device Class Methods 37 | --]] 38 | -- Retrieve the audio endpoints 39 | -- use the kind to specify the flow (source, sink, filter) 40 | function MMDevice.AudioEndpoints(self, dataFlow) 41 | dataFlow = dataFlow or ffi.C.eAll; 42 | 43 | -- Create an instance of the enumeration interface 44 | local pEnumerator = ffi.new("IMMDeviceEnumerator *[1]") 45 | 46 | local hr = CoCreateInstance(CLSID_MMDeviceEnumerator, 47 | nil, 48 | CLSCTX_INPROC_SERVER, 49 | IID_IMMDeviceEnumerator, 50 | ffi.cast("void**",pEnumerator)); 51 | 52 | -- get the collection of all devices 53 | local ppDevices = ffi.new("IMMDeviceCollection *[1]") 54 | hr = pEnumerator[0].EnumAudioEndpoints(pEnumerator[0], dataFlow, ffi.C.DEVICE_STATE_ACTIVE, ppDevices) 55 | 56 | -- Find out how many devices there are 57 | local pcDevices = ffi.new("UINT[1]") 58 | local deviceCollection = ppDevices[0] 59 | hr = deviceCollection:GetCount(pcDevices) 60 | local deviceCount = pcDevices[0] 61 | 62 | local idx = -1; 63 | 64 | local function closure() 65 | idx = idx + 1; 66 | if idx >= deviceCount then 67 | return nil; 68 | end 69 | 70 | -- Construct a MMDevice instance using 71 | -- the ID of the device 72 | local ppDevice = ffi.new("IMMDevice * [1]") 73 | local hr = deviceCollection:Item(idx, ppDevice) 74 | 75 | 76 | return MMDevice:init(ppDevice[0]); 77 | end 78 | 79 | return closure 80 | end 81 | 82 | --[[ 83 | Device Instance Methods 84 | --]] 85 | function MMDevice.getID(self) 86 | 87 | if not self.ID then 88 | local ppstrId = ffi.new("PWSTR [1]") 89 | local hr = self.Device:GetId(ppstrId) 90 | self.ID = mbs(ppstrId[0]) 91 | end 92 | 93 | return self.ID 94 | end 95 | 96 | function MMDevice.getProperty(self, propKey) 97 | local propVar = ffi.new("PROPVARIANT"); 98 | local hr = self.PropertyStore:GetValue(propKey, propVar); 99 | 100 | return propVar; 101 | end 102 | 103 | -- Enumerate all the properties of the device 104 | function MMDevice.properties(self) 105 | local idx = -1; 106 | 107 | local function closure() 108 | idx = idx + 1; 109 | if idx >= self.PropertyCount then 110 | return nil; 111 | end 112 | 113 | local pkey = ffi.new("PROPERTYKEY") 114 | local hr = self.PropertyStore:GetAt(idx, pkey) 115 | 116 | return self:getProperty(pkey) 117 | end 118 | 119 | return closure 120 | end 121 | 122 | 123 | if not ... then 124 | for device in MMDevice:AudioEndpoints() do 125 | print("Device ID: ", device:getID()) 126 | 127 | for property in device:properties() do 128 | print(" Property: ", property.vt, tostring(property)) 129 | end 130 | end 131 | end 132 | 133 | -------------------------------------------------------------------------------- /winapi/mmsystem.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/system/mmsystem: Multimedia API 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.winuser' 7 | 8 | local winmm = ffi.load'winmm' 9 | 10 | TIMERR_BASE = 96 11 | TIMERR_NOERROR = 0 12 | TIMERR_NOCANDO = TIMERR_BASE+1 --request not completed 13 | TIMERR_STRUCT = TIMERR_BASE+33 --time struct size 14 | 15 | ffi.cdef[[ 16 | typedef UINT MMRESULT; 17 | 18 | typedef struct timecaps_tag { 19 | UINT wPeriodMin; /* minimum period supported */ 20 | UINT wPeriodMax; /* maximum period supported */ 21 | } TIMECAPS, *PTIMECAPS, *LPTIMECAPS; 22 | 23 | MMRESULT timeGetDevCaps(LPTIMECAPS ptc, UINT cbtc); 24 | MMRESULT timeBeginPeriod(UINT uPeriod); 25 | MMRESULT timeEndPeriod(UINT uPeriod); 26 | ]] 27 | 28 | TIMECAPS = types.TIMECAPS 29 | 30 | function timeGetDevCaps(ptc) 31 | ptc = TIMECAPS(ptc) 32 | checkz(winmm.timeGetDevCaps(ptc, ffi.sizeof(ptc))) 33 | return ptc 34 | end 35 | 36 | timeBeginPeriod = winmm.timeBeginPeriod 37 | timeEndPeriod = winmm.timeEndPeriod --called automatically when the process ends. 38 | 39 | 40 | --showcase 41 | 42 | if not ... then 43 | local t = timeGetDevCaps() 44 | print(t.wPeriodMin, t.wPeriodMax) 45 | timeBeginPeriod(t.wPeriodMin) 46 | timeEndPeriod(t.wPeriodMin) 47 | end 48 | -------------------------------------------------------------------------------- /winapi/module.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/system/module: LoadLibrary API 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.winuser' 7 | 8 | ffi.cdef[[ 9 | HMODULE GetModuleHandleW( 10 | LPCWSTR lpModuleName 11 | ); 12 | 13 | BOOL GetModuleHandleExW( 14 | DWORD dwFlags, 15 | LPCWSTR lpModuleName, 16 | HMODULE* phModule 17 | ); 18 | 19 | DWORD GetModuleFileNameW( 20 | HMODULE hModule, 21 | LPWSTR lpFilename, 22 | DWORD nSize 23 | ); 24 | 25 | HMODULE LoadLibraryW(LPCWSTR lpLibFileName); 26 | ]] 27 | 28 | function GetModuleHandle(name) 29 | return checkh(C.GetModuleHandleW(wcs(name))) 30 | end 31 | 32 | GET_MODULE_HANDLE_EX_FLAG_PIN = 0x00000001 33 | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT = 0x00000002 34 | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS = 0x00000004 35 | 36 | function GetModuleHandleEx(name, GMHX, h) 37 | h = h or arrays.HMODULE(1) 38 | checknz(C.GetModuleHandleExW(flags(GMHX), wcs(name), h)) 39 | return h[0] 40 | end 41 | 42 | local ERROR_INSUFFICIENT_BUFFER = 122 43 | 44 | function GetModuleFilename(hmodule) 45 | local bsz = 2048 46 | ::again:: 47 | local buf = WCS(bsz) 48 | local sz = checkpoz(C.GetModuleFileNameW(hmodule, buf, bsz)) 49 | if GetLastError() == ERROR_INSUFFICIENT_BUFFER then 50 | bsz = bsz * 2 51 | goto again 52 | end 53 | return mbs(buf, sz) 54 | end 55 | 56 | function LoadLibrary(filename) 57 | return checkh(C.LoadLibraryW(wcs(filename))) 58 | end 59 | 60 | if not ... then 61 | local file = GetModuleFilename() 62 | print(file) 63 | print(GetModuleHandle()) 64 | print(GetModuleHandleEx(file)) 65 | print(LoadLibrary'shell32') 66 | end 67 | -------------------------------------------------------------------------------- /winapi/monitor.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/system/monitor: Monitor API 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.winuser' 7 | 8 | --NOTE: EnumDisplayMonitors() returns the monitors in random order 9 | --which can also change between reboots. 10 | 11 | ffi.cdef[[ 12 | HMONITOR MonitorFromPoint(POINT pt, DWORD dwFlags); 13 | HMONITOR MonitorFromRect(LPCRECT lprc, DWORD dwFlags); 14 | HMONITOR MonitorFromWindow(HWND hwnd, DWORD dwFlags); 15 | 16 | typedef struct tagMONITORINFO 17 | { 18 | DWORD cbSize; 19 | RECT monitor_rect; 20 | RECT work_rect; 21 | DWORD dwFlags; 22 | } MONITORINFO, *LPMONITORINFO; 23 | 24 | typedef struct tagMONITORINFOEXW 25 | { 26 | MONITORINFO; 27 | WCHAR szDevice[32]; 28 | } MONITORINFOEXW, *LPMONITORINFOEXW; 29 | 30 | BOOL GetMonitorInfoW(HMONITOR hMonitor, LPMONITORINFOEXW lpmi); 31 | typedef BOOL (* MONITORENUMPROC)(HMONITOR, HDC, LPRECT, LPARAM); 32 | 33 | BOOL EnumDisplayMonitors( 34 | HDC hdc, 35 | LPCRECT lprcClip, 36 | MONITORENUMPROC lpfnEnum, 37 | LPARAM dwData); 38 | ]] 39 | 40 | MONITOR_DEFAULTTONULL = 0x00000000 41 | MONITOR_DEFAULTTOPRIMARY = 0x00000001 42 | MONITOR_DEFAULTTONEAREST = 0x00000002 43 | 44 | MONITORINFOF_PRIMARY = 0x00000001 --the only flag in dwFlags 45 | 46 | MONITORINFOEX = struct{ctype = 'MONITORINFOEXW', size = 'cbSize', 47 | fields = sfields{ 48 | 'flags', 'dwFlags', flags, pass, 49 | 'device', '', wc_set'szDevice', wc_get'szDevice', 50 | } 51 | } 52 | 53 | function MonitorFromPoint(pt, mflags) 54 | return ptr(C.MonitorFromPoint(POINT(pt), flags(mflags))) 55 | end 56 | 57 | function MonitorFromRect(rect, mflags) 58 | return ptr(C.MonitorFromRect(RECT(rect), flags(mflags))) 59 | end 60 | 61 | function MonitorFromWindow(hwnd, mflags) 62 | return ptr(C.MonitorFromWindow(hwnd, flags(mflags))) 63 | end 64 | 65 | function GetMonitorInfo(hmonitor, info) 66 | info = MONITORINFOEX(info) 67 | checknz(C.GetMonitorInfoW(hmonitor, info)) 68 | return info 69 | end 70 | 71 | function EnumDisplayMonitors(hdc, cliprect) 72 | local t = {} 73 | local cb = ffi.cast('MONITORENUMPROC', function(hmonitor, hdc, vrect) 74 | table.insert(t, hmonitor) 75 | return 1 --continue 76 | end) 77 | local ret = C.EnumDisplayMonitors(hdc, cliprect, cb, 0) 78 | cb:free() 79 | checknz(ret) 80 | return t 81 | end 82 | 83 | 84 | --showcase 85 | 86 | if not ... then 87 | for i,monitor in ipairs(EnumDisplayMonitors()) do 88 | local info = GetMonitorInfo(monitor) 89 | print(i, info.monitor_rect, info.work_rect, info.device) 90 | end 91 | end 92 | 93 | -------------------------------------------------------------------------------- /winapi/mouse.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/input/mouse: Mouse API 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | 7 | TME_HOVER = 0x00000001 8 | TME_LEAVE = 0x00000002 9 | TME_NONCLIENT = 0x00000010 10 | TME_QUERY = 0x40000000 11 | TME_CANCEL = 0x80000000 12 | HOVER_DEFAULT = 0xFFFFFFFF 13 | 14 | ffi.cdef[[ 15 | typedef struct tagTRACKMOUSEEVENT { 16 | DWORD cbSize; 17 | DWORD dwFlags; 18 | HWND hwnd; 19 | DWORD hover_time; 20 | } TRACKMOUSEEVENT, *LPTRACKMOUSEEVENT; 21 | 22 | BOOL TrackMouseEvent(LPTRACKMOUSEEVENT lpEventTrack); 23 | 24 | UINT GetDoubleClickTime(); 25 | BOOL SetDoubleClickTime(UINT uInterval); 26 | 27 | HWND GetCapture(void); 28 | HWND SetCapture(HWND hWnd); 29 | BOOL ReleaseCapture(void); 30 | 31 | BOOL DragDetect(HWND hwnd, POINT pt); 32 | ]] 33 | 34 | TRACKMOUSEEVENT = struct{ 35 | ctype = 'TRACKMOUSEEVENT', size = 'cbSize', 36 | fields = sfields{ 37 | 'flags', 'dwFlags', flags, pass, 38 | }, 39 | 40 | } 41 | 42 | function TrackMouseEvent(event) 43 | event = TRACKMOUSEEVENT(event) 44 | checknz(C.TrackMouseEvent(event)) 45 | end 46 | 47 | GetDoubleClickTime = C.GetDoubleClickTime 48 | 49 | function SetDoubleClickTime(interval) 50 | checknz(C.SetDoubleClickTime(interval)) 51 | end 52 | 53 | function GetCapture() 54 | return ptr(C.GetCapture()) 55 | end 56 | 57 | function SetCapture(hwnd) 58 | return ptr(C.SetCapture(hwnd)) 59 | end 60 | 61 | function ReleaseCapture() 62 | return checknz(C.ReleaseCapture()) 63 | end 64 | 65 | function DragDetect(hwnd, point) 66 | return C.DragDetect(hwnd, POINT(point)) ~= 0 67 | end 68 | 69 | --messages 70 | 71 | HTERROR = -2 72 | HTTRANSPARENT = -1 73 | HTNOWHERE = 0 74 | HTCLIENT = 1 75 | HTCAPTION = 2 76 | HTSYSMENU = 3 77 | HTGROWBOX = 4 78 | HTSIZE = HTGROWBOX 79 | HTMENU = 5 80 | HTHSCROLL = 6 81 | HTVSCROLL = 7 82 | HTMINBUTTON = 8 83 | HTMAXBUTTON = 9 84 | HTLEFT = 10 85 | HTRIGHT = 11 86 | HTTOP = 12 87 | HTTOPLEFT = 13 88 | HTTOPRIGHT = 14 89 | HTBOTTOM = 15 90 | HTBOTTOMLEFT = 16 91 | HTBOTTOMRIGHT = 17 92 | HTBORDER = 18 93 | HTREDUCE = HTMINBUTTON 94 | HTZOOM = HTMAXBUTTON 95 | HTSIZEFIRST = HTLEFT 96 | HTSIZELAST = HTBOTTOMRIGHT 97 | HTOBJECT = 19 98 | HTCLOSE = 20 99 | HTHELP = 21 100 | 101 | function WM.WM_NCHITTEST(wParam, lParam) 102 | return splitsigned(lParam) --x, y; must return HT* 103 | end 104 | 105 | MK_LBUTTON = 0x0001 106 | MK_RBUTTON = 0x0002 107 | MK_SHIFT = 0x0004 108 | MK_CONTROL = 0x0008 109 | MK_MBUTTON = 0x0010 110 | MK_XBUTTON1 = 0x0020 111 | MK_XBUTTON2 = 0x0040 112 | 113 | local buttons_bitmask = bitmask{ 114 | lbutton = MK_LBUTTON, 115 | rbutton = MK_RBUTTON, 116 | shift = MK_SHIFT, 117 | control = MK_CONTROL, 118 | mbutton = MK_MBUTTON, 119 | xbutton1 = MK_XBUTTON1, 120 | xbutton2 = MK_XBUTTON2, 121 | } 122 | 123 | --NOTE: double-click messages are only received on windows with CS_DBLCLKS style 124 | function WM.WM_LBUTTONDBLCLK(wParam, lParam) 125 | local x, y = splitsigned(lParam) 126 | return x, y, buttons_bitmask:get(tonumber(wParam)) 127 | end 128 | 129 | WM.WM_LBUTTONDOWN = WM.WM_LBUTTONDBLCLK 130 | WM.WM_LBUTTONUP = WM.WM_LBUTTONDBLCLK 131 | WM.WM_MBUTTONDBLCLK = WM.WM_LBUTTONDBLCLK 132 | WM.WM_MBUTTONDOWN = WM.WM_LBUTTONDBLCLK 133 | WM.WM_MBUTTONUP = WM.WM_LBUTTONDBLCLK 134 | WM.WM_MOUSEHOVER = WM.WM_LBUTTONDBLCLK 135 | WM.WM_MOUSEMOVE = WM.WM_LBUTTONDBLCLK 136 | WM.WM_RBUTTONDBLCLK = WM.WM_LBUTTONDBLCLK 137 | WM.WM_RBUTTONDOWN = WM.WM_LBUTTONDBLCLK 138 | WM.WM_RBUTTONUP = WM.WM_LBUTTONDBLCLK 139 | 140 | function WM.WM_MOUSEWHEEL(wParam, lParam) 141 | local x, y = splitsigned(lParam) 142 | local buttons, delta = splitsigned(ffi.cast('int32_t', wParam)) 143 | return x, y, buttons_bitmask:get(buttons), delta 144 | end 145 | 146 | WM.WM_MOUSEHWHEEL = WM.WM_MOUSEWHEEL 147 | 148 | XBUTTON1 = 0x0001 149 | XBUTTON2 = 0x0002 150 | 151 | local xbuttons_bitmask = bitmask{ 152 | xbutton1 = XBUTTON1, 153 | xbutton2 = XBUTTON2, 154 | } 155 | 156 | function WM.WM_XBUTTONDBLCLK(wParam, lParam) 157 | local x, y = splitsigned(lParam) 158 | local MK, XBUTTON = splitlong(wParam) 159 | return x, y, buttons_bitmask:get(MK), xbuttons_bitmask:get(XBUTTON) 160 | end 161 | 162 | WM.WM_XBUTTONDOWN = WM.WM_XBUTTONDBLCLK 163 | WM.WM_XBUTTONUP = WM.WM_XBUTTONDBLCLK 164 | 165 | function WM.WM_NCLBUTTONDBLCLK(wParam, lParam) 166 | local x, y = splitsigned(lParam) 167 | return x, y, tonumber(wParam) --x, y, HT* 168 | end 169 | WM.WM_NCLBUTTONDOWN = WM.WM_NCLBUTTONDBLCLK 170 | WM.WM_NCLBUTTONUP = WM.WM_NCLBUTTONDBLCLK 171 | WM.WM_NCMBUTTONDBLCLK = WM.WM_NCLBUTTONDBLCLK 172 | WM.WM_NCMBUTTONDOWN = WM.WM_NCLBUTTONDBLCLK 173 | WM.WM_NCMBUTTONUP = WM.WM_NCLBUTTONDBLCLK 174 | WM.WM_NCMOUSEHOVER = WM.WM_NCLBUTTONDBLCLK 175 | WM.WM_NCMOUSEMOVE = WM.WM_NCLBUTTONDBLCLK 176 | WM.WM_NCRBUTTONDBLCLK = WM.WM_NCLBUTTONDBLCLK 177 | WM.WM_NCRBUTTONDOWN = WM.WM_NCLBUTTONDBLCLK 178 | WM.WM_NCRBUTTONUP = WM.WM_NCLBUTTONDBLCLK 179 | 180 | WM.WM_NCXBUTTONDBLCLK = WM.WM_XBUTTONDBLCLK --HT*, XBUTTON*, x, y 181 | WM.WM_NCXBUTTONDOWN = WM.WM_NCXBUTTONDBLCLK 182 | WM.WM_NCXBUTTONUP = WM.WM_NCXBUTTONDBLCLK 183 | 184 | MA_ACTIVATE = 1 185 | MA_ACTIVATEANDEAT = 2 186 | MA_NOACTIVATE = 3 187 | MA_NOACTIVATEANDEAT = 4 188 | 189 | function WM.WM_MOUSEACTIVATE(wParam, lParam) 190 | local HT, MK = splitlong(lParam) 191 | return ffi.cast('HWND', wParam), HT, buttons_bitmask:get(MK) --must return MA_* 192 | end 193 | 194 | -------------------------------------------------------------------------------- /winapi/namespace.lua: -------------------------------------------------------------------------------- 1 | 2 | --binding/namespace: namespace module and utils 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | --additional sub-namespaces are published here too. 6 | 7 | local _M = {__index = _G} 8 | setmetatable(_M, _M) 9 | _M._M = _M 10 | 11 | setfenv(1, _M) --all sub-modules use this pattern to publish their stuff. 12 | 13 | --utility to import the contents of a table into the global winapi namespace 14 | --because when strict mode is enabled we can't do glue.update(_M, t) 15 | function import(globals) 16 | for k,v in pairs(globals) do 17 | rawset(_M, k, v) 18 | end 19 | return globals 20 | end 21 | 22 | --import a table as module globals and return the reverse lookup table of it. 23 | function constants(t) 24 | import(t) 25 | return index(t) 26 | end 27 | 28 | --WM is a namespace for registering window message decoders. 29 | WM = {} --{WM_* = function(wParam, lParam) return decoded values ... end} 30 | 31 | --NM is a namespace for registering WM_NOTIFY message decoders. 32 | NM = {} --{NM_* = function(hdr, wParam) return decoded values ... end} 33 | 34 | return _M 35 | -------------------------------------------------------------------------------- /winapi/notifyiconclass.lua: -------------------------------------------------------------------------------- 1 | 2 | --oo/controls/notifyiconclass: system tray icons 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.window' 7 | require'winapi.shellapi' 8 | require'winapi.vobject' 9 | require'winapi.handlelist' 10 | 11 | NotifyIcons = HandleList'id' --id -> NotifyIcon map 12 | 13 | NotifyIcon = class(VObject) 14 | 15 | local last_id = 0 --autoincrement 16 | 17 | function NotifyIcon:__init(t) 18 | self.__info = NOTIFYICONDATA() 19 | local info = self.__info 20 | 21 | last_id = last_id + 1 22 | self.id = last_id 23 | info.id = self.id --for tracking by NotifyIcons. 24 | 25 | info.message = t.message or WM_NOTIFYICON 26 | info.hwnd = t.window and t.window.hwnd or t.hwnd 27 | 28 | info.icon = t.icon 29 | info.tip = t.tip 30 | info.state_HIDDEN = t.visible == false 31 | info.state_SHAREDICON = t.icon_shared 32 | info.info = t.info 33 | info.info_title = t.info_title 34 | info.info_flags = t.info_flags or 0 35 | info.info_timeout = t.info_timeout or 0 36 | 37 | Shell_NotifyIcon(NIM_ADD, self.__info) 38 | 39 | NotifyIcons:add(self) 40 | end 41 | 42 | function NotifyIcon:free() 43 | NotifyIcons:remove(self) 44 | Shell_NotifyIcon(NIM_DELETE, self.__info) 45 | self.id = nil 46 | end 47 | 48 | NotifyIcon.__wm_handler_names = index{ 49 | on_mouse_move = WM_MOUSEMOVE, 50 | on_lbutton_double_click = WM_LBUTTONDBLCLK, 51 | on_lbutton_down = WM_LBUTTONDOWN, 52 | on_lbutton_up = WM_LBUTTONUP, 53 | on_mbutton_double_click = WM_MBUTTONDBLCLK, 54 | on_mbutton_down = WM_MBUTTONDOWN, 55 | on_mbutton_up = WM_MBUTTONUP, 56 | on_rbutton_double_click = WM_RBUTTONDBLCLK, 57 | on_rbutton_down = WM_RBUTTONDOWN, 58 | on_rbutton_up = WM_RBUTTONUP, 59 | on_xbutton_double_click = WM_XBUTTONDBLCLK, 60 | on_xbutton_down = WM_XBUTTONDOWN, 61 | on_xbutton_up = WM_XBUTTONUP, 62 | } 63 | 64 | function NotifyIcon:WM_NOTIFYICON(WM) 65 | local wm_name = WM_NAMES[WM] 66 | if self[wm_name] then 67 | if self[wm_name](self) ~= nil then 68 | return 69 | end 70 | end 71 | local handler_name = self.__wm_handler_names[WM] 72 | if self[handler_name] then 73 | self[handler_name](self) 74 | end 75 | end 76 | 77 | function NotifyIcon:get_visible() --Vista+ 78 | return not self.__info.state_HIDDEN 79 | end 80 | 81 | function NotifyIcon:set_visible(visible) --Vista+ 82 | self.__info.state_HIDDEN = not visible 83 | Shell_NotifyIcon(NIM_MODIFY, self.__info) 84 | end 85 | 86 | --publish info fields individually. 87 | NotifyIcon:__gen_vproperties(NOTIFYICONDATA.fields, function(self, k) 88 | return self.__info[k] 89 | end, function(self, k, v) 90 | self.__info[k] = v 91 | Shell_NotifyIcon(NIM_MODIFY, self.__info) 92 | end) 93 | 94 | --showcase 95 | 96 | if not ... then 97 | require'winapi.windowclass' 98 | require'winapi.icon' 99 | require'winapi.menu' 100 | 101 | local win = Window{w = 500, h = 300, visible = false, autoquit = true} 102 | 103 | local nicon, pmenu 104 | 105 | function win:on_show() 106 | 107 | --create a notification icon. 108 | nicon = NotifyIcon{ 109 | window = self, 110 | icon = LoadIconFromInstance(IDI_INFORMATION), 111 | } 112 | 113 | --alternate the icon on a timer. 114 | local alt = true 115 | self:settimer(0.2, function() 116 | nicon.icon = LoadIconFromInstance(alt == true and IDI_WARNING or IDI_INFORMATION) 117 | alt = not alt 118 | end) 119 | 120 | --popup a menu when right-clicking on the icon. 121 | pmenu = Menu() 122 | pmenu.items:add{text = 'Hello1'} 123 | pmenu.items:add{text = 'Hello2'} 124 | pmenu.items:add{text = 'Hello3'} 125 | pmenu.items:add{text = 'Hello4'} 126 | 127 | function nicon:on_rbutton_up() 128 | local pos = win.cursor_pos 129 | pmenu:popup(win, pos.x, pos.y) 130 | end 131 | end 132 | 133 | function win:on_destroy() 134 | nicon:free() 135 | end 136 | 137 | win:show() 138 | 139 | MessageLoop() 140 | end 141 | -------------------------------------------------------------------------------- /winapi/ole.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/system/ole: OLE API 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | 7 | ole32 = ffi.load'ole32' 8 | 9 | E_NOINTERFACE = 0x80004002 10 | 11 | CLSCTX_INPROC_SERVER = 0x1 12 | CLSCTX_INPROC_HANDLER = 0x2 13 | CLSCTX_LOCAL_SERVER = 0x4 14 | CLSCTX_INPROC_SERVER16 = 0x8 15 | CLSCTX_REMOTE_SERVER = 0x10 16 | CLSCTX_INPROC_HANDLER16 = 0x20 17 | CLSCTX_RESERVED1 = 0x40 18 | CLSCTX_RESERVED2 = 0x80 19 | CLSCTX_RESERVED3 = 0x100 20 | CLSCTX_RESERVED4 = 0x200 21 | CLSCTX_NO_CODE_DOWNLOAD = 0x400 22 | CLSCTX_RESERVED5 = 0x800 23 | CLSCTX_NO_CUSTOM_MARSHAL = 0x1000 24 | CLSCTX_ENABLE_CODE_DOWNLOAD = 0x2000 25 | CLSCTX_NO_FAILURE_LOG = 0x4000 26 | CLSCTX_DISABLE_AAA = 0x8000 27 | CLSCTX_ENABLE_AAA = 0x10000 28 | CLSCTX_FROM_DEFAULT_CONTEXT = 0x20000 29 | CLSCTX_ACTIVATE_32_BIT_SERVER = 0x40000 30 | CLSCTX_ACTIVATE_64_BIT_SERVER = 0x80000 31 | CLSCTX_ENABLE_CLOAKING = 0x100000 32 | CLSCTX_APPCONTAINER = 0x400000 33 | CLSCTX_ACTIVATE_AAA_AS_IU = 0x800000 34 | CLSCTX_PS_DLL = 0x80000000 35 | 36 | ffi.cdef[[ 37 | typedef ULONG PROPID; 38 | 39 | typedef WCHAR OLECHAR; 40 | typedef OLECHAR *LPOLESTR; 41 | typedef const OLECHAR *LPCOLESTR; 42 | typedef OLECHAR *BSTR; 43 | typedef BSTR *LPBSTR; 44 | 45 | typedef struct IUnknown IUnknown, *LPUNKNOWN; 46 | typedef struct IStream IStream; 47 | typedef struct IStorage IStorage; 48 | typedef struct IAdviseSink IAdviseSink; 49 | typedef struct IEnumSTATDATA IEnumSTATDATA; 50 | typedef struct IDispatch IDispatch; 51 | 52 | HRESULT OleInitialize(LPVOID pvReserved); 53 | void OleUninitialize(void); 54 | 55 | HRESULT CoInitialize(LPVOID pvReserved); 56 | void CoUninitialize(void); 57 | 58 | HRESULT CoCreateInstance(REFCLSID rclsid, 59 | IUnknown * pUnkOuter, 60 | DWORD dwClsContext, 61 | REFIID riid, 62 | void ** ppv); 63 | 64 | // COM initialization flags; passed to CoInitialize. 65 | typedef enum tagCOINIT { 66 | COINIT_APARTMENTTHREADED = 0x2, // Apartment model 67 | 68 | // These constants are only valid on Windows NT 4.0 69 | COINIT_MULTITHREADED = 0x0, // OLE calls objects on any thread. 70 | COINIT_DISABLE_OLE1DDE = 0x4, // Don't use DDE for Ole1 support. 71 | COINIT_SPEED_OVER_MEMORY = 0x8, // Trade memory for speed. 72 | } COINIT; 73 | 74 | ]] 75 | 76 | local checkokfalse = checkwith(function(ret) return ret == 0 or ret == 1 end) 77 | 78 | function OleInitialize() 79 | checkokfalse(ole32.OleInitialize(nil)) 80 | end 81 | 82 | function CoInitialize() 83 | checkokfalse(ole32.CoInitialize(nil)) 84 | end 85 | 86 | OleUninitialize = ole32.OleUninitialize 87 | CoUninitialize = ole32.CoUninitialize 88 | 89 | function CoCreateInstance(...) 90 | return checkz(ole32.CoCreateInstance(...)) 91 | end 92 | 93 | --enable Clipboard, Drag and Drop, OLE, In-place activation. 94 | OleInitialize() 95 | 96 | --uninitialize when the module is unloaded. 97 | _ole32 = ffi.new'char*' 98 | ffi.gc(_ole32, OleUninitialize) 99 | 100 | -------------------------------------------------------------------------------- /winapi/panelclass.lua: -------------------------------------------------------------------------------- 1 | 2 | --oo/controls/panel: custom frameless child windows 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.controlclass' 7 | require'winapi.cursor' 8 | require'winapi.color' 9 | require'winapi.winbase' --GetCurrentThreadId 10 | 11 | Panel = subclass({ 12 | __class_style_bitmask = bitmask{ --only static, frame styles here 13 | dropshadow = CS_DROPSHADOW, 14 | own_dc = CS_OWNDC, --keep the same HDC 15 | receive_double_clicks = CS_DBLCLKS, --receive double click messages 16 | }, 17 | __style_bitmask = bitmask{ 18 | tabstop = WS_TABSTOP, 19 | }, 20 | __style_ex_bitmask = bitmask{ 21 | transparent = WS_EX_TRANSPARENT, 22 | }, 23 | __defaults = { 24 | --class style bits 25 | receive_double_clicks = true, --receive double click messages 26 | --other class properties 27 | background = COLOR_WINDOW, 28 | cursor = LoadCursor(IDC_ARROW), 29 | --window properties 30 | w = 100, h = 100, 31 | }, 32 | }, Control) 33 | 34 | --generate a unique class name for each panel so that we can change 35 | --the class styles and properties for each panel individually. 36 | local i = 0 37 | local function gen_classname() 38 | i = i + 1 39 | return string.format('Panel_%d_%d', GetCurrentThreadId(), i) 40 | end 41 | 42 | function Panel:after___before_create(info, args) 43 | self.__winclass = RegisterClass{ 44 | name = gen_classname(), 45 | style = self.__class_style_bitmask:set(0, info), 46 | proc = MessageRouter.proc, 47 | cursor = info.cursor, 48 | background = info.background, --TODO: can't be changed afterwards! 49 | } 50 | args.class = self.__winclass 51 | end 52 | 53 | Panel.__default_proc = BaseWindow.__default_proc 54 | 55 | function Panel:after_WM_NCDESTROY() 56 | PostMessage(nil, WM_UNREGISTER_CLASS, self.__winclass) 57 | end 58 | 59 | --showcase 60 | 61 | if not ... then 62 | require'winapi.showcase' 63 | local win = ShowcaseWindow() 64 | local panel = Panel{ 65 | parent = win, 66 | x = 20, y = 20, 67 | w = win.client_w - 40, 68 | h = win.client_h - 40, 69 | background = CreateSolidBrush(RGB(10, 20, 30)), 70 | anchors = {top = true, left = true, bottom = true, right = true}, 71 | } 72 | MessageLoop() 73 | end 74 | -------------------------------------------------------------------------------- /winapi/panelclass.md: -------------------------------------------------------------------------------- 1 | --- 2 | tagline: custom-painted child windows 3 | --- 4 | 5 | ## `require'winapi.panelclass'` 6 | 7 | This module implements the `Panel` class which is the base class for 8 | custom-painted child windows. `Panel` is useful for both subclassing 9 | and for instantiation. 10 | 11 | ## Panel 12 | 13 | ### Hierarchy 14 | 15 | * [VObject][winapi.vobject] 16 | * [BaseWindow][winapi.basewindowclass] 17 | * [Control][winapi.controlclass] 18 | * Panel 19 | 20 | ### Initial fields and properties 21 | 22 | __NOTE:__ in the table below `i` means initial field, `r` means property 23 | which can be read, `w` means property which can be set. 24 | 25 | ----------------------- -------- ----------------------------------------- -------------- --------------------- 26 | __appearance__ __irw__ __description__ __default__ __reference__ 27 | dropshadow irw drop shadow false CS_DROPSHADOW 28 | transparent irw make transparent false WS_EX_TRANSPARENT 29 | __behavior__ __irw__ __description__ __default__ __reference__ 30 | own_dc irw keep the same HDC false CS_OWNDC 31 | receive_double_clicks irw receive double click messages true CS_DBLCLKS 32 | tabstop irw focus on tab false WS_TABSTOP 33 | ----------------------- -------- ----------------------------------------- -------------- --------------------- 34 | -------------------------------------------------------------------------------- /winapi/propsys.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/system/propsys: Property System API 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.sstorage' 7 | 8 | ffi.cdef[[ 9 | typedef struct _tagpropertykey 10 | { 11 | GUID fmtid; 12 | DWORD pid; 13 | } PROPERTYKEY; 14 | 15 | typedef const PROPERTYKEY * REFPROPERTYKEY; 16 | 17 | typedef struct IPropertyStore IPropertyStore; 18 | 19 | typedef struct IPropertyStoreVtbl 20 | { 21 | 22 | HRESULT ( __stdcall *QueryInterface )( 23 | IPropertyStore * This, 24 | REFIID riid, 25 | void **ppvObject); 26 | 27 | ULONG ( __stdcall *AddRef )( 28 | IPropertyStore * This); 29 | 30 | ULONG ( __stdcall *Release )( 31 | IPropertyStore * This); 32 | 33 | HRESULT ( __stdcall *GetCount )( 34 | IPropertyStore * This, 35 | DWORD *cProps); 36 | 37 | HRESULT ( __stdcall *GetAt )( 38 | IPropertyStore * This, 39 | DWORD iProp, 40 | PROPERTYKEY *pkey); 41 | 42 | HRESULT ( __stdcall *GetValue )( 43 | IPropertyStore * This, 44 | REFPROPERTYKEY key, 45 | PROPVARIANT *pv); 46 | 47 | HRESULT ( __stdcall *SetValue )( 48 | IPropertyStore * This, 49 | /* [in] */ REFPROPERTYKEY key, 50 | /* [in] */ REFPROPVARIANT propvar); 51 | 52 | HRESULT ( __stdcall *Commit )( 53 | IPropertyStore * This); 54 | 55 | } IPropertyStoreVtbl; 56 | 57 | struct IPropertyStore 58 | { 59 | const struct IPropertyStoreVtbl *lpVtbl; 60 | }; 61 | ]] 62 | 63 | IPropertyStore = ffi.typeof("IPropertyStore"); 64 | IPropertyStore_mt = { 65 | __index = { 66 | GetAt = function(self, idx, pkey) 67 | return self.lpVtbl.GetAt(self, idx, pkey); 68 | end, 69 | 70 | GetValue = function(self, pkey, pv) 71 | return self.lpVtbl.GetValue(self, pkey, pv); 72 | end, 73 | }, 74 | } 75 | ffi.metatype(IPropertyStore, IPropertyStore_mt); 76 | 77 | 78 | --[[ 79 | #define IPropertyStore_QueryInterface(This,riid,ppvObject) \ 80 | ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) 81 | 82 | #define IPropertyStore_AddRef(This) \ 83 | ( (This)->lpVtbl -> AddRef(This) ) 84 | 85 | #define IPropertyStore_Release(This) \ 86 | ( (This)->lpVtbl -> Release(This) ) 87 | 88 | 89 | #define IPropertyStore_GetCount(This,cProps) \ 90 | ( (This)->lpVtbl -> GetCount(This,cProps) ) 91 | 92 | #define IPropertyStore_GetAt(This,iProp,pkey) \ 93 | ( (This)->lpVtbl -> GetAt(This,iProp,pkey) ) 94 | 95 | #define IPropertyStore_GetValue(This,key,pv) \ 96 | ( (This)->lpVtbl -> GetValue(This,key,pv) ) 97 | 98 | #define IPropertyStore_SetValue(This,key,propvar) \ 99 | ( (This)->lpVtbl -> SetValue(This,key,propvar) ) 100 | 101 | #define IPropertyStore_Commit(This) \ 102 | ( (This)->lpVtbl -> Commit(This) ) 103 | --]] 104 | -------------------------------------------------------------------------------- /winapi/radiobuttonclass.lua: -------------------------------------------------------------------------------- 1 | 2 | --oo/controls/radiobutton: radio button control 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.basebuttonclass' 7 | 8 | RadioButton = subclass({ 9 | __style_bitmask = bitmask{ 10 | box_align = { 11 | left = 0, 12 | right = BS_LEFTTEXT, 13 | }, 14 | pushlike = BS_PUSHLIKE, 15 | autocheck = { 16 | [false] = BS_RADIOBUTTON, 17 | [true] = BS_AUTORADIOBUTTON, 18 | }, 19 | }, 20 | __defaults = { 21 | autocheck = true, 22 | text = 'Option', 23 | w = 100, h = 24, 24 | }, 25 | __init_properties = { 26 | 'checked' 27 | }, 28 | }, BaseButton) 29 | 30 | function RadioButton:set_dontclick(dontclick) --Vista+ 31 | Button_SetDontClick(self.hwnd, dontclick) 32 | end 33 | 34 | local button_states = { 35 | [false] = BST_UNCHECKED, 36 | [true] = BST_CHECKED, 37 | } 38 | local button_state_names = index(button_states) 39 | function RadioButton:set_checked(checked) 40 | Button_SetCheck(self.hwnd, button_states[checked]) 41 | end 42 | function RadioButton:get_checked() 43 | return button_state_names[bit.band(Button_GetCheck(self.hwnd), 3)] 44 | end 45 | 46 | --showcase 47 | 48 | if not ... then 49 | require'winapi.showcase' 50 | local window = ShowcaseWindow{w=300,h=200} 51 | local cb1 = RadioButton{parent = window, w = 200, text = 'I am The Ocean', checked = true, 52 | box_align = 'right', align = 'left', halign = 'center', flat = true, 53 | image_list = {image_list = ShowcaseImageList()}} 54 | function cb1:on_click() print'b1 clicked' end 55 | 56 | local cb2 = RadioButton{parent = window, y = 30, pushlike = true} 57 | 58 | local cb3 = RadioButton{parent = window, y = 60, w = 150, h = 50, 59 | word_wrap = true, valign = 'top', double_clicks = true, 60 | text = "I'm a radioobutton and I'm ok. I sleep all night and I work all day."} 61 | function cb3:on_double_click() print 'b3 dbl-clicked' end 62 | 63 | MessageLoop() 64 | end 65 | 66 | -------------------------------------------------------------------------------- /winapi/radiobuttonclass.md: -------------------------------------------------------------------------------- 1 | --- 2 | tagline: radio buttons 3 | --- 4 | 5 | ## `require'winapi.radiobuttonclass'` 6 | 7 | This module implements the `RadioButton` class for creating radio buttons. 8 | 9 | ## RadioButton 10 | 11 | ### Hierarchy 12 | 13 | * [VObject][winapi.vobject] 14 | * [BaseWindow][winapi.basewindowclass] 15 | * [Control][winapi.controlclass] 16 | * [BaseButton][winapi.basebuttonclass] 17 | * RadioButton 18 | 19 | ### Initial fields and properties 20 | 21 | __NOTE:__ in the table below `i` means initial field, `r` means property 22 | which can be read, `w` means property which can be set. 23 | 24 | ----------------------- -------- ----------------------------------------- ----------------------- --------------------- 25 | __field/property__ __irw__ __description__ __default__ __reference__ 26 | text irw checkbox's label 'Option' Get/SetWindowText 27 | w, h irw size 100, 24 28 | box_align irw 'left', 'right' 'left' BS_LEFTTEXT 29 | pushlike irw push-like appearance false BS_PUSHLIKE 30 | checked irw true, false false BST_(UN)CHECKED 31 | autocheck irw automatic checking based on group true BS_(AUTO)RADIOBUTTON 32 | dontclick w make not clickable (Vista+) BM_SETDONTCLICK 33 | ----------------------- -------- ----------------------------------------- ----------------------- --------------------- 34 | -------------------------------------------------------------------------------- /winapi/registry.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/system/registry: Registry API 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | 7 | -------------------------------------------------------------------------------- /winapi/resource.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/resources/resource: LoadImage API 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.winuser' 7 | 8 | ffi.cdef[[ 9 | HANDLE LoadImageW( 10 | HINSTANCE hInst, 11 | LPCWSTR name, 12 | UINT type, 13 | int cx, 14 | int cy, 15 | UINT fuLoad); 16 | ]] 17 | 18 | LR_DEFAULTCOLOR = 0x00000000 19 | LR_MONOCHROME = 0x00000001 20 | LR_COLOR = 0x00000002 21 | LR_COPYRETURNORG = 0x00000004 22 | LR_COPYDELETEORG = 0x00000008 23 | LR_LOADFROMFILE = 0x00000010 --will only load from the current working directory! 24 | LR_LOADTRANSPARENT = 0x00000020 25 | LR_DEFAULTSIZE = 0x00000040 26 | LR_VGACOLOR = 0x00000080 27 | LR_LOADMAP3DCOLORS = 0x00001000 28 | LR_CREATEDIBSECTION = 0x00002000 29 | LR_COPYFROMRESOURCE = 0x00004000 30 | LR_SHARED = 0x00008000 31 | 32 | function LoadImage(hinst, name, IMAGE, w, h, LR) 33 | return checkh(C.LoadImageW(hinst, wcs(name), flags(IMAGE), w, h, flags(LR))) 34 | end 35 | 36 | function LoadIconFromFile(filename, w, h, LR) 37 | return LoadImage(nil, filename, IMAGE_ICON, w or 0, h or 0, bit.bor(LR_LOADFROMFILE, flags(LR))) 38 | end 39 | 40 | function LoadBitmapFromFile(filename, w, h, LR) 41 | return LoadImage(nil, filename, IMAGE_BITMAP, w or 0, h or 0, bit.bor(LR_LOADFROMFILE, flags(LR))) 42 | end 43 | -------------------------------------------------------------------------------- /winapi/richedit.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/controls/richedit: standard richedit control 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | 7 | ffi.cdef[[ 8 | ]] 9 | -------------------------------------------------------------------------------- /winapi/rpc.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/system/rpc: RPC types 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | 7 | rpc = ffi.load'Rpcrt4' 8 | 9 | ffi.cdef[[ 10 | typedef long RPC_STATUS; 11 | typedef unsigned short* RPC_WSTR; 12 | 13 | RPC_STATUS RpcStringFreeW(RPC_WSTR* String); 14 | ]] 15 | -------------------------------------------------------------------------------- /winapi/showcase.lua: -------------------------------------------------------------------------------- 1 | 2 | --test/showcase: testing utilities 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.windowclass' 7 | require'winapi.comctl' 8 | require'winapi.imagelistclass' 9 | 10 | function ShowcaseWindow(info) 11 | return Window(update({}, {title = 'Showcase', autoquit = true}, info)) 12 | end 13 | 14 | require'winapi.shellapi' 15 | function ShowcaseImageList() 16 | return ImageList(ffi.cast('HIMAGELIST', 17 | SHGetFileInfo('c:\\', 0, 'SHGFI_ICON | SHGFI_SYSICONINDEX | SHGFI_SMALLICON'))) 18 | end 19 | 20 | 21 | if not ... then 22 | local window = ShowcaseWindow() 23 | MessageLoop() 24 | end 25 | -------------------------------------------------------------------------------- /winapi/static.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/controls/static: label/shape/image control 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.window' 7 | 8 | --creation 9 | 10 | WC_STATIC = 'Static' 11 | 12 | --text styles 13 | SS_LEFT = 0x00000000 14 | SS_CENTER = 0x00000001 15 | SS_RIGHT = 0x00000002 16 | SS_SIMPLE = 0x0000000B 17 | SS_LEFTNOWORDWRAP = 0x0000000C 18 | SS_NOPREFIX = 0x00000080 -- Don't do "&" character translation 19 | 20 | --image styles 21 | SS_ICON = 0x00000003 22 | SS_BITMAP = 0x0000000E 23 | SS_ENHMETAFILE = 0x0000000F 24 | 25 | --shape styles 26 | SS_BLACKRECT = 0x00000004 27 | SS_GRAYRECT = 0x00000005 28 | SS_WHITERECT = 0x00000006 29 | SS_BLACKFRAME = 0x00000007 30 | SS_GRAYFRAME = 0x00000008 31 | SS_WHITEFRAME = 0x00000009 32 | SS_ETCHEDHORZ = 0x00000010 33 | SS_ETCHEDVERT = 0x00000011 34 | SS_ETCHEDFRAME = 0x00000012 35 | 36 | --behavior styles 37 | SS_NOTIFY = 0x00000100 38 | 39 | --other styles 40 | SS_USERITEM = 0x0000000A --undocumented 41 | SS_OWNERDRAW = 0x0000000D 42 | SS_TYPEMASK = 0x0000001F --deprecated 43 | SS_REALSIZECONTROL = 0x00000040 44 | SS_CENTERIMAGE = 0x00000200 45 | SS_RIGHTJUST = 0x00000400 46 | SS_REALSIZEIMAGE = 0x00000800 47 | SS_SUNKEN = 0x00001000 48 | SS_EDITCONTROL = 0x00002000 49 | SS_ENDELLIPSIS = 0x00004000 50 | SS_PATHELLIPSIS = 0x00008000 51 | SS_WORDELLIPSIS = 0x0000C000 52 | SS_ELLIPSISMASK = 0x0000C000 53 | 54 | --commands 55 | 56 | STM_SETICON = 0x0170 57 | STM_GETICON = 0x0171 58 | STM_SETIMAGE = 0x0172 59 | STM_GETIMAGE = 0x0173 60 | 61 | --notifications 62 | 63 | STN_CLICKED = 0 64 | STN_DBLCLK = 1 65 | STN_ENABLE = 2 66 | STN_DISABLE = 3 67 | 68 | Static_Enable = EnableWindow 69 | Static_GetText = GetWindowText 70 | Static_SetText = SetWindowText 71 | 72 | --[[ 73 | function Static_SetIcon(st, icon) 74 | return SNDMSG(st, STM_SETICON, icon, 0, 'HICON', nil, checkh, 'HICON') 75 | end 76 | 77 | function Static_GetIcon(st) 78 | return SNDMSG(st, STM_GETICON, 0, 0, nil, nil, checkh, 'HICON') 79 | end 80 | ]] 81 | -------------------------------------------------------------------------------- /winapi/sync.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/system/sync: Synchronization API 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.winbase' 7 | 8 | ffi.cdef[[ 9 | HANDLE CreateMutexW( 10 | LPSECURITY_ATTRIBUTES lpMutexAttributes, 11 | BOOL bInitialOwner, 12 | LPCWSTR lpName 13 | ); 14 | ]] 15 | 16 | local ERROR_ACCESS_DENIED = 0x5 17 | local ERROR_ALREADY_EXISTS = 0xB7 18 | local errors = { 19 | [ERROR_ACCESS_DENIED] = 'access_denied', 20 | [ERROR_ALREADY_EXISTS] = 'already_exists', 21 | } 22 | 23 | function CreateMutex(sec, initial_owner, name) 24 | local h = checkh(C.CreateMutexW(sec, initial_owner, wcs(name))) 25 | local err = GetLastError() 26 | if err == 0 then return h end 27 | return h, errors[err] or err 28 | end 29 | 30 | if not ... then 31 | print(CreateMutex(nil, false, 'my mutex')) 32 | end 33 | -------------------------------------------------------------------------------- /winapi/sysinfo.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/system/sysinfo: System Info API 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | 7 | --GetSystemInfo 8 | 9 | ffi.cdef[[ 10 | typedef struct _SYSTEM_INFO { 11 | union { 12 | DWORD dwOemId; 13 | struct { 14 | WORD wProcessorArchitecture; 15 | WORD wReserved; 16 | }; 17 | }; 18 | DWORD dwPageSize; 19 | LPVOID lpMinimumApplicationAddress; 20 | LPVOID lpMaximumApplicationAddress; 21 | DWORD_PTR dwActiveProcessorMask; 22 | DWORD dwNumberOfProcessors; 23 | DWORD dwProcessorType; 24 | DWORD dwAllocationGranularity; 25 | WORD wProcessorLevel; 26 | WORD wProcessorRevision; 27 | } SYSTEM_INFO, *LPSYSTEM_INFO; 28 | 29 | void GetSystemInfo(LPSYSTEM_INFO lpSystemInfo); 30 | ]] 31 | 32 | function GetSystemInfo(sysinfo) 33 | local sysinfo = sysinfo or ffi.new'SYSTEM_INFO' 34 | C.GetSystemInfo(sysinfo) 35 | return sysinfo 36 | end 37 | 38 | --GetVersionEx 39 | 40 | ffi.cdef[[ 41 | typedef struct _OSVERSIONINFOEXW { 42 | DWORD dwOSVersionInfoSize; 43 | DWORD dwMajorVersion; 44 | DWORD dwMinorVersion; 45 | DWORD dwBuildNumber; 46 | DWORD dwPlatformId; // always 2 47 | WCHAR szCSDVersion[128]; 48 | WORD wServicePackMajor; 49 | WORD wServicePackMinor; 50 | WORD wSuiteMask; // VER_SUITE_* 51 | BYTE wProductType; // VER_NT_* 52 | BYTE wReserved; 53 | } OSVERSIONINFOEXW, *POSVERSIONINFOEXW, *LPOSVERSIONINFOEXW, RTL_OSVERSIONINFOEXW, *PRTL_OSVERSIONINFOEXW; 54 | 55 | BOOL GetVersionExW(LPOSVERSIONINFOEXW lpVersionInfo); 56 | DWORD RtlGetVersion(PRTL_OSVERSIONINFOEXW lpVersionInformation); 57 | ]] 58 | 59 | VER_SUITE_SMALLBUSINESS = 0x00000001 60 | VER_SUITE_ENTERPRISE = 0x00000002 61 | VER_SUITE_BACKOFFICE = 0x00000004 62 | VER_SUITE_COMMUNICATIONS = 0x00000008 63 | VER_SUITE_TERMINAL = 0x00000010 64 | VER_SUITE_SMALLBUSINESS_RESTRICTED = 0x00000020 65 | VER_SUITE_EMBEDDEDNT = 0x00000040 66 | VER_SUITE_DATACENTER = 0x00000080 67 | VER_SUITE_SINGLEUSERTS = 0x00000100 68 | VER_SUITE_PERSONAL = 0x00000200 69 | VER_SUITE_BLADE = 0x00000400 70 | VER_SUITE_EMBEDDED_RESTRICTED = 0x00000800 71 | VER_SUITE_SECURITY_APPLIANCE = 0x00001000 72 | VER_SUITE_STORAGE_SERVER = 0x00002000 73 | VER_SUITE_COMPUTE_SERVER = 0x00004000 74 | VER_SUITE_WH_SERVER = 0x00008000 75 | 76 | VER_NT_DOMAIN_CONTROLLER = 0x0000002 --domain controler for VER_NT_SERVER. 77 | VER_NT_SERVER = 0x0000003 --Server 2013, 2008 R2, 2008, 2003, 2000. 78 | VER_NT_WORKSTATION = 0x0000001 --8, 7, Vista, XP Pro, XP Home, 200O Pro. 79 | 80 | local function forcembs(ver) 81 | return mbs(ffi.cast('WCHAR*', ver)) 82 | end 83 | 84 | OSVERSIONINFOEX = struct{ 85 | ctype = 'OSVERSIONINFOEXW', size = 'dwOSVersionInfoSize', 86 | fields = sfields{ 87 | 'ServicePackString', 'szCSDVersion', pass, forcembs, 88 | }, 89 | } 90 | 91 | --NOTE: GetVersionEx lies about Win8.1 being Win8.0 (i.e. 6.2 instead of 6.3). 92 | --To make it not lie, you have to use a dreaded manifest. 93 | --Better use RtlGetVersion which doesn't (yet) lie. 94 | function GetVersionEx(info) 95 | info = OSVERSIONINFOEX(info) 96 | checknz(C.GetVersionExW(info)) 97 | return info 98 | end 99 | 100 | local ntdll 101 | function RtlGetVersion(info) 102 | ntdll = ntdll or ffi.load'ntdll' 103 | info = OSVERSIONINFOEX(info) 104 | checkz(ntdll.RtlGetVersion(info)) 105 | return info 106 | end 107 | 108 | if not ... then 109 | local sysinfo = GetSystemInfo() 110 | 111 | local function print_verinfo(how) 112 | local verinfo = _M[how]() 113 | print(how, 'Windows ' .. 114 | verinfo.dwMajorVersion .. '.' .. verinfo.dwMinorVersion .. '.' .. verinfo.dwBuildNumber .. ' ' .. 115 | 'SP ' .. verinfo.wServicePackMajor .. '.' .. verinfo.wServicePackMinor .. ' (' .. 116 | verinfo.ServicePackString .. ')') 117 | end 118 | 119 | print_verinfo'GetVersionEx' 120 | print_verinfo'RtlGetVersion' 121 | end 122 | 123 | -------------------------------------------------------------------------------- /winapi/systemmetrics.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/system/systemmetrics: System Metrics API 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | 7 | SM_CXSCREEN = 0 8 | SM_CYSCREEN = 1 9 | SM_CXVSCROLL = 2 10 | SM_CYHSCROLL = 3 11 | SM_CYCAPTION = 4 12 | SM_CXBORDER = 5 13 | SM_CYBORDER = 6 14 | SM_CXDLGFRAME = 7 15 | SM_CYDLGFRAME = 8 16 | SM_CYVTHUMB = 9 17 | SM_CXHTHUMB = 10 18 | SM_CXICON = 11 19 | SM_CYICON = 12 20 | SM_CXCURSOR = 13 21 | SM_CYCURSOR = 14 22 | SM_CYMENU = 15 23 | SM_CXFULLSCREEN = 16 24 | SM_CYFULLSCREEN = 17 25 | SM_CYKANJIWINDOW = 18 26 | SM_MOUSEPRESENT = 19 27 | SM_CYVSCROLL = 20 28 | SM_CXHSCROLL = 21 29 | SM_DEBUG = 22 30 | SM_SWAPBUTTON = 23 31 | SM_RESERVED1 = 24 32 | SM_RESERVED2 = 25 33 | SM_RESERVED3 = 26 34 | SM_RESERVED4 = 27 35 | SM_CXMIN = 28 36 | SM_CYMIN = 29 37 | SM_CXSIZE = 30 38 | SM_CYSIZE = 31 39 | SM_CXFRAME = 32 40 | SM_CYFRAME = 33 41 | SM_CXMINTRACK = 34 42 | SM_CYMINTRACK = 35 43 | SM_CXDOUBLECLK = 36 44 | SM_CYDOUBLECLK = 37 45 | SM_CXICONSPACING = 38 46 | SM_CYICONSPACING = 39 47 | SM_MENUDROPALIGNMENT = 40 48 | SM_PENWINDOWS = 41 49 | SM_DBCSENABLED = 42 50 | SM_CMOUSEBUTTONS = 43 51 | SM_CXFIXEDFRAME = SM_CXDLGFRAME -- ;win40 name change 52 | SM_CYFIXEDFRAME = SM_CYDLGFRAME -- ;win40 name change 53 | SM_CXSIZEFRAME = SM_CXFRAME -- ;win40 name change 54 | SM_CYSIZEFRAME = SM_CYFRAME -- ;win40 name change 55 | SM_SECURE = 44 56 | SM_CXEDGE = 45 57 | SM_CYEDGE = 46 58 | SM_CXMINSPACING = 47 59 | SM_CYMINSPACING = 48 60 | SM_CXSMICON = 49 61 | SM_CYSMICON = 50 62 | SM_CYSMCAPTION = 51 63 | SM_CXSMSIZE = 52 64 | SM_CYSMSIZE = 53 65 | SM_CXMENUSIZE = 54 66 | SM_CYMENUSIZE = 55 67 | SM_ARRANGE = 56 68 | SM_CXMINIMIZED = 57 69 | SM_CYMINIMIZED = 58 70 | SM_CXMAXTRACK = 59 71 | SM_CYMAXTRACK = 60 72 | SM_CXMAXIMIZED = 61 73 | SM_CYMAXIMIZED = 62 74 | SM_NETWORK = 63 75 | SM_CLEANBOOT = 67 76 | SM_CXDRAG = 68 77 | SM_CYDRAG = 69 78 | SM_SHOWSOUNDS = 70 79 | SM_CXMENUCHECK = 71 --Use instead of GetMenuCheckMarkDimensions()! 80 | SM_CYMENUCHECK = 72 81 | SM_SLOWMACHINE = 73 82 | SM_MIDEASTENABLED = 74 83 | SM_MOUSEWHEELPRESENT = 75 84 | SM_XVIRTUALSCREEN = 76 85 | SM_YVIRTUALSCREEN = 77 86 | SM_CXVIRTUALSCREEN = 78 87 | SM_CYVIRTUALSCREEN = 79 88 | SM_CMONITORS = 80 89 | SM_SAMEDISPLAYFORMAT = 81 90 | SM_IMMENABLED = 82 91 | SM_CXFOCUSBORDER = 83 92 | SM_CYFOCUSBORDER = 84 93 | SM_TABLETPC = 86 94 | SM_MEDIACENTER = 87 95 | SM_STARTER = 88 96 | SM_SERVERR2 = 89 97 | SM_MOUSEHORIZONTALWHEELPRESENT = 91 98 | SM_CXPADDEDBORDER = 92 99 | SM_DIGITIZER = 94 100 | SM_MAXIMUMTOUCHES = 95 101 | SM_REMOTESESSION = 0x1000 102 | SM_SHUTTINGDOWN = 0x2000 103 | SM_REMOTECONTROL = 0x2001 104 | SM_CARETBLINKINGENABLED = 0x2002 105 | 106 | ffi.cdef[[ 107 | int GetSystemMetrics(int nIndex); 108 | ]] 109 | 110 | function GetSystemMetrics(index) 111 | return C.GetSystemMetrics(flags(index)) 112 | end 113 | 114 | 115 | if not ... then 116 | for k in pairs(getfenv(1)) do 117 | if k:match'^SM_' then 118 | print(string.format('%-30s %s', k, GetSystemMetrics(k))) 119 | end 120 | end 121 | end 122 | -------------------------------------------------------------------------------- /winapi/tabcontrolclass.lua: -------------------------------------------------------------------------------- 1 | 2 | --oo/controls/tabcontrol: standard tab control 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.controlclass' 7 | require'winapi.itemlist' 8 | require'winapi.tabcontrol' 9 | 10 | TabItemList = class(ItemList) 11 | 12 | function TabItemList:__init(tab, items) 13 | self.hwnd = tab.hwnd 14 | self:add_items(items) 15 | end 16 | 17 | function TabItemList:add(i, item) 18 | if not item then i, item = 0x7fffffff, i end 19 | if type(item) == 'string' then 20 | local s = item 21 | item = TCITEM() 22 | item.text = wcs(s) 23 | end 24 | TabCtrl_InsertItem(self.hwnd, i, item) 25 | end 26 | 27 | function TabItemList:del(i) 28 | TabCtrl_DeleteItem(self.hwnd, i) 29 | end 30 | 31 | function TabItemList:clear() 32 | TabCtrl_DeleteAllItems(self.hwnd) 33 | end 34 | 35 | function TabItemList:set(i, item) 36 | TabCtrl_SetItem(self.hwnd, i, item) 37 | end 38 | 39 | function TabItemList:get(i) 40 | self.__item = TCITEM:setmask(self.__item) 41 | TabCtrl_GetItem(self.hwnd, i, self.__item) 42 | return self.__item 43 | end 44 | 45 | function TabItemList:get_count() 46 | return TabCtrl_GetItemCount(self.hwnd) 47 | end 48 | 49 | 50 | TabControl = subclass({ 51 | __style_bitmask = bitmask{ 52 | tabstop = WS_TABSTOP, 53 | }, 54 | __style_ex_bitmask = bitmask{ --these don't work well with CBS_SIMPLE says MS! 55 | 56 | }, 57 | __defaults = { 58 | tabstop = true, 59 | w = 200, h = 100, 60 | }, 61 | __init_properties = {}, 62 | __wm_notify_handler_names = index{ 63 | on_key_down = TCN_KEYDOWN, 64 | on_tab_change = TCN_SELCHANGE, 65 | on_tab_changing = TCN_SELCHANGING, 66 | on_get_object = TCN_GETOBJECT, 67 | on_focus_change = TCN_FOCUSCHANGE, 68 | } 69 | }, Control) 70 | 71 | function TabControl:after___before_create(info, args) 72 | args.class = WC_TABCONTROL 73 | --args.style_ex = bit.bor(args.style_ex, WS_EX_COMPOSITED) 74 | end 75 | 76 | function TabControl:after___init(info) 77 | self.items = TabItemList(self, info.items) 78 | end 79 | 80 | function TabControl:set_image_list(iml) 81 | TabCtrl_SetImageList(self.hwnd, iml.himl) 82 | end 83 | 84 | function TabControl:set_selected_index(i) TabCtrl_SetCurSel(self.hwnd, i) end 85 | function TabControl:get_selected_index() return TabCtrl_GetCurSel(self.hwnd) end 86 | 87 | --showcase 88 | if not ... then 89 | require'winapi.showcase' 90 | local window = ShowcaseWindow{w=300,h=200} 91 | 92 | t1 = TabControl{parent = window} 93 | t1.image_list = ShowcaseImageList() 94 | t1.items:add{text = 'tab#1', image = 2} 95 | t1.items:add{text = 'tab#2', image = 3} 96 | t1.selected_index = 2 97 | assert(t1.selected_index == 2) 98 | 99 | MessageLoop() 100 | end 101 | -------------------------------------------------------------------------------- /winapi/thread.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/system/thread: Threads API 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | local ffi = require'ffi' 6 | 7 | setfenv(1, require'winapi') 8 | require'winapi.winbase' 9 | 10 | ffi.cdef[[ 11 | typedef DWORD (*LPTHREAD_START_ROUTINE)(LPVOID lpThreadParameter); 12 | 13 | HANDLE CreateThread( 14 | LPSECURITY_ATTRIBUTES lpThreadAttributes, 15 | SIZE_T dwStackSize, 16 | LPTHREAD_START_ROUTINE lpStartAddress, 17 | LPVOID lpParameter, 18 | DWORD dwCreationFlags, 19 | LPDWORD lpThreadId 20 | ); 21 | 22 | DWORD ResumeThread( 23 | HANDLE hThread 24 | ); 25 | ]] 26 | 27 | function ResumeThread(h) 28 | local sc = C.ResumeThread(h) 29 | if sc == 4294967295 then sc = -1 end 30 | return retpoz(sc) 31 | end 32 | -------------------------------------------------------------------------------- /winapi/time.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/system/time: time functions 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | 7 | ffi.cdef[[ 8 | DWORD GetTickCount(); 9 | ULONGLONG GetTickCount64(); 10 | BOOL QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount); 11 | BOOL QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency); 12 | BOOL QueryUnbiasedInterruptTime(PULONGLONG UnbiasedTime); 13 | ]] 14 | 15 | GetTickCount = C.GetTickCount --NOTE: wraps around after 49 days of system runtime 16 | 17 | function GetTickCount64() --Vista+ 18 | return C.GetTickCount64() 19 | end 20 | 21 | function QueryPerformanceCounter(counter) 22 | counter = counter or types.LARGE_INTEGER(counter) 23 | checknz(C.QueryPerformanceCounter(counter)) 24 | return counter 25 | end 26 | 27 | function QueryPerformanceFrequency(freq) 28 | freq = freq or types.LARGE_INTEGER(freq) 29 | checknz(C.QueryPerformanceFrequency(freq)) 30 | return freq 31 | end 32 | 33 | function QueryUnbiasedInterruptTime(time) --Vista+ 34 | time = time or ffi.new'ULONGLONG[1]' 35 | checknz(C.QueryUnbiasedInterruptTime(time)) 36 | return time[0] 37 | end 38 | 39 | if not ... then 40 | print('GetTickCount', GetTickCount()) 41 | --print('GetTickCount64', GetTickCount64()) 42 | print('QueryPerformanceCounter', QueryPerformanceCounter().QuadPart, 43 | QueryPerformanceCounter().QuadPart - tonumber(QueryPerformanceCounter().QuadPart)) 44 | print('QueryPerformanceFrequency', QueryPerformanceFrequency().QuadPart) 45 | --print('QueryUnbiasedInterruptTime', QueryUnbiasedInterruptTime()) 46 | 47 | end 48 | 49 | -------------------------------------------------------------------------------- /winapi/toolbarclass.lua: -------------------------------------------------------------------------------- 1 | 2 | --oo/controls/toolbar: standard toolbar control 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.controlclass' 7 | require'winapi.itemlist' 8 | require'winapi.toolbar' 9 | 10 | TBItemList = class(ItemList) 11 | 12 | function TBItemList:add(i, item) 13 | if not item then i,item = nil,i end --i is optional 14 | if i then 15 | Toolbar_InsertButton(self.hwnd, i, item) 16 | else 17 | Toolbar_AddButton(self.hwnd, item) 18 | end 19 | end 20 | 21 | function TBItemList:remove(i) 22 | return Tooldbar_DeleteButton(self.hwnd, i) 23 | end 24 | 25 | function TBItemList:set(i, item) 26 | Toolbar_SetButtonInfo(self.hwnd, i, item) 27 | end 28 | 29 | function TBItemList:get(i) 30 | return Toolbar_GetButtonInfo(self.hwnd, i) 31 | end 32 | 33 | function TBItemList:get_count() 34 | return Toolbar_GetButtonCount(self.hwnd) 35 | end 36 | 37 | function TBItemList:get_text(i) 38 | return Toolbar_GetButtonText(self.hwnd, i) 39 | end 40 | 41 | Toolbar = subclass({ 42 | __style_bitmask = bitmask{ 43 | align = { 44 | top = CCS_TOP, 45 | bottom = CCS_BOTTOM, 46 | }, 47 | customizable = CCS_ADJUSTABLE, 48 | tooltips = TBSTYLE_TOOLTIPS, 49 | multiline = TBSTYLE_WRAPABLE, 50 | alt_drag = TBSTYLE_ALTDRAG, --only if customizable 51 | flat = TBSTYLE_FLAT, 52 | list = TBSTYLE_LIST, --not resettable 53 | custom_erase_background = TBSTYLE_CUSTOMERASE, 54 | is_drop_target = TBSTYLE_REGISTERDROP, 55 | transparent = TBSTYLE_TRANSPARENT, --not resettable 56 | no_divider = CCS_NODIVIDER, 57 | no_align = CCS_NOPARENTALIGN, 58 | }, 59 | __style_ex_bitmask = bitmask{ 60 | mixed_buttons = TBSTYLE_EX_MIXEDBUTTONS, 61 | hide_clipped_buttons = TBSTYLE_EX_HIDECLIPPEDBUTTONS, 62 | draw_drop_down_arrows = TBSTYLE_EX_DRAWDDARROWS, --requires window_edge! 63 | double_buffer = TBSTYLE_EX_DOUBLEBUFFER, 64 | window_edge = WS_EX_WINDOWEDGE, --false by default 65 | }, 66 | __defaults = { 67 | w = 400, h = 48, 68 | align = 'top', 69 | accelerator_prefix = true, 70 | }, 71 | __init_properties = { 72 | 'image_list', 73 | }, 74 | __wm_command_handler_names = index{ 75 | }, 76 | __wm_notify_handler_names = index{ 77 | on_get_button_info = TBN_GETBUTTONINFOA, 78 | on_begin_drag = TBN_BEGINDRAG, 79 | on_end_drag = TBN_ENDDRAG, 80 | on_begin_adjust = TBN_BEGINADJUST, 81 | on_end_adjust = TBN_ENDADJUST, 82 | on_reset = TBN_RESET, 83 | on_inserting = TBN_QUERYINSERT, 84 | on_deleting = TBN_QUERYDELETE, 85 | on_change = TBN_TOOLBARCHANGE, 86 | on_help = TBN_CUSTHELP, 87 | on_dropdown = TBN_DROPDOWN, 88 | on_get_object = TBN_GETOBJECT, 89 | }, 90 | }, Control) 91 | 92 | function Toolbar:after___before_create(info, args) 93 | args.class = TOOLBARCLASSNAME 94 | end 95 | 96 | function Toolbar:after___init(info) 97 | self.items = TBItemList(self, info.items) 98 | end 99 | 100 | function Toolbar:set_image_list(iml) 101 | Toolbar_SetImageList(self.hwnd, iml.himl) 102 | end 103 | 104 | function Toolbar:get_image_list(iml) 105 | ImageLists:find(Toolbar_GetImageList(self.hwnd)) 106 | end 107 | 108 | function Toolbar:load_images(which) 109 | Toolbar_LoadImages(self.hwnd, which) 110 | end 111 | 112 | --showcase 113 | 114 | if not ... then 115 | require'winapi.showcase' 116 | local win = ShowcaseWindow() 117 | 118 | local tb = Toolbar{ 119 | parent = win, 120 | image_list = ImageList{w = 16, h = 16, masked = true, colors = '32bit'}, 121 | items = { 122 | --NOTE: using `iBitmap` instead of `i` because `i` counts from 1 123 | {iBitmap = STD_FILENEW, text = 'New'}, 124 | {iBitmap = STD_FILEOPEN, text = 'Open', style = {toggle = true}}, 125 | {iBitmap = STD_FILESAVE, text = 'Save', style = {type = 'dropdown'}}, 126 | }, 127 | anchors = {left = true, right = true}, 128 | } 129 | tb:load_images(IDB_STD_SMALL_COLOR) 130 | 131 | function tb:on_dropdown(info) 132 | print('dropdown', info.button.iBitmap, info.rect.x, info.rect.y) 133 | end 134 | 135 | --TODO: this gives "The handle is invalid." 136 | --local item = tb.items:get(3) 137 | --print(require'pp'.format(item.state)) 138 | 139 | MessageLoop() 140 | end 141 | -------------------------------------------------------------------------------- /winapi/tooltipclass.lua: -------------------------------------------------------------------------------- 1 | 2 | --oo/controls/tooltip: standard tooltip control 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.basewindowclass' 7 | require'winapi.tooltip' 8 | require'winapi.controlclass' 9 | 10 | Tooltip = subclass({ 11 | __style_bitmask = bitmask{ 12 | always_show = TTS_ALWAYSTIP, --show when owner window is inactive too 13 | no_prefix = TTS_NOPREFIX, --prevent stripping ampersants and tabs 14 | no_animate = TTS_NOANIMATE, 15 | no_fade = TTS_NOFADE, 16 | baloon = TTS_BALLOON, 17 | close_button = TTS_CLOSE, --only for baloon tooltips 18 | themed_hyperlinks = TTS_USEVISUALSTYLE, --needs TTF_PARSELINKS 19 | clip_siblings = WS_CLIPSIBLINGS, --set by Windows 20 | }, 21 | __style_ex_bitmask = bitmask{ 22 | tompost = WS_EX_TOPMOST, 23 | }, 24 | __defaults = { 25 | --style bits 26 | clip_siblings = true, --avoid warning 27 | no_prefix = true, 28 | --ex style bits 29 | topmost = true, 30 | --window properties 31 | x = CW_USEDEFAULT, 32 | y = CW_USEDEFAULT, 33 | w = CW_USEDEFAULT, 34 | h = CW_USEDEFAULT, 35 | --TOOLINFO TTF_* flags 36 | subclass = true, 37 | center_tip = false, 38 | rtl_reading = false, 39 | track = false, 40 | absolute = false, 41 | transparent = false, 42 | parse_links = false, 43 | id_is_hwnd = false, 44 | }, 45 | __wm_handler_names = index{ 46 | on_activate = TTM_ACTIVATE, --TODO: not sent 47 | --[[ --TODO: finish these 48 | on_ = TTM_SETDELAYTIME, 49 | on_ = TTM_ADDTOOL, 50 | on_ = TTM_DELTOOL, 51 | on_ = TTM_NEWTOOLRECT, 52 | on_ = TTM_RELAYEVENT, 53 | on_ = TTM_GETTOOLINFO, 54 | on_ = TTM_SETTOOLINFO, 55 | on_ = TTM_HITTEST, 56 | on_ = TTM_GETTEXT, 57 | on_ = TTM_UPDATETIPTEXT, 58 | on_ = TTM_GETTOOLCOUNT, 59 | on_ = TTM_ENUMTOOLS, 60 | on_ = TTM_GETCURRENTTOOL, 61 | on_ = TTM_WINDOWFROMPOINT, 62 | on_ = TTM_TRACKACTIVATE, 63 | on_ = TTM_TRACKPOSITION, 64 | on_ = TTM_SETTIPBKCOLOR, 65 | on_ = TTM_SETTIPTEXTCOLOR, 66 | on_ = TTM_GETDELAYTIME, 67 | on_ = TTM_GETTIPBKCOLOR, 68 | on_ = TTM_GETTIPTEXTCOLOR, 69 | on_ = TTM_SETMAXTIPWIDTH, 70 | on_ = TTM_GETMAXTIPWIDTH, 71 | on_ = TTM_SETMARGIN, 72 | on_ = TTM_GETMARGIN, 73 | on_ = TTM_POP, 74 | on_ = TTM_UPDATE, 75 | on_ = TTM_GETBUBBLESIZE, 76 | on_ = TTM_ADJUSTRECT, 77 | on_ = TTM_SETTITLE, 78 | on_ = TTM_POPUP, 79 | on_ = TTM_GETTITLE, 80 | ]] 81 | }, 82 | __wm_notify_handler_names = index{ 83 | on_get_display_info = TTN_GETDISPINFO, 84 | on_show = TTN_SHOW, 85 | on_pop = TTN_POP, 86 | on_link_click = TTN_LINKCLICK, 87 | }, 88 | __init_properties = {}, 89 | }, BaseWindow) 90 | 91 | function Tooltip:after___before_create(info, args) 92 | args.class = TOOLTIPS_CLASS 93 | args.parent = info.parent and info.parent.hwnd 94 | end 95 | 96 | local ti = TOOLINFO() 97 | 98 | function Tooltip:__after_create(info, args) 99 | SetWindowPos(self.hwnd, HWND_TOPMOST, 100 | 0, 0, 0, 0, bit.bor(SWP_NOMOVE, SWP_NOSIZE, SWP_NOACTIVATE)) 101 | TOOLINFO:reset(ti) 102 | ti.text = info.text or ffi.cast('LPWSTR', -1) 103 | ti.flagbits = info 104 | ti.hwnd = args.parent 105 | ti.rect = info.rect or info.parent.client_rect 106 | checktrue(SNDMSG(self.hwnd, TTM_ADDTOOL, 0, ffi.cast('void*', ti))) 107 | end 108 | 109 | function Tooltip:get_parent() 110 | return Windows:find(GetWindowOwner(self.hwnd)) 111 | end 112 | 113 | function Tooltip:set_rect(r) 114 | TOOLINFO:reset(ti) 115 | ti.hwnd = self.parent.hwnd 116 | ti.rect = r 117 | SNDMSG(self.hwnd, TTM_NEWTOOLRECT, 0, ffi.cast('void*', ti)) 118 | end 119 | 120 | function Tooltip:set_active(active) 121 | SNDMSG(self.hwnd, TTM_ACTIVATE, active and 1 or 0, 0) 122 | end 123 | 124 | function Tooltip:set_text(text) 125 | TOOLINFO:reset(ti) 126 | ti.hwnd = self.parent.hwnd 127 | ti.text = text 128 | SNDMSG(self.hwnd, TTM_UPDATETIPTEXT, 0, ffi.cast('void*', ti)) 129 | end 130 | 131 | --showcase ------------------------------------------------------------------- 132 | 133 | if not ... then 134 | require'winapi.showcase' 135 | local window = ShowcaseWindow{w=300,h=200} 136 | local t1 = Tooltip{parent = window} --, text='xxxx'}--, visible = false}--, text = 'Hellooo!'} 137 | 138 | local n = 10 139 | function t1:on_get_display_info(nmt) 140 | print'on_get_display_info' 141 | n = n - 1 142 | nmt.text = string.format('H%s!!!!', ('o'):rep(n)) 143 | nmt.uFlags = 0 144 | end 145 | 146 | function t1:on_show() 147 | print'on_show' 148 | end 149 | 150 | function t1:on_activate() 151 | print'on_activate' 152 | end 153 | 154 | function window:on_mouse_move(mx, my) 155 | t1.rect = t1.parent.client_rect 156 | n = n + .001 157 | --t1.text = string.format('H%s!!!!', ('o'):rep(math.floor(n))) 158 | t1.active = mx < window.client_w / 2 159 | end 160 | 161 | t1.active = false 162 | --t1.text = 'xx' 163 | 164 | MessageLoop() 165 | end 166 | -------------------------------------------------------------------------------- /winapi/trackbar.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/controls/trackbar: trackbar control 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.window' 7 | require'winapi.comctl' 8 | 9 | --creation 10 | 11 | TRACKBAR_CLASS = 'msctls_trackbar32' 12 | 13 | TBS_AUTOTICKS = 0x0001 14 | TBS_VERT = 0x0002 15 | TBS_HORZ = 0x0000 16 | TBS_TOP = 0x0004 17 | TBS_BOTTOM = 0x0000 18 | TBS_LEFT = 0x0004 19 | TBS_RIGHT = 0x0000 20 | TBS_BOTH = 0x0008 21 | TBS_NOTICKS = 0x0010 22 | TBS_ENABLESELRANGE = 0x0020 23 | TBS_FIXEDLENGTH = 0x0040 24 | TBS_NOTHUMB = 0x0080 25 | TBS_TOOLTIPS = 0x0100 26 | TBS_REVERSED = 0x0200 27 | TBS_DOWNISLEFT = 0x0400 28 | TBS_NOTIFYBEFOREMOVE = 0x0800 29 | TBS_TRANSPARENTBKGND = 0x1000 30 | 31 | TBM_GETPOS = (WM_USER) 32 | TBM_GETRANGEMIN = (WM_USER+1) 33 | TBM_GETRANGEMAX = (WM_USER+2) 34 | TBM_GETTIC = (WM_USER+3) 35 | TBM_SETTIC = (WM_USER+4) 36 | TBM_SETPOS = (WM_USER+5) 37 | TBM_SETRANGE = (WM_USER+6) 38 | TBM_SETRANGEMIN = (WM_USER+7) 39 | TBM_SETRANGEMAX = (WM_USER+8) 40 | TBM_CLEARTICS = (WM_USER+9) 41 | TBM_SETSEL = (WM_USER+10) 42 | TBM_SETSELSTART = (WM_USER+11) 43 | TBM_SETSELEND = (WM_USER+12) 44 | TBM_GETPTICS = (WM_USER+14) 45 | TBM_GETTICPOS = (WM_USER+15) 46 | TBM_GETNUMTICS = (WM_USER+16) 47 | TBM_GETSELSTART = (WM_USER+17) 48 | TBM_GETSELEND = (WM_USER+18) 49 | TBM_CLEARSEL = (WM_USER+19) 50 | TBM_SETTICFREQ = (WM_USER+20) 51 | TBM_SETPAGESIZE = (WM_USER+21) 52 | TBM_GETPAGESIZE = (WM_USER+22) 53 | TBM_SETLINESIZE = (WM_USER+23) 54 | TBM_GETLINESIZE = (WM_USER+24) 55 | TBM_GETTHUMBRECT = (WM_USER+25) 56 | TBM_GETCHANNELRECT = (WM_USER+26) 57 | TBM_SETTHUMBLENGTH = (WM_USER+27) 58 | TBM_GETTHUMBLENGTH = (WM_USER+28) 59 | TBM_SETTOOLTIPS = (WM_USER+29) 60 | TBM_GETTOOLTIPS = (WM_USER+30) 61 | TBM_SETTIPSIDE = (WM_USER+31) 62 | 63 | TBTS_TOP = 0 64 | TBTS_LEFT = 1 65 | TBTS_BOTTOM = 2 66 | TBTS_RIGHT = 3 67 | 68 | TBM_SETBUDDY = (WM_USER+32) -- wparam = BOOL fLeft; (or right) 69 | TBM_GETBUDDY = (WM_USER+33) -- wparam = BOOL fLeft; (or right) 70 | TBM_SETPOSNOTIFY = (WM_USER+34) 71 | 72 | TBM_SETUNICODEFORMAT = CCM_SETUNICODEFORMAT 73 | TBM_GETUNICODEFORMAT = CCM_GETUNICODEFORMAT 74 | 75 | TB_LINEUP = 0 76 | TB_LINEDOWN = 1 77 | TB_PAGEUP = 2 78 | TB_PAGEDOWN = 3 79 | TB_THUMBPOSITION = 4 80 | TB_THUMBTRACK = 5 81 | TB_TOP = 6 82 | TB_BOTTOM = 7 83 | TB_ENDTRACK = 8 84 | 85 | TBCD_TICS = 0x0001 86 | TBCD_THUMB = 0x0002 87 | TBCD_CHANNEL = 0x0003 88 | 89 | TRBN_FIRST = (0ULL-1501ULL) 90 | TRBN_THUMBPOSCHANGING = (TRBN_FIRST-1) 91 | 92 | -- Structure for Trackbar's TRBN_THUMBPOSCHANGING notification 93 | ffi.cdef[[ 94 | typedef struct tagTRBTHUMBPOSCHANGING 95 | { 96 | NMHDR hdr; 97 | DWORD dwPos; 98 | int nReason; 99 | } NMTRBTHUMBPOSCHANGING; 100 | ]] 101 | -------------------------------------------------------------------------------- /winapi/trackbarclass.lua: -------------------------------------------------------------------------------- 1 | 2 | --oo/controls/trackbar: trackbar control 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.trackbar' 7 | require'winapi.controlclass' 8 | 9 | Trackbar = { 10 | __style_bitmask = bitmask{ 11 | ticks = { 12 | auto = TBS_AUTOTICKS, 13 | none = TBS_NOTICKS, 14 | }, 15 | orientation = { 16 | vertical = TBS_VERT, 17 | horizontal = TBS_HORZ, 18 | }, 19 | ticks_orientation = { 20 | top = TBS_TOP, 21 | bottom = TBS_BOTTOM, 22 | left = TBS_LEFT, 23 | right = TBS_RIGHT, 24 | both = TBS_BOTH, 25 | }, 26 | range = TBS_ENABLESELRANGE, 27 | fixed_length = TBS_FIXEDLENGTH, 28 | thumb = { 29 | [true] = 0, 30 | [false] = TBS_NOTHUMB, 31 | }, 32 | tooltips = TBS_TOOLTIPS, 33 | reversed = TBS_REVERSED, 34 | vertical_reversed = TBS_DOWNISLEFT, 35 | notify_before_remove = TBS_NOTIFYBEFOREMOVE, 36 | transparent_background = TBS_TRANSPARENTBKGND, 37 | }, 38 | __defaults = { 39 | w = 100, 40 | h = 40, 41 | }, 42 | __init_properties = { 43 | 'pos', 'sel_start', 'sel_end', 44 | 'min_range', 'max_range', 45 | 'line_size', 'page_size', 46 | 'tick_freq', 47 | }, 48 | } 49 | 50 | subclass(Trackbar, Control) 51 | 52 | function Trackbar:after___before_create(info, args) 53 | args.class = TRACKBAR_CLASS 54 | end 55 | 56 | function Trackbar:set_pos (pos, redraw) SNDMSG(self.hwnd, TBM_SETPOS , redraw ~= false, pos) end 57 | function Trackbar:set_sel_start (pos, redraw) SNDMSG(self.hwnd, TBM_SETSELSTART, redraw ~= false, pos) end 58 | function Trackbar:set_sel_end (pos, redraw) SNDMSG(self.hwnd, TBM_SETSELEND , redraw ~= false, pos) end 59 | function Trackbar:set_min_range (pos, redraw) SNDMSG(self.hwnd, TBM_SETRANGEMIN, redraw ~= false, pos) end 60 | function Trackbar:set_max_range (pos, redraw) SNDMSG(self.hwnd, TBM_SETRANGEMAX, redraw ~= false, pos) end 61 | function Trackbar:set_line_size (size) SNDMSG(self.hwnd, TBM_SETLINESIZE, 0, size) end 62 | function Trackbar:set_page_size (size) SNDMSG(self.hwnd, TBM_SETPAGESIZE, 0, size) end 63 | function Trackbar:set_tick (pos) return SNDMSG(self.hwnd, TBM_SETTIC , 0, pos) == 1 end 64 | function Trackbar:set_tick_freq (freq) SNDMSG(self.hwnd, TBM_SETTICFREQ , freq, 0) end 65 | function Trackbar:clear_sel (redraw) SNDMSG(self.hwnd, TBM_CLEARSEL , redraw ~= false, 0) end 66 | function Trackbar:remove_ticks (redraw) SNDMSG(self.hwnd, TBM_CLEARTICS , redraw ~= false, 0) end 67 | function Trackbar:set_buddy (p, win) SNDMSG(self.hwnd, TBM_SETBUDDY , p=='l' or p=='t', win.hwnd) end 68 | 69 | function Trackbar:get_pos () return SNDMSG(self.hwnd, TBM_GETPOS , 0, 0) end 70 | function Trackbar:get_sel_start () return SNDMSG(self.hwnd, TBM_GETSELSTART, 0, 0) end 71 | function Trackbar:get_sel_end () return SNDMSG(self.hwnd, TBM_SETSELEND , 0, 0) end 72 | function Trackbar:get_min_range () return SNDMSG(self.hwnd, TBM_GETRANGEMIN, 0, 0) end 73 | function Trackbar:get_max_range () return SNDMSG(self.hwnd, TBM_GETRANGEMAX, 0, 0) end 74 | function Trackbar:get_line_size () return SNDMSG(self.hwnd, TBM_GETLINESIZE, 0, 0) end 75 | function Trackbar:get_page_size () return SNDMSG(self.hwnd, TBM_GETPAGESIZE, 0, 0) end 76 | function Trackbar:get_tick_count () return SNDMSG(self.hwnd, TBM_GETNUMTICS , 0, 0) end 77 | function Trackbar:get_tick (i) return SNDMSG(self.hwnd, TBM_GETTIC, countfrom0(i), 0) end 78 | function Trackbar:get_buddy (p) return SNDMSG(self.hwnd, TBM_GETBUDDY, p=='l' or p=='t', 0) end 79 | 80 | --[[ 81 | TBM_GETPTICS = (WM_USER+14) 82 | TBM_GETTICPOS = (WM_USER+15) 83 | TBM_GETTHUMBRECT = (WM_USER+25) 84 | TBM_GETCHANNELRECT = (WM_USER+26) 85 | TBM_SETTHUMBLENGTH = (WM_USER+27) 86 | TBM_GETTHUMBLENGTH = (WM_USER+28) 87 | TBM_SETTOOLTIPS = (WM_USER+29) 88 | TBM_GETTOOLTIPS = (WM_USER+30) 89 | TBM_SETTIPSIDE = (WM_USER+31) 90 | ]] 91 | -------------------------------------------------------------------------------- /winapi/uuid.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/system/uuid: UUID API from rpcdce.h 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.rpc' 7 | 8 | ffi.cdef[[ 9 | RPC_STATUS UuidCreate (UUID* Uuid); 10 | RPC_STATUS UuidCreateSequential (UUID* Uuid); 11 | RPC_STATUS UuidToStringW (const UUID* Uuid, RPC_WSTR* StringUuid); 12 | RPC_STATUS UuidFromStringW (RPC_WSTR StringUuid, UUID* Uuid); 13 | signed int UuidCompare (UUID* Uuid1, UUID* Uuid2, RPC_STATUS* Status); 14 | RPC_STATUS UuidCreateNil (UUID* NilUuid); 15 | int UuidEqual (UUID* Uuid1, UUID* Uuid2, RPC_STATUS* Status); 16 | unsigned short UuidHash (UUID* Uuid, RPC_STATUS* Status); 17 | int UuidIsNil (UUID* Uuid, RPC_STATUS* Status); 18 | ]] 19 | 20 | function UuidCreate() 21 | local uuid = types.UUID() 22 | checkz(rpc.UuidCreate(uuid)) 23 | return uuid 24 | end 25 | 26 | function UuidCreateSequential() 27 | local uuid = types.UUID() 28 | checkz(rpc.UuidCreateSequential(uuid)) 29 | return uuid 30 | end 31 | 32 | function UuidCreateNil() 33 | local uuid = types.UUID() 34 | checkz(rpc.UuidCreateNil(uuid)) 35 | return uuid 36 | end 37 | 38 | function UuidFromString(s, uuid) 39 | uuid = types.UUID(uuid) 40 | checkz(rpc.UuidFromStringW(wcs(s), uuid)) 41 | return uuid 42 | end 43 | 44 | function UuidToString(uuid, pws) 45 | pws = pws or ffi.new('RPC_WSTR[1]') 46 | checkz(rpc.UuidToStringW(uuid, pws)) 47 | local s = mbs(pws[0]) 48 | rpc.RpcStringFreeW(pws) 49 | return s 50 | end 51 | 52 | function UuidCompare(uuid1, uuid2, status) --returns -1, 0, 1 for <, ==, > 53 | status = status or ffi.new'RPC_STATUS[1]' 54 | local ret = rpc.UuidCompare(uuid1, uuid2, status) 55 | checkz(status[0]) 56 | return ret 57 | end 58 | 59 | function UuidEqual(uuid1, uuid2, status) 60 | status = status or ffi.new'RPC_STATUS[1]' 61 | local ret = rpc.UuidEqual(uuid1, uuid2, status) == 1 62 | checkz(status[0]) 63 | return ret 64 | end 65 | 66 | function UuidHash(uuid, status) 67 | status = status or ffi.new'RPC_STATUS[1]' 68 | local ret = rpc.UuidHash(uuid, status) 69 | checkz(status[0]) 70 | return ret 71 | end 72 | 73 | function UuidIsNil(uuid, status) 74 | status = status or ffi.new'RPC_STATUS[1]' 75 | local ret = rpc.UuidIsNil(uuid, status) == 1 76 | checkz(status[0]) 77 | return ret 78 | end 79 | 80 | ffi.metatype('GUID', { 81 | __tostring = UuidToString, 82 | __eq = UuidEqual, 83 | __index = { 84 | compare = UuidCompare, 85 | hash = UuidHash, 86 | is_nil = UuidIsNil, 87 | }, 88 | }) 89 | 90 | if not ... then 91 | print(UuidCreate()) 92 | print(UuidCreateSequential()) 93 | print(UuidCreate():hash()) 94 | 95 | assert(#tostring(UuidCreate()) == 36) 96 | assert(#tostring(UuidCreateSequential()) == 36) 97 | assert(tostring(UuidCreateNil()) == '00000000-0000-0000-0000-000000000000') 98 | 99 | assert(UuidCreate():is_nil() == false) 100 | assert(UuidCreateSequential():is_nil() == false) 101 | assert(UuidCreateNil():is_nil() == true) 102 | assert(UuidCreateSequential():compare(UuidCreateSequential()) == -1) 103 | assert(UuidCreate() ~= UuidCreate()) 104 | end 105 | 106 | -------------------------------------------------------------------------------- /winapi/vobject.md: -------------------------------------------------------------------------------- 1 | --- 2 | tagline: object model for winapi windows and controls 3 | --- 4 | 5 | ## `require'winapi.vobject'` 6 | 7 | This module defines a single-inheritance object model with 8 | virtual properties, method-overriding hooks and [events]. 9 | 10 | ## Subclassing and instantiation protocol 11 | 12 | At the core there's on an user API and an implementation protocol 13 | for implementing a single-inheritance object model. 14 | 15 | The user API is comprised of 2 functions: 16 | 17 | * `subclass(derived[, super]) -> derived` 18 | * `isinstance(object, class) -> true|false` 19 | 20 | `subclass()` calls `super:__subclass(derived)` to perform the actual 21 | subclassing and returns `derived`. This means that each class is free 22 | to define how subclassing should be performed (copy all members to 23 | the derived class aka static inheritance, assign an `__index` 24 | metamethod aka dynamic inheritance, etc.). If the super class doesn't 25 | define a `__subclass` method, nothing gets inherited and `derived` 26 | is returned untouched. 27 | 28 | `isinstance()` calls `object:__super()` recursively until it matches 29 | the wanted class. Classes must implement `__super()` for this to work. 30 | 31 | Note that there's no API or implementation protocol for instantiation. 32 | The root class will define these. 33 | 34 | ## The root object 35 | 36 | The `VObject` class is the base class of every other class in winapi. 37 | 38 | VObject implements the single-inheritance object model. This means that 39 | you can use `subclass()` to subclass from `VObject` and `isinstance()` 40 | on every instance or subclass of `VObject`. 41 | 42 | VObject It also defines how instantiation works: calling `Foo(args...)` creates 43 | an instance of `Foo`, calls `__init(self, args...)` on it, and returns it. 44 | 45 | VObject instances: 46 | 47 | * inhert class fields dynamically 48 | * inherit instance metamethods statically 49 | * inherit super class fields dynamically 50 | * inherit super class metamethods statically 51 | 52 | ## Virtual properties 53 | 54 | Virtual properties means that: 55 | 56 | * `x = foo.bar` calls `foo:get_bar() -> x`, and 57 | * `foo.bar = x` calls `foo:set_bar(x)`. 58 | 59 | If there's a `get_bar` but no `set_bar`, doing `foo.bar = x` raises an error. 60 | These are "read-only properties". 61 | 62 | ### Generating properties in bulk 63 | 64 | Calling `Foo:__gen_vproperties({foo = true, bar = true}, getter, setter)` 65 | generates getters and setters for `foo` and `bar` properties 66 | based on `getter` and `setter` such that: 67 | 68 | get_foo(self) calls getter(self, 'foo') 69 | get_bar(self) calls getter(self, 'bar') 70 | set_foo(self, val) calls setter(self, 'foo', val) 71 | set_bar(self, val) calls setter(self, 'bar', val) 72 | 73 | ### API 74 | 75 | ------------------------------------------- ---------------------------------------------------------- 76 | __subclassing__ 77 | `__subclass(class) -> class` subclassing constructor 78 | `__gen_vproperties(names, getter, setter)` generate virtual properties in bulk 79 | __instantiation__ 80 | `__init(...)` stub object constructor (implemented in concrete classes) 81 | __introspection__ 82 | `__super() -> class` access the super class 83 | `__supers() -> iter() -> class` iterate over the class hierarchy 84 | `__allpairs() -> iter() -> k, v, class` iterate instance and class members recursively 85 | `__pairs() -> iter() -> k, v` iterate the flattened map of instance and class members 86 | `__properties() -> iter() -> k, class` iterate the flattened map of instance and class members 87 | `__vproperties() -> iter() -> prop, info` iterate all virtual properties 88 | ------------------------------------------- ---------------------------------------------------------- 89 | -------------------------------------------------------------------------------- /winapi/volman.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/volman: Volume Management API 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | 7 | ffi.cdef[[ 8 | BOOL GetVolumeInformationW( 9 | LPCWSTR lpRootPathName, 10 | LPWSTR lpVolumeNameBuffer, 11 | DWORD nVolumeNameSize, 12 | LPDWORD lpVolumeSerialNumber, 13 | LPDWORD lpMaximumComponentLength, 14 | LPDWORD lpFileSystemFlags, 15 | LPWSTR lpFileSystemNameBuffer, 16 | DWORD nFileSystemNameSize 17 | ); 18 | ]] 19 | 20 | --lpFileSystemFlags bits 21 | FILE_CASE_SENSITIVE_SEARCH = 0x00000001 22 | FILE_CASE_PRESERVED_NAMES = 0x00000002 23 | FILE_DAX_VOLUME = 0x20000000 24 | FILE_FILE_COMPRESSION = 0x00000010 25 | FILE_NAMED_STREAMS = 0x00040000 26 | FILE_PERSISTENT_ACLS = 0x00000008 27 | FILE_READ_ONLY_VOLUME = 0x00080000 28 | FILE_SEQUENTIAL_WRITE_ONCE = 0x00100000 29 | FILE_SUPPORTS_ENCRYPTION = 0x00020000 30 | FILE_SUPPORTS_EXTENDED_ATTRIBUTES = 0x00800000 31 | FILE_SUPPORTS_HARD_LINKS = 0x00400000 32 | FILE_SUPPORTS_OBJECT_IDS = 0x00010000 33 | FILE_UNICODE_ON_DISK = 0x00000004 34 | FILE_VOLUME_QUOTAS = 0x00000020 35 | FILE_SUPPORTS_SPARSE_FILES = 0x00000040 36 | FILE_SUPPORTS_REPARSE_POINTS = 0x00000080 37 | FILE_SUPPORTS_REMOTE_STORAGE = 0x00000100 38 | FILE_VOLUME_IS_COMPRESSED = 0x00008000 39 | FILE_SUPPORTS_TRANSACTIONS = 0x00200000 40 | FILE_SUPPORTS_OPEN_BY_FILE_ID = 0x01000000 41 | FILE_SUPPORTS_USN_JOURNAL = 0x02000000 42 | 43 | local name_buf, serial_buf, len_buf, flags_buf, fsname_buf 44 | function GetVolumeInformation(path) 45 | local MAX_PATH = 260 46 | if not name_buf then 47 | name_buf = WCS(MAX_PATH+1) 48 | serial_buf = ffi.new'DWORD[1]' 49 | len_buf = ffi.new'DWORD[1]' 50 | flags_buf = ffi.new'DWORD[1]' 51 | fsname_buf = WCS(MAX_PATH+1) 52 | end 53 | local last_errmode = SetErrorMode(SEM_FAILCRITICALERRORS) 54 | local ret = C.GetVolumeInformationW(wcs(path), 55 | name_buf, MAX_PATH+1, 56 | serial_buf, len_buf, flags_buf, 57 | fsname_buf, MAX_PATH+1 58 | ) 59 | SetErrorMode(last_errmode) 60 | checknz(ret) 61 | return { 62 | volume_name = mbs(name_buf), 63 | volume_serial = serial_buf[0], 64 | max_component_length = len_buf[0], 65 | filesystem_flags = flags_buf[0], 66 | filesystem_name = mbs(fsname_buf), 67 | } 68 | end 69 | 70 | if not ... then 71 | require'pp'(GetVolumeInformation'C:\\') 72 | end 73 | -------------------------------------------------------------------------------- /winapi/waitemlistclass.lua: -------------------------------------------------------------------------------- 1 | 2 | --oo/controls/waitemlist: accelerator item list 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.itemlist' 7 | require'winapi.accelerator' 8 | 9 | local modifier_masks = { 10 | shift = FSHIFT, 11 | control = FCONTROL, 12 | ctrl = FCONTROL, 13 | alt = FALT, 14 | } 15 | 16 | local function parse_hotkey(s) --parse hotkeys like "shift + alt + F5" or "ctrl + C"; note: say "C" instead of "shift + c" 17 | local key, modifiers = nil, 0 18 | for k in s:gmatch'([^%+]+)' do 19 | k = trim(k) 20 | local m = modifier_masks[k:lower()] 21 | if m then 22 | modifiers = bit.bor(modifiers, m) 23 | elseif #k == 1 then 24 | key = k 25 | else 26 | key = flags('VK_'..k:upper()) 27 | end 28 | end 29 | assert(key, 'invalid hotkey') 30 | return key, modifiers 31 | end 32 | 33 | 34 | WAItemList = class(ItemList) 35 | 36 | function WAItemList:after___init(window) 37 | self.__items = {} 38 | end 39 | 40 | function WAItemList:checkrange(i) 41 | assert(i >= 1 and i <= #self.__items + 1, 'index out of range') 42 | end 43 | 44 | function WAItemList:__changed() 45 | if self.haccel then 46 | DestroyAcceleratorTable(self.haccel) 47 | self.haccel = nil 48 | end 49 | local t = {} 50 | for i,v in ipairs(self.__items) do 51 | local key, modifiers = parse_hotkey(v.hotkey) 52 | t[i] = ACCEL{id = i, key = key, modifiers = modifiers} 53 | end 54 | self.haccel = CreateAcceleratorTable(t) 55 | end 56 | 57 | function WAItemList:add(i, item) 58 | if not item then i,item = nil,i end --i is optional 59 | if i then 60 | self:checkrange(i) 61 | table.insert(self.__items, i, item) 62 | else 63 | table.insert(self.__items, item) 64 | end 65 | self:__changed() 66 | end 67 | 68 | function WAItemList:add_items(items) 69 | if not items then return end 70 | for i=1,#items do 71 | table.insert(self.__items, items[i]) 72 | end 73 | self:__changed() 74 | end 75 | 76 | function WAItemList:remove(i) 77 | self:checkrange(i) 78 | table.remove(self.__items, i) 79 | self:__changed() 80 | end 81 | 82 | function WAItemList:set(i, item) 83 | self:checkrange(i) 84 | self.__items[i] = item 85 | self:__changed() 86 | end 87 | 88 | function WAItemList:get(i) 89 | self:checkrange(i) 90 | return self.__items[i] 91 | end 92 | 93 | function WAItemList:get_count() 94 | return #self.__items 95 | end 96 | 97 | function WAItemList:clear() 98 | self.__items = {} 99 | self:__changed() 100 | end 101 | 102 | function WAItemList:WM_COMMAND(i) 103 | self:checkrange(i) 104 | self.__items[i].handler(self.window) 105 | end 106 | 107 | -------------------------------------------------------------------------------- /winapi/winbase.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/system/winbase: winbase.h. incomplete :) 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | 7 | FILE_FLAG_WRITE_THROUGH = 0x80000000 8 | FILE_FLAG_OVERLAPPED = 0x40000000 9 | FILE_FLAG_NO_BUFFERING = 0x20000000 10 | FILE_FLAG_RANDOM_ACCESS = 0x10000000 11 | FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000 12 | FILE_FLAG_DELETE_ON_CLOSE = 0x04000000 13 | FILE_FLAG_BACKUP_SEMANTICS = 0x02000000 14 | FILE_FLAG_POSIX_SEMANTICS = 0x01000000 15 | FILE_FLAG_SESSION_AWARE = 0x00800000 16 | FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000 17 | FILE_FLAG_OPEN_NO_RECALL = 0x00100000 18 | FILE_FLAG_FIRST_PIPE_INSTANCE = 0x00080000 19 | FILE_FLAG_OPEN_REQUIRING_OPLOCK = 0x00040000 --Win8+ 20 | 21 | INVALID_HANDLE_VALUE = ffi.cast('HANDLE', -1) 22 | 23 | ffi.cdef[[ 24 | typedef struct _SECURITY_ATTRIBUTES { 25 | DWORD nLength; 26 | LPVOID lpSecurityDescriptor; 27 | BOOL bInheritHandle; 28 | } SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES; 29 | 30 | DWORD GetCurrentThreadId(void); 31 | 32 | BOOL CloseHandle (HANDLE hObject); 33 | BOOL DuplicateHandle ( 34 | HANDLE hSourceProcessHandle, 35 | HANDLE hSourceHandle, 36 | HANDLE hTargetProcessHandle, 37 | LPHANDLE lpTargetHandle, 38 | DWORD dwDesiredAccess, 39 | BOOL bInheritHandle, 40 | DWORD dwOptions); 41 | 42 | BOOL GetHandleInformation (HANDLE hObject, LPDWORD lpdwFlags); 43 | BOOL SetHandleInformation (HANDLE hObject, DWORD dwMask, DWORD dwFlags); 44 | ]] 45 | 46 | GetCurrentThreadId = C.GetCurrentThreadId 47 | 48 | function CloseHandle(h) 49 | return retnz(C.CloseHandle(h)) 50 | end 51 | 52 | -------------------------------------------------------------------------------- /winapi/windowclasses.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/windows/class: WNDCLASSEX API 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | require'winapi.winuser' 7 | 8 | --register/unregister 9 | 10 | ffi.cdef[[ 11 | typedef struct tagWNDCLASSEXW { 12 | UINT cbSize; 13 | UINT _style; 14 | WNDPROC proc; 15 | int cbClsExtra; 16 | int cbWndExtra; 17 | HINSTANCE hInstance; 18 | HICON icon; 19 | HCURSOR cursor; 20 | HBRUSH background; 21 | LPCWSTR lpszMenuName; 22 | LPCWSTR lpszClassName; 23 | HICON small_icon; 24 | } WNDCLASSEXW, *PWNDCLASSEXW, *NPWNDCLASSEXW, *LPWNDCLASSEXW; 25 | 26 | ATOM RegisterClassExW(const WNDCLASSEXW *); 27 | 28 | BOOL UnregisterClassW( 29 | LPCWSTR lpClassName, 30 | HINSTANCE hInstance); 31 | 32 | ]] 33 | 34 | CS_VREDRAW = 0x0001 35 | CS_HREDRAW = 0x0002 36 | CS_DBLCLKS = 0x0008 37 | CS_OWNDC = 0x0020 38 | CS_CLASSDC = 0x0040 39 | CS_PARENTDC = 0x0080 40 | CS_NOCLOSE = 0x0200 41 | CS_SAVEBITS = 0x0800 42 | CS_BYTEALIGNCLIENT = 0x1000 43 | CS_BYTEALIGNWINDOW = 0x2000 44 | CS_GLOBALCLASS = 0x4000 45 | CS_IME = 0x00010000 46 | CS_DROPSHADOW = 0x00020000 47 | 48 | WNDCLASSEXW = struct{ 49 | ctype = 'WNDCLASSEXW', size = 'cbSize', 50 | fields = sfields{ 51 | 'name', 'lpszClassName', wcs, mbs, 52 | 'style', '_style', flags, pass, 53 | } 54 | } 55 | 56 | function RegisterClass(info) 57 | assert(info.proc ~= nil, 'proc is required') --or you'll get a crash 58 | return checknz(C.RegisterClassExW(WNDCLASSEXW(info))) 59 | end 60 | 61 | function UnregisterClass(class) 62 | if not class then return end 63 | checknz(C.UnregisterClassW(ffi.cast('LPCWSTR', wcs(MAKEINTRESOURCE(class))), nil)) 64 | end 65 | 66 | --set/get class long 67 | 68 | GCL_MENUNAME = -8 69 | GCL_HBRBACKGROUND = -10 70 | GCL_HCURSOR = -12 71 | GCL_HICON = -14 72 | GCL_HMODULE = -16 73 | GCL_CBWNDEXTRA = -18 74 | GCL_CBCLSEXTRA = -20 75 | GCL_WNDPROC = -24 76 | GCL_STYLE = -26 77 | GCW_ATOM = -32 78 | GCL_HICONSM = -34 79 | 80 | if ffi.abi'64bit' then 81 | ffi.cdef[[ 82 | LONG_PTR SetClassLongPtrW(HWND hWnd, int nIndex, LONG_PTR dwNewLong); 83 | LONG_PTR GetClassLongPtrW(HWND hWnd, int nIndex); 84 | ]] 85 | SetClassLongW = C.SetClassLongPtrW 86 | GetClassLongW = C.GetClassLongPtrW 87 | else --32bit 88 | ffi.cdef[[ 89 | LONG SetClassLongW(HWND hWnd, int nIndex, LONG dwNewLong); 90 | LONG GetClassLongW(HWND hWnd, int nIndex); 91 | ]] 92 | SetClassLongW = C.SetClassLongW 93 | GetClassLongW = C.GetClassLongW 94 | end 95 | 96 | function SetClassLong(hwnd, GCL, long) 97 | callnz2(SetClassLongW, hwnd, flags(GCL), ffi.cast('LONG', long)) 98 | end 99 | 100 | function GetClassLong(hwnd, GCL) return GetClassLongW(hwnd, flags(GCL)) end 101 | 102 | -- Get/SetClassLong wrappers (don't look them up in the docs) 103 | 104 | function GetClassStyle(hwnd) return tonumber(GetClassLong(hwnd, GCL_STYLE)) end 105 | function SetClassStyle(hwnd, style) SetClassLong(hwnd, GCL_STYLE, flags(style)) end 106 | 107 | function GetClassIcon(hwnd) return ptr(ffi.cast('HICON', GetClassLong(hwnd, GCL_HICON))) end 108 | function SetClassIcon(hwnd, icon) SetClassLong(hwnd, GCL_HICON, icon) end 109 | 110 | function GetClassSmallIcon(hwnd) return ptr(ffi.cast('HICON', GetClassLong(hwnd, GCL_HICONSM))) end 111 | function SetClassSmallIcon(hwnd, icon) SetClassLong(hwnd, GCL_HICONSM, icon) end 112 | 113 | function GetClassCursor(hwnd) return ptr(ffi.cast('HCURSOR', GetClassLong(hwnd, GCL_HCURSOR))) end 114 | function SetClassCursor(hwnd, cursor) SetClassLong(hwnd, GCL_HCURSOR, cursor) end 115 | 116 | function GetClassBackground(hwnd) return ptr(ffi.cast('HBRUSH', GetClassLong(hwnd, GCL_HBRBACKGROUND))) end 117 | function SetClassBackground(hwnd, bg) SetClassLong(hwnd, GCL_HBRBACKGROUND, bg) end 118 | 119 | --showcase 120 | 121 | if not ... then 122 | package.loaded['winapi.windowclasses'] = true --prevent double-loading by winapi.window 123 | require'winapi.color' 124 | require'winapi.cursor' 125 | require'winapi.window' --for DefWindowProc 126 | local class = print(RegisterClass{ 127 | name='MyClass', 128 | style = bit.bor(CS_HREDRAW, CS_VREDRAW), 129 | background = COLOR_WINDOW, 130 | cursor = LoadCursor(IDC_ARROW), 131 | proc = DefWindowProc, 132 | }) 133 | UnregisterClass(class) 134 | end 135 | 136 | -------------------------------------------------------------------------------- /winapi/winnt.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/system/winnt: don't know the scope of this yet. 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | 7 | STANDARD_RIGHTS_REQUIRED = 0x000F0000 8 | STANDARD_RIGHTS_ALL = 0x001F0000 9 | 10 | SECTION_QUERY = 0x0001 11 | SECTION_MAP_WRITE = 0x0002 12 | SECTION_MAP_READ = 0x0004 13 | SECTION_MAP_EXECUTE = 0x0008 14 | SECTION_EXTEND_SIZE = 0x0010 15 | SECTION_MAP_EXECUTE_EXPLICIT = 0x0020 16 | SECTION_ALL_ACCESS = bit.bor(STANDARD_RIGHTS_REQUIRED, 17 | SECTION_QUERY, SECTION_MAP_WRITE, SECTION_MAP_READ, SECTION_MAP_EXECUTE, 18 | SECTION_EXTEND_SIZE) 19 | 20 | PAGE_NOACCESS = 0x01 21 | PAGE_READONLY = 0x02 22 | PAGE_READWRITE = 0x04 23 | PAGE_WRITECOPY = 0x08 24 | PAGE_EXECUTE = 0x10 25 | PAGE_EXECUTE_READ = 0x20 --XP SP2+ 26 | PAGE_EXECUTE_READWRITE = 0x40 --XP SP2+ 27 | PAGE_EXECUTE_WRITECOPY = 0x80 --Vista SP1+ 28 | PAGE_GUARD = 0x100 29 | PAGE_NOCACHE = 0x200 30 | PAGE_WRITECOMBINE = 0x400 31 | 32 | SEC_FILE = 0x00800000 33 | SEC_IMAGE = 0x01000000 34 | SEC_PROTECTED_IMAGE = 0x02000000 35 | SEC_RESERVE = 0x04000000 36 | SEC_COMMIT = 0x08000000 37 | SEC_NOCACHE = 0x10000000 38 | SEC_WRITECOMBINE = 0x40000000 39 | SEC_LARGE_PAGES = 0x80000000 40 | 41 | GENERIC_READ = 0x80000000 42 | GENERIC_WRITE = 0x40000000 43 | GENERIC_EXECUTE = 0x20000000 44 | GENERIC_ALL = 0x10000000 45 | 46 | FILE_SHARE_READ = 0x00000001 47 | FILE_SHARE_WRITE = 0x00000002 48 | FILE_SHARE_DELETE = 0x00000004 49 | FILE_SHARE_VALID_FLAGS = 0x00000007 50 | 51 | FILE_ATTRIBUTE_READONLY = 0x00000001 52 | FILE_ATTRIBUTE_HIDDEN = 0x00000002 53 | FILE_ATTRIBUTE_SYSTEM = 0x00000004 54 | FILE_ATTRIBUTE_DIRECTORY = 0x00000010 55 | FILE_ATTRIBUTE_ARCHIVE = 0x00000020 56 | FILE_ATTRIBUTE_DEVICE = 0x00000040 57 | FILE_ATTRIBUTE_NORMAL = 0x00000080 58 | FILE_ATTRIBUTE_TEMPORARY = 0x00000100 59 | FILE_ATTRIBUTE_SPARSE_FILE = 0x00000200 60 | FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400 61 | FILE_ATTRIBUTE_COMPRESSED = 0x00000800 62 | FILE_ATTRIBUTE_OFFLINE = 0x00001000 63 | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x00002000 64 | FILE_ATTRIBUTE_ENCRYPTED = 0x00004000 65 | FILE_ATTRIBUTE_VIRTUAL = 0x00010000 66 | -------------------------------------------------------------------------------- /winapi/winuser.lua: -------------------------------------------------------------------------------- 1 | 2 | --types/winuser: winuser types and macros from multiple headers 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | setfenv(1, require'winapi') 6 | 7 | --constants 8 | 9 | IMAGE_BITMAP = 0 10 | IMAGE_ICON = 1 11 | IMAGE_CURSOR = 2 12 | IMAGE_ENHMETAFILE = 3 13 | 14 | DLGC_WANTARROWS = 0x0001 -- Control wants arrow keys 15 | DLGC_WANTTAB = 0x0002 -- Control wants tab keys 16 | DLGC_WANTALLKEYS = 0x0004 -- Control wants all keys 17 | DLGC_WANTMESSAGE = 0x0004 -- Pass message to control 18 | DLGC_HASSETSEL = 0x0008 -- Understands EM_SETSEL message 19 | DLGC_DEFPUSHBUTTON = 0x0010 -- Default pushbutton 20 | DLGC_UNDEFPUSHBUTTON= 0x0020 -- Non-default pushbutton 21 | DLGC_RADIOBUTTON = 0x0040 -- Radio button 22 | DLGC_WANTCHARS = 0x0080 -- Want WM_CHAR messages 23 | DLGC_STATIC = 0x0100 -- Static item: don't include 24 | DLGC_BUTTON = 0x2000 -- Button item: can be checked 25 | 26 | --macros 27 | 28 | function MAKELONG(lo,hi) 29 | return bit.bor(bit.band(lo, 0xffff), bit.lshift(bit.band(hi, 0xffff), 16)) 30 | end 31 | 32 | MAKEWPARAM = MAKELONG 33 | MAKELPARAM = MAKELONG 34 | MAKELRESULT = MAKELONG 35 | 36 | function MAKEINTRESOURCE(i) 37 | if type(i) == 'number' then 38 | return ffi.cast('LPWSTR', ffi.cast('WORD', i)) 39 | end 40 | return i 41 | end 42 | 43 | function IS_INTRESOURCE(i) 44 | error'NYI' --((((ULONG_PTR)(_r)) >> 16) == 0) 45 | end 46 | 47 | --types 48 | 49 | SIZE = types.SIZE 50 | POINT = types.POINT 51 | RECT = types.RECT 52 | 53 | local function struct_tostring(fields) 54 | return function(t) 55 | local s = fields[1]..'{'..t[fields[2]] 56 | for i=3,#fields do 57 | s = s..','..t[fields[i]] 58 | end 59 | return s..'}' 60 | end 61 | end 62 | 63 | ffi.metatype('SIZE', {__tostring = struct_tostring{'SIZE','w','h'}}) 64 | ffi.metatype('POINT', {__tostring = struct_tostring{'POINT','x','y'}}) 65 | 66 | --NOTE: there's no __newindex for virtual fields because Lua's 67 | --assignment order in multiple assignment is undefined (and even 68 | --if it were defined, it would be significant which is a bug nest). 69 | ffi.metatype('RECT', { 70 | __tostring = struct_tostring{'RECT','x1','y1','x2','y2'}, 71 | __index = function(r,k) 72 | if k == 'w' then return r.x2 - r.x1 end 73 | if k == 'h' then return r.y2 - r.y1 end 74 | end, 75 | }) 76 | -------------------------------------------------------------------------------- /winapi/wmapp.lua: -------------------------------------------------------------------------------- 1 | 2 | --proc/windows/wmapp: user-defined (WM_APP+N) messages 3 | --Written by Cosmin Apreutesei. Public Domain. 4 | 5 | --this module is loaded by `winapi.window` module. 6 | --WM_APP messages are shared resources. this module keeps track of them 7 | --and allows you to acquire and release them as needed. 8 | setfenv(1, require'winapi') 9 | 10 | assert(WM_APP, 'winapi.window not loaded') 11 | 12 | local codes = {} --sparse array of codes 13 | local min_code = WM_APP + 1 14 | local max_code = min_code - 1 --start with no slots 15 | 16 | local function add_message() 17 | --scan array for gaps. 18 | for code = min_code, max_code do 19 | if not codes[code] then 20 | codes[code] = true 21 | return code 22 | end 23 | end 24 | --no gaps, grow array. 25 | max_code = max_code + 1 26 | codes[max_code] = true 27 | return max_code 28 | end 29 | 30 | local function remove_message(code) 31 | assert(code >= min_code and code <= max_code) --not an acquired code 32 | codes[code] = nil 33 | --released the last code: shrink array. 34 | if code == max_code then 35 | max_code = max_code - 1 36 | end 37 | end 38 | 39 | function register_message(name, code) 40 | code = code or add_message() 41 | if name then 42 | WM_NAMES[code] = name 43 | rawset(_M, name, code) 44 | end 45 | return code 46 | end 47 | 48 | local function unregister_message(code) 49 | local name 50 | if type(code) == 'string' then 51 | name, code = code, rawget(_M, code) 52 | else 53 | name, code = WM_NAMES[code], code 54 | end 55 | remove_message(code) 56 | if name then 57 | WM_NAMES[code] = nil 58 | rawset(_M, name, nil) 59 | end 60 | end 61 | 62 | --usage: 63 | --WM_FOO = register_message'WM_FOO' 64 | --unregister_message(WM_FOO) 65 | -------------------------------------------------------------------------------- /winapi_design.md: -------------------------------------------------------------------------------- 1 | --- 2 | tagline: technical documentation 3 | --- 4 | 5 | ## Structure 6 | 7 | The library publishes a procedural API that mimics the windows API, and an 8 | object API for creating windows and controls. Both APIs share the same 9 | namespace, which is the table returned by `require'winapi'`. 10 | 11 | Interactivity (windows message processing) is handled in the object layer 12 | because it needs to keep state. Dispatching of messages to child controls 13 | is implemented in the object layer. The object layer also provides additional 14 | features like anchor-based layouting. There's generally little reason to use 15 | the procedural API directly for managing windows and controls except for say, 16 | implementing a different object API. 17 | 18 | ## Scope 19 | 20 | Current work is based on Windows 7 SDK headers, the latest available headers 21 | from Microsoft at the time of writing. Constants, macros, typedefs and 22 | function prototypes for all platforms from Windows 2000/XP on (version 0x0500) 23 | are included. Obsolete ones are not included. Only wide-char API variants 24 | are included, the ANSI variants are not included. Only controls from 25 | `ComCtl32.dll` version 6 available on Windows XP and above are supported. 26 | To be able to use comctl 6, you'll need a manifest file near your `luajit.exe` 27 | (included). Note: comctl 6 is Unicode only, another reason not to bind the 28 | ANSI API. 29 | 30 | ## The code 31 | 32 | The code is a 4-layer pie that looks like this (from bottom to top): 33 | 34 | * [ffi layer][winapi_binding] - helper functions that comprise the binding 35 | vocabulary 36 | * winapi modules - low-level procedural winapi wrappers 37 | * oo system - provides a mechanism for inheritance, instantiation and 38 | virtual properties 39 | * winapi classes - actual classes for windows and controls (all files named 40 | `*class.lua`) 41 | 42 | > Each module starts with a comment which describes what the module does 43 | and its place in the pie. 44 | 45 | ## Object API 46 | 47 | The object API is implemented in terms of a minimalist OO system implemented 48 | in `class.lua`, `object.lua`, and `vobject.lua`. The OO system features 49 | single inheritance, constructors, and virtual properties with getters and 50 | setters. It differentiates between class (derivation) and object 51 | (instantiation), so it's not a prototype-based system. 52 | 53 | Winapi classes are implemented one-per-file in `*class.lua` and start with 54 | `basewindowclass.lua` which contains `BaseWindow` from which `Control` (the 55 | base class for all controls) and `Window` (the final class for top-level 56 | windows) are derived. 57 | 58 | ## Procedural API 59 | 60 | The procedural API is designed to work with both cdata objects and equivalent 61 | Lua types. For a string you can choose to pass a ffi WCHAR buffer, which will 62 | be interpreted as UTF-16, or a Lua string, which will be interpreted as UTF-8. 63 | For a struct you can choose to pass a struct cdata or a Lua table, same for 64 | arrays. 65 | 66 | Counting (indexing) starts from 1. 67 | 68 | Flags can be passed as either 'FLAG1 FLAG2 ...' or as 69 | `bit.bor(winapi.FLAG1, winapi.FLAG2, ...)`. 70 | 71 | A winapi handle can be owned either by another winapi object or by Lua's 72 | garbage collector, to prevent memory leaks. Owning (assigning a destructor) 73 | and disowning objects (when windows takes ownership) is taken care of 74 | automatically. 75 | 76 | Boilerplate like a struct's mask field or a struct/buffer/string size, etc. 77 | are hidden from the API. In general, stuff that doesn't relate to actual 78 | functionality but it's an artifact of the ABI is considered an unnecessary 79 | distraction and it is hidden away as much as possible. 80 | 81 | The API doesn't mimic winapi perfectly. Object constructors like 82 | `CreateWindow` take a table with named arguments instead of a list of 83 | arguments like in winapi. Argument positions are sometimes reversed to make 84 | less-used arguments optional, and so on. Struct fields are sometimes renamed 85 | from the crazy hungarian notation, etc. 86 | 87 | The procedural API is implemented with the aid of a set of utilities dealing 88 | with bitmasks, utf-8 conversion, etc. See the [dev doc][winapi_binding] 89 | for more on that. 90 | 91 | -------------------------------------------------------------------------------- /winapi_history.md: -------------------------------------------------------------------------------- 1 | --- 2 | tagline: how it came about 3 | --- 4 | 5 | Here's how the process of binding a subset of winapi for the purpose of 6 | writing a humble Win32 GUI could lead you to write this library in the end. 7 | 8 | So you are on Windows and you want to write a GUI. With just the ffi, 9 | the headers from the Windows SDK and the good old MSDN you could bind enough 10 | of winapi to get by. So you start binding and transcribing to Lua the 11 | necessary functions, macros and constants for windows and controls and 12 | messages and all that's needed to get the app off the ground. 13 | 14 | Soon you realize some facts about winapi that draw more and more attention 15 | to the binding than to the actual application that you want to write. 16 | 17 | Most functions can result in an error but there's different ways in which 18 | they report that (some by a zero result, others with null, others with -1 19 | and so on). When that happens you have to call `GetLastResult` and 20 | `FormatMessageA` every time if you want to get a clue of what happened. 21 | And so you start wrapping the calls. 22 | 23 | Windows and most controls must be initialized with good defaults even if 24 | you don't care for them, or your controls will refuse to get created or 25 | you'll get strange display bugs. 26 | 27 | You can set multiple properties of existing controls at once via "setinfo" 28 | commands, but you have to specify which properties you want to set values 29 | for using a bitmask field - another artifact of a statically-typed language 30 | and old times when RAM was scarce. 31 | 32 | The various "state" fields are bit fields and so they too have a bitmask 33 | that you have to set according to which bits you want to set. 34 | 35 | Also some structs have a "cbSize" field that you have to set to the sizeof 36 | the struct every time you create a new one. Other times there's a "version" 37 | field for similar purpose. If you forget this, nothing will be set and you 38 | won't even get an error. 39 | 40 | You want to feed the GUI unicode strings. To use string constants from your 41 | source file (which is probably in utf8) you have to bind `MultiByteToWideChar` 42 | and call it on all your string constants and other utf8 strings coming from 43 | different places. 44 | 45 | Winapi, like most C APIs counts from 0 so you always have to adjust for that 46 | in your loops which leads to off-by-one bugs. 47 | 48 | To set callbacks on individual controls to respond to events you have to 49 | subclass the controls. Then you have to dispatch them by hand, typecasting 50 | for the various different meanings of `wParam` and `lParam`. 51 | It soon becomes clear that for an app with more than a handful of windows 52 | and controls, some sort dispatching system must be devised to allow event 53 | handlers to be set for individual windows, controls and/or event types. 54 | Message decoders must also be written for each event type. 55 | 56 | To change the state or behavior of controls after creation you have to 57 | awkwardly send messages to them via `SendMessage`, jamming your values and 58 | structs into `wParam` and `lParam` with lots of typecasting and bit shuffling. 59 | There are macros for these that you can transcribe to Lua, but it's a lot of 60 | grunt work. 61 | 62 | In winapi, the objects you create you have to destroy yourself. But when 63 | assigned as children or properties to other objects, the parent takes the 64 | responsibility of destroying them when it is itself destroyed. You want to 65 | prevent memory leaks so you assign the objects a finalizer tied to the 66 | garbage collector, but you are careful to unassign it when the object gets 67 | owned by another object, and assign it back again when it gets disowned. 68 | 69 | Now you have windows and controls on the screen and you can respond to 70 | events. But writing GUIs procedural style is tedious to say the least. So you 71 | now have to devise an object system to encapsulate the controls creation, 72 | setting and getting of properties and assigning event handlers. It needs to 73 | have inheritance because you want to reuse the many properties and methods 74 | of similar controls like buttons and checkboxes. Virtual properties that are 75 | read and written to by way of getters and setters would also be nice, 76 | considering the sheer number of those. 77 | 78 | Finally, you may remember how Delphi had a simple yet very effective 79 | layouting system based on anchors. Windows doesn't come with that, so you 80 | write that too. 81 | 82 | This is more/less where the winapi binding is right now, and this is the 83 | process that got it here. There are still a lot of missing pieces of this 84 | huge API, but there's an infrastructure of utilities and conventions and code 85 | organization in place (which is outlined in the [dev doc]) that makes further 86 | work on the library relatively painless and opens it up for collaboration. 87 | 88 | [dev doc]: winapi_binding 89 | --------------------------------------------------------------------------------