Refactor (windows).

This commit is contained in:
Nuno Cruces 2022-06-22 15:14:52 +01:00
parent e2dc86414f
commit 762d54a00d
13 changed files with 225 additions and 152 deletions

View file

@ -72,7 +72,6 @@ func TestCalendar_script(t *testing.T) {
if skip, err := skip(err); skip {
t.Skip("skipping:", err)
}
got.Date()
if !DateEquals(got, tt.want) || err != tt.err {
t.Errorf("Calendar() = %v, %v; want %v, %v", got, err, tt.want, tt.err)
}

View file

@ -139,7 +139,7 @@ func TestSelectFile_script(t *testing.T) {
t.Skip("skipping:", err)
}
if str == "" || err != nil {
t.Errorf("SelectFile() = %q, %v; want [path], nil", str, err)
t.Fatalf("SelectFile() = %q, %v; want [path], nil", str, err)
}
if _, serr := os.Stat(str); serr != nil {
t.Errorf("SelectFile() = %q, %v; %v", str, err, serr)
@ -152,7 +152,7 @@ func TestSelectFile_script(t *testing.T) {
t.Skip("skipping:", err)
}
if str == "" || err != nil {
t.Errorf("SelectFile() = %q, %v; want [path], nil", str, err)
t.Fatalf("SelectFile() = %q, %v; want [path], nil", str, err)
}
if s, serr := os.Stat(str); serr != nil {
t.Errorf("SelectFile() = %q, %v; %v", str, err, serr)
@ -183,7 +183,7 @@ func TestSelectFileMultiple_script(t *testing.T) {
t.Skip("skipping:", err)
}
if lst == nil || err != nil {
t.Errorf("SelectFileMultiple() = %v, %v; want [path, path], nil", lst, err)
t.Fatalf("SelectFileMultiple() = %v, %v; want [path, path], nil", lst, err)
}
for _, str := range lst {
if _, serr := os.Stat(str); serr != nil {
@ -201,7 +201,7 @@ func TestSelectFileMultiple_script(t *testing.T) {
t.Skip("was not unsupported:", err)
}
if lst == nil || err != nil {
t.Errorf("SelectFileMultiple() = %v, %v; want [path, path], nil", lst, err)
t.Fatalf("SelectFileMultiple() = %v, %v; want [path, path], nil", lst, err)
}
for _, str := range lst {
if s, serr := os.Stat(str); serr != nil {

View file

@ -10,16 +10,6 @@ import (
"github.com/ncruces/zenity/internal/win"
)
const (
_FOS_NOCHANGEDIR = 0x00000008
_FOS_PICKFOLDERS = 0x00000020
_FOS_FORCEFILESYSTEM = 0x00000040
_FOS_ALLOWMULTISELECT = 0x00000200
_FOS_FORCESHOWHIDDEN = 0x10000000
_SIGDN_FILESYSPATH = 0x80058000
)
func selectFile(opts options) (string, error) {
if opts.directory {
res, _, err := pickFolders(opts, false)
@ -189,10 +179,10 @@ func selectFileSave(opts options) (string, error) {
return syscall.UTF16ToString(res[:]), nil
}
func pickFolders(opts options, multi bool) (str string, lst []string, err error) {
func pickFolders(opts options, multi bool) (string, []string, error) {
defer setup()()
err = win.CoInitializeEx(0, win.COINIT_APARTMENTTHREADED|win.COINIT_DISABLE_OLE1DDE)
err := win.CoInitializeEx(0, win.COINIT_APARTMENTTHREADED|win.COINIT_DISABLE_OLE1DDE)
if err != win.RPC_E_CHANGED_MODE {
if err != nil {
return "", nil, err
@ -216,12 +206,12 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error)
if err != nil {
return "", nil, err
}
flgs |= _FOS_NOCHANGEDIR | _FOS_PICKFOLDERS | _FOS_FORCEFILESYSTEM
flgs |= win.FOS_NOCHANGEDIR | win.FOS_PICKFOLDERS | win.FOS_FORCEFILESYSTEM
if multi {
flgs |= _FOS_ALLOWMULTISELECT
flgs |= win.FOS_ALLOWMULTISELECT
}
if opts.showHidden {
flgs |= _FOS_FORCESHOWHIDDEN
flgs |= win.FOS_FORCESHOWHIDDEN
}
err = dialog.SetOptions(flgs)
if err != nil {
@ -236,8 +226,8 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error)
var item *win.IShellItem
win.SHCreateItemFromParsingName(strptr(opts.filename), nil, win.IID_IShellItem, &item)
if item != nil {
defer item.Release()
dialog.SetFolder(item)
item.Release()
}
}
@ -261,15 +251,6 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error)
return "", nil, err
}
shellItemPath := func(item *win.IShellItem) error {
defer item.Release()
str, err := item.GetDisplayName(_SIGDN_FILESYSPATH)
if err == nil {
lst = append(lst, str)
}
return err
}
if multi {
items, err := dialog.GetResults()
if err != nil {
@ -281,25 +262,31 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error)
if err != nil {
return "", nil, err
}
for i := uint32(0); i < count; i++ {
item, err := items.GetItemAt(i)
if err == nil {
err = shellItemPath(item)
}
var lst []string
for i := uint32(0); i < count && err == nil; i++ {
str, err := shellItemPath(items.GetItemAt(i))
if err != nil {
return "", nil, err
}
lst = append(lst, str)
}
return "", lst, nil
} else {
item, err := dialog.GetResult()
if err == nil {
err = shellItemPath(item)
}
str, err := shellItemPath(dialog.GetResult())
if err != nil {
return "", nil, err
}
return str, nil, nil
}
return
}
func shellItemPath(item *win.IShellItem, err error) (string, error) {
if err != nil {
return "", err
}
defer item.Release()
return item.GetDisplayName(win.SIGDN_FILESYSPATH)
}
func browseForFolder(opts options) (string, []string, error) {
@ -327,10 +314,10 @@ func browseForFolder(opts options) (string, []string, error) {
if opts.ctx != nil && opts.ctx.Err() != nil {
return "", nil, opts.ctx.Err()
}
if ptr == nullptr {
if ptr == nil {
return "", nil, ErrCanceled
}
defer win.CoTaskMemFree(ptr)
defer win.CoTaskMemFree(unsafe.Pointer(ptr))
var res [32768]uint16
win.SHGetPathFromIDListEx(ptr, &res[0], len(res), 0)

View file

@ -2,6 +2,26 @@
package win
const (
ICC_LISTVIEW_CLASSES = 0x00000001
ICC_TREEVIEW_CLASSES = 0x00000002
ICC_BAR_CLASSES = 0x00000004
ICC_TAB_CLASSES = 0x00000008
ICC_UPDOWN_CLASS = 0x00000010
ICC_PROGRESS_CLASS = 0x00000020
ICC_HOTKEY_CLASS = 0x00000040
ICC_ANIMATE_CLASS = 0x00000080
ICC_WIN95_CLASSES = 0x000000FF
ICC_DATE_CLASSES = 0x00000100
ICC_USEREX_CLASSES = 0x00000200
ICC_COOL_CLASSES = 0x00000400
ICC_INTERNET_CLASSES = 0x00000800
ICC_PAGESCROLLER_CLASS = 0x00001000
ICC_NATIVEFNTCTL_CLASS = 0x00002000
ICC_STANDARD_CLASSES = 0x00004000
ICC_LINK_CLASS = 0x00008000
)
// https://docs.microsoft.com/en-us/windows/win32/api/commctrl/ns-commctrl-initcommoncontrolsex
type INITCOMMONCONTROLSEX struct {
Size uint32

View file

@ -32,38 +32,41 @@ func CoInitializeEx(reserved uintptr, coInit uint32) error {
func CoUninitialize() { windows.CoUninitialize() }
func CoTaskMemFree(address unsafe.Pointer) { windows.CoTaskMemFree(address) }
// https://github.com/wine-mirror/wine/blob/master/include/unknwn.idl
type _IUnknownBase struct{ COMObject }
type _IUnknownVtbl struct {
type IUnknown struct{}
type iUnknownVtbl struct {
QueryInterface uintptr
AddRef uintptr
Release uintptr
}
func (c *_IUnknownBase) Release() {
vtbl := (*(**_IUnknownVtbl)(unsafe.Pointer(c)))
c.Call(vtbl.Release)
func (u *IUnknown) Release() {
vtbl := *(**iUnknownVtbl)(unsafe.Pointer(u))
u.call(vtbl.Release)
}
type COMObject struct{}
//go:uintptrescapes
func (o *COMObject) Call(trap uintptr, a ...uintptr) (r1, r2 uintptr, lastErr error) {
func (u *IUnknown) call(trap uintptr, a ...uintptr) (r1, r2 uintptr, lastErr error) {
switch nargs := uintptr(len(a)); nargs {
case 0:
return syscall.Syscall(trap, nargs+1, uintptr(unsafe.Pointer(o)), 0, 0)
return syscall.Syscall(trap, nargs+1, uintptr(unsafe.Pointer(u)), 0, 0)
case 1:
return syscall.Syscall(trap, nargs+1, uintptr(unsafe.Pointer(o)), a[0], 0)
return syscall.Syscall(trap, nargs+1, uintptr(unsafe.Pointer(u)), a[0], 0)
case 2:
return syscall.Syscall(trap, nargs+1, uintptr(unsafe.Pointer(o)), a[0], a[1])
return syscall.Syscall(trap, nargs+1, uintptr(unsafe.Pointer(u)), a[0], a[1])
default:
panic("COM call with too many arguments.")
}
}
//sys CoCreateInstance(clsid uintptr, unkOuter *COMObject, clsContext int32, iid uintptr, address unsafe.Pointer) (res error) = ole32.CoCreateInstance
//sys CoTaskMemFree(address Pointer) = ole32.CoTaskMemFree
// https://github.com/wine-mirror/wine/blob/master/include/objidl.idl
type IBindCtx struct{ IUnknown }
//sys CoCreateInstance(clsid uintptr, unkOuter *IUnknown, clsContext int32, iid uintptr, address unsafe.Pointer) (res error) = ole32.CoCreateInstance
func uuid(s string) uintptr {
return (*reflect.StringHeader)(unsafe.Pointer(&s)).Data

View file

@ -14,8 +14,73 @@ const (
BFFM_INITIALIZED = 1
BFFM_SETSELECTION = WM_USER + 103
NIM_ADD = 0
NIM_DELETE = 2
// ShellNotifyIcon messages
NIM_ADD = 0
NIM_MODIFY = 1
NIM_DELETE = 2
NIM_SETFOCUS = 3
NIM_SETVERSION = 4
// NOTIFYICONDATA flags
NIF_MESSAGE = 0x01
NIF_ICON = 0x02
NIF_TIP = 0x04
NIF_STATE = 0x08
NIF_INFO = 0x10
NIF_GUID = 0x20
NIF_REALTIME = 0x40
NIF_SHOWTIP = 0x80
// NOTIFYICONDATA info flags
NIIF_NONE = 0x00
NIIF_INFO = 0x01
NIIF_WARNING = 0x02
NIIF_ERROR = 0x03
NIIF_USER = 0x04
NIIF_NOSOUND = 0x10
NIIF_LARGE_ICON = 0x20
NIIF_RESPECT_QUIET_TIME = 0x80
NIIF_ICON_MASK = 0x0F
// NOTIFYICONDATA state
NIS_HIDDEN = 0x1
NIS_SHAREDICON = 0x2
// IFileOpenDialog options
FOS_OVERWRITEPROMPT = 0x2
FOS_STRICTFILETYPES = 0x4
FOS_NOCHANGEDIR = 0x8
FOS_PICKFOLDERS = 0x20
FOS_FORCEFILESYSTEM = 0x40
FOS_ALLNONSTORAGEITEMS = 0x80
FOS_NOVALIDATE = 0x100
FOS_ALLOWMULTISELECT = 0x200
FOS_PATHMUSTEXIST = 0x800
FOS_FILEMUSTEXIST = 0x1000
FOS_CREATEPROMPT = 0x2000
FOS_SHAREAWARE = 0x4000
FOS_NOREADONLYRETURN = 0x8000
FOS_NOTESTFILECREATE = 0x10000
FOS_HIDEMRUPLACES = 0x20000
FOS_HIDEPINNEDPLACES = 0x40000
FOS_NODEREFERENCELINKS = 0x100000
FOS_OKBUTTONNEEDSINTERACTION = 0x200000
FOS_DONTADDTORECENT = 0x2000000
FOS_FORCESHOWHIDDEN = 0x10000000
FOS_DEFAULTNOMINIMODE = 0x20000000
FOS_FORCEPREVIEWPANEON = 0x40000000
FOS_SUPPORTSTREAMABLEITEMS = 0x80000000
SIGDN_NORMALDISPLAY = 0x00000000
SIGDN_PARENTRELATIVEPARSING = ^(^0x18001 + 0x80000000)
SIGDN_DESKTOPABSOLUTEPARSING = ^(^0x28000 + 0x80000000)
SIGDN_PARENTRELATIVEEDITING = ^(^0x31001 + 0x80000000)
SIGDN_DESKTOPABSOLUTEEDITING = ^(^0x4c000 + 0x80000000)
SIGDN_FILESYSPATH = ^(^0x58000 + 0x80000000)
SIGDN_URL = ^(^0x68000 + 0x80000000)
SIGDN_PARENTRELATIVEFORADDRESSBAR = ^(^0x7c001 + 0x80000000)
SIGDN_PARENTRELATIVE = ^(^0x80001 + 0x80000000)
SIGDN_PARENTRELATIVEFORUI = ^(^0x94001 + 0x80000000)
)
// https://docs.microsoft.com/en-us/windows/win32/api/shlobj_core/ns-shlobj_core-browseinfow
@ -49,6 +114,8 @@ type NOTIFYICONDATA struct {
// BalloonIcon Handle // NOTIFYICONDATAA_V3_SIZE
}
type IDLIST struct{}
// https://github.com/wine-mirror/wine/blob/master/include/shobjidl.idl
var (
@ -57,30 +124,25 @@ var (
CLSID_FileOpenDialog = uuid("\x9c\x5a\x1c\xdc\x8a\xe8\xde\x4d\xa5\xa1\x60\xf8\x2a\x20\xae\xf7")
)
type IFileOpenDialog struct {
_IFileOpenDialogBase
_ *_IFileOpenDialogVtbl
}
type _IFileOpenDialogBase struct{ _IFileDialogBase }
type _IFileOpenDialogVtbl struct {
_IFileDialogVtbl
type IFileOpenDialog struct{ IFileDialog }
type iFileOpenDialogVtbl struct {
iFileDialogVtbl
GetResults uintptr
GetSelectedItems uintptr
}
func (c *_IFileOpenDialogBase) GetResults() (res *IShellItemArray, err error) {
vtbl := (*(**_IFileOpenDialogVtbl)(unsafe.Pointer(c)))
hr, _, _ := c.Call(vtbl.GetResults, uintptr(unsafe.Pointer(&res)))
func (u *IFileOpenDialog) GetResults() (res *IShellItemArray, err error) {
vtbl := *(**iFileOpenDialogVtbl)(unsafe.Pointer(u))
hr, _, _ := u.call(vtbl.GetResults, uintptr(unsafe.Pointer(&res)))
if hr != 0 {
err = syscall.Errno(hr)
}
return
}
type _IFileDialogBase struct{ _IModalWindowBase }
type _IFileDialogVtbl struct {
_IModalWindowVtbl
type IFileDialog struct{ IModalWindow }
type iFileDialogVtbl struct {
iModalWindowVtbl
SetFileTypes uintptr
SetFileTypeIndex uintptr
GetFileTypeIndex uintptr
@ -106,74 +168,69 @@ type _IFileDialogVtbl struct {
SetFilter uintptr
}
func (c *_IFileDialogBase) SetOptions(fos int) (err error) {
vtbl := (*(**_IFileDialogVtbl)(unsafe.Pointer(c)))
hr, _, _ := c.Call(vtbl.SetOptions, uintptr(fos))
func (u *IFileDialog) SetOptions(fos int) (err error) {
vtbl := *(**iFileDialogVtbl)(unsafe.Pointer(u))
hr, _, _ := u.call(vtbl.SetOptions, uintptr(fos))
if hr != 0 {
err = syscall.Errno(hr)
}
return
}
func (c *_IFileDialogBase) GetOptions() (fos int, err error) {
vtbl := (*(**_IFileDialogVtbl)(unsafe.Pointer(c)))
hr, _, _ := c.Call(vtbl.GetOptions, uintptr(unsafe.Pointer(&fos)))
func (u *IFileDialog) GetOptions() (fos int, err error) {
vtbl := *(**iFileDialogVtbl)(unsafe.Pointer(u))
hr, _, _ := u.call(vtbl.GetOptions, uintptr(unsafe.Pointer(&fos)))
if hr != 0 {
err = syscall.Errno(hr)
}
return
}
func (c *_IFileDialogBase) SetFolder(item *IShellItem) (err error) {
vtbl := (*(**_IFileDialogVtbl)(unsafe.Pointer(c)))
hr, _, _ := c.Call(vtbl.SetFolder, uintptr(unsafe.Pointer(item)))
func (u *IFileDialog) SetFolder(item *IShellItem) (err error) {
vtbl := *(**iFileDialogVtbl)(unsafe.Pointer(u))
hr, _, _ := u.call(vtbl.SetFolder, uintptr(unsafe.Pointer(item)))
if hr != 0 {
err = syscall.Errno(hr)
}
return
}
func (c *_IFileDialogBase) SetTitle(title *uint16) (err error) {
vtbl := (*(**_IFileDialogVtbl)(unsafe.Pointer(c)))
hr, _, _ := c.Call(vtbl.SetTitle, uintptr(unsafe.Pointer(title)))
func (u *IFileDialog) SetTitle(title *uint16) (err error) {
vtbl := *(**iFileDialogVtbl)(unsafe.Pointer(u))
hr, _, _ := u.call(vtbl.SetTitle, uintptr(unsafe.Pointer(title)))
if hr != 0 {
err = syscall.Errno(hr)
}
return
}
func (c *_IFileDialogBase) GetResult() (item *IShellItem, err error) {
vtbl := (*(**_IFileDialogVtbl)(unsafe.Pointer(c)))
hr, _, _ := c.Call(vtbl.GetResult, uintptr(unsafe.Pointer(&item)))
func (u *IFileDialog) GetResult() (item *IShellItem, err error) {
vtbl := *(**iFileDialogVtbl)(unsafe.Pointer(u))
hr, _, _ := u.call(vtbl.GetResult, uintptr(unsafe.Pointer(&item)))
if hr != 0 {
err = syscall.Errno(hr)
}
return
}
type _IModalWindowBase struct{ _IUnknownBase }
type _IModalWindowVtbl struct {
_IUnknownVtbl
type IModalWindow struct{ IUnknown }
type iModalWindowVtbl struct {
iUnknownVtbl
Show uintptr
}
func (c *_IModalWindowBase) Show(wnd HWND) (err error) {
vtbl := (*(**_IModalWindowVtbl)(unsafe.Pointer(c)))
hr, _, _ := c.Call(vtbl.Show, uintptr(wnd))
func (u *IModalWindow) Show(wnd HWND) (err error) {
vtbl := *(**iModalWindowVtbl)(unsafe.Pointer(u))
hr, _, _ := u.call(vtbl.Show, uintptr(wnd))
if hr != 0 {
err = syscall.Errno(hr)
}
return
}
type IShellItem struct {
_IShellItemBase
_ *_IShellItemVtbl
}
type _IShellItemBase struct{ _IUnknownBase }
type _IShellItemVtbl struct {
_IUnknownVtbl
type IShellItem struct{ IUnknown }
type iShellItemVtbl struct {
iUnknownVtbl
BindToHandler uintptr
GetParent uintptr
GetDisplayName uintptr
@ -181,10 +238,10 @@ type _IShellItemVtbl struct {
Compare uintptr
}
func (c *_IShellItemBase) GetDisplayName(name int) (res string, err error) {
func (u *IShellItem) GetDisplayName(name int) (res string, err error) {
var ptr uintptr
vtbl := (*(**_IShellItemVtbl)(unsafe.Pointer(c)))
hr, _, _ := c.Call(vtbl.GetDisplayName, uintptr(name), uintptr(unsafe.Pointer(&ptr)))
vtbl := *(**iShellItemVtbl)(unsafe.Pointer(u))
hr, _, _ := u.call(vtbl.GetDisplayName, uintptr(name), uintptr(unsafe.Pointer(&ptr)))
if hr != 0 {
err = syscall.Errno(hr)
} else {
@ -196,14 +253,9 @@ func (c *_IShellItemBase) GetDisplayName(name int) (res string, err error) {
return
}
type IShellItemArray struct {
_IShellItemArrayBase
_ *_IShellItemArrayVtbl
}
type _IShellItemArrayBase struct{ _IUnknownBase }
type _IShellItemArrayVtbl struct {
_IUnknownVtbl
type IShellItemArray struct{ IUnknown }
type iShellItemArrayVtbl struct {
iUnknownVtbl
BindToHandler uintptr
GetPropertyStore uintptr
GetPropertyDescriptionList uintptr
@ -213,25 +265,25 @@ type _IShellItemArrayVtbl struct {
EnumItems uintptr
}
func (c *_IShellItemArrayBase) GetCount() (numItems uint32, err error) {
vtbl := (*(**_IShellItemArrayVtbl)(unsafe.Pointer(c)))
hr, _, _ := c.Call(vtbl.GetCount, uintptr(unsafe.Pointer(&numItems)))
func (u *IShellItemArray) GetCount() (numItems uint32, err error) {
vtbl := *(**iShellItemArrayVtbl)(unsafe.Pointer(u))
hr, _, _ := u.call(vtbl.GetCount, uintptr(unsafe.Pointer(&numItems)))
if hr != 0 {
err = syscall.Errno(hr)
}
return
}
func (c *_IShellItemArrayBase) GetItemAt(index uint32) (item *IShellItem, err error) {
vtbl := (*(**_IShellItemArrayVtbl)(unsafe.Pointer(c)))
hr, _, _ := c.Call(vtbl.GetItemAt, uintptr(index), uintptr(unsafe.Pointer(&item)))
func (u *IShellItemArray) GetItemAt(index uint32) (item *IShellItem, err error) {
vtbl := *(**iShellItemArrayVtbl)(unsafe.Pointer(u))
hr, _, _ := u.call(vtbl.GetItemAt, uintptr(index), uintptr(unsafe.Pointer(&item)))
if hr != 0 {
err = syscall.Errno(hr)
}
return
}
//sys SHBrowseForFolder(bi *BROWSEINFO) (ret Pointer) = shell32.SHBrowseForFolder
//sys SHCreateItemFromParsingName(path *uint16, bc *COMObject, iid uintptr, item **IShellItem) (res error) = shell32.SHCreateItemFromParsingName
//sys SHBrowseForFolder(bi *BROWSEINFO) (ret *IDLIST) = shell32.SHBrowseForFolder
//sys SHCreateItemFromParsingName(path *uint16, bc *IBindCtx, iid uintptr, item **IShellItem) (res error) = shell32.SHCreateItemFromParsingName
//sys ShellNotifyIcon(message uint32, data *NOTIFYICONDATA) (ret int, err error) = shell32.Shell_NotifyIconW
//sys SHGetPathFromIDListEx(ptr Pointer, path *uint16, pathLen int, opts int) (ok bool) = shell32.SHGetPathFromIDListEx
//sys SHGetPathFromIDListEx(ptr *IDLIST, path *uint16, pathLen int, opts int) (ok bool) = shell32.SHGetPathFromIDListEx

View file

@ -19,6 +19,9 @@ const (
IDYES = 6
IDNO = 7
// Control IDs
IDC_STATIC_OK = 20
// MessageBox types
MB_OK = windows.MB_OK
MB_OKCANCEL = windows.MB_OKCANCEL
@ -60,7 +63,7 @@ const (
STM_SETICON = 0x0170
// CreateWindow
CW_USEDEFAULT = 0x80000000
CW_USEDEFAULT = -0x80000000
// Window classes
PROGRESS_CLASS = "msctls_progress32"
@ -217,18 +220,34 @@ const (
// SetWindowsHookEx types
WH_CALLWNDPROCRET = 12
USER_DEFAULT_SCREEN_DPI = 96
// System colors
COLOR_WINDOW = 5
// DPI awareness
USER_DEFAULT_SCREEN_DPI = 96
DPI_AWARENESS_CONTEXT_UNAWARE = ^uintptr(1) + 1
DPI_AWARENESS_CONTEXT_SYSTEM_AWARE = ^uintptr(2) + 1
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE = ^uintptr(3) + 1
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 = ^uintptr(4) + 1
DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED = ^uintptr(5) + 1
// LoadImage type
IMAGE_BITMAP = 0
IMAGE_ICON = 1
IMAGE_CURSOR = 2
// LoadIcon resources
IDI_APPLICATION = 32512
IDI_ERROR = 32513
IDI_HAND = 32513
IDI_QUESTION = 32514
IDI_WARNING = 32515
IDI_EXCLAMATION = 32515
IDI_ASTERISK = 32516
IDI_INFORMATION = 32516
IDI_WINLOGO = 32517
IDI_SHIELD = 32518
// LoadResource (image/icon) flags
LR_DEFAULTCOLOR = 0x00000000
LR_MONOCHROME = 0x00000001

View file

@ -7,7 +7,7 @@ import "golang.org/x/sys/windows"
type Handle = windows.Handle
type HWND = windows.HWND
type Pointer uintptr
type Pointer = windows.Pointer
// https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-systemtime
type SYSTEMTIME struct {

View file

@ -62,7 +62,6 @@ var (
procGetModuleHandleW = modkernel32.NewProc("GetModuleHandleW")
procReleaseActCtx = modkernel32.NewProc("ReleaseActCtx")
procCoCreateInstance = modole32.NewProc("CoCreateInstance")
procCoTaskMemFree = modole32.NewProc("CoTaskMemFree")
procSHBrowseForFolder = modshell32.NewProc("SHBrowseForFolder")
procSHCreateItemFromParsingName = modshell32.NewProc("SHCreateItemFromParsingName")
procSHGetPathFromIDListEx = modshell32.NewProc("SHGetPathFromIDListEx")
@ -199,7 +198,7 @@ func ReleaseActCtx(actCtx Handle) {
return
}
func CoCreateInstance(clsid uintptr, unkOuter *COMObject, clsContext int32, iid uintptr, address unsafe.Pointer) (res error) {
func CoCreateInstance(clsid uintptr, unkOuter *IUnknown, clsContext int32, iid uintptr, address unsafe.Pointer) (res error) {
r0, _, _ := syscall.Syscall6(procCoCreateInstance.Addr(), 5, uintptr(clsid), uintptr(unsafe.Pointer(unkOuter)), uintptr(clsContext), uintptr(iid), uintptr(address), 0)
if r0 != 0 {
res = syscall.Errno(r0)
@ -207,18 +206,13 @@ func CoCreateInstance(clsid uintptr, unkOuter *COMObject, clsContext int32, iid
return
}
func CoTaskMemFree(address Pointer) {
syscall.Syscall(procCoTaskMemFree.Addr(), 1, uintptr(address), 0, 0)
return
}
func SHBrowseForFolder(bi *BROWSEINFO) (ret Pointer) {
func SHBrowseForFolder(bi *BROWSEINFO) (ret *IDLIST) {
r0, _, _ := syscall.Syscall(procSHBrowseForFolder.Addr(), 1, uintptr(unsafe.Pointer(bi)), 0, 0)
ret = Pointer(r0)
ret = (*IDLIST)(unsafe.Pointer(r0))
return
}
func SHCreateItemFromParsingName(path *uint16, bc *COMObject, iid uintptr, item **IShellItem) (res error) {
func SHCreateItemFromParsingName(path *uint16, bc *IBindCtx, iid uintptr, item **IShellItem) (res error) {
r0, _, _ := syscall.Syscall6(procSHCreateItemFromParsingName.Addr(), 4, uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(bc)), uintptr(iid), uintptr(unsafe.Pointer(item)), 0, 0)
if r0 != 0 {
res = syscall.Errno(r0)
@ -226,8 +220,8 @@ func SHCreateItemFromParsingName(path *uint16, bc *COMObject, iid uintptr, item
return
}
func SHGetPathFromIDListEx(ptr Pointer, path *uint16, pathLen int, opts int) (ok bool) {
r0, _, _ := syscall.Syscall6(procSHGetPathFromIDListEx.Addr(), 4, uintptr(ptr), uintptr(unsafe.Pointer(path)), uintptr(pathLen), uintptr(opts), 0, 0)
func SHGetPathFromIDListEx(ptr *IDLIST, path *uint16, pathLen int, opts int) (ok bool) {
r0, _, _ := syscall.Syscall6(procSHGetPathFromIDListEx.Addr(), 4, uintptr(unsafe.Pointer(ptr)), uintptr(unsafe.Pointer(path)), uintptr(pathLen), uintptr(opts), 0, 0)
ok = r0 != 0
return
}

View file

@ -187,7 +187,7 @@ func listProc(wnd win.HWND, msg uint32, wparam uintptr, lparam *unsafe.Pointer)
dlg.out = make([]string, len)
if len > 0 {
indices := make([]int32, len)
win.SendMessage(dlg.listCtl, win.LB_GETSELITEMS, len, uintptr(unsafe.Pointer(&indices[0])))
win.SendMessagePointer(dlg.listCtl, win.LB_GETSELITEMS, len, unsafe.Pointer(&indices[0]))
for i, idx := range indices {
dlg.out[i] = dlg.items[idx]
}

View file

@ -88,6 +88,7 @@ func message(kind messageKind, text string, opts options) error {
}
func hookMessageDialog(opts options) (unhook context.CancelFunc, err error) {
// TODO: use GetDlgItem, SetDlgItemText instead of EnumChildWindows.
return hookDialog(opts.ctx, opts.windowIcon, nil, func(wnd win.HWND) {
win.EnumChildWindows(wnd, syscall.NewCallback(hookMessageDialogCallback),
unsafe.Pointer(&opts))
@ -110,7 +111,7 @@ func hookMessageDialogCallback(wnd win.HWND, lparam *options) uintptr {
win.SetWindowText(wnd, strptr(*text))
}
if ctl == 20 /*IDC_STATIC_OK*/ {
if ctl == win.IDC_STATIC_OK {
icon := getIcon(lparam.icon)
if icon.handle != 0 {
defer icon.delete()

View file

@ -19,8 +19,8 @@ func notify(text string, opts options) error {
var args win.NOTIFYICONDATA
args.StructSize = uint32(unsafe.Sizeof(args))
args.ID = rand.Uint32()
args.Flags = 0x00000010 // NIF_INFO
args.State = 0x00000001 // NIS_HIDDEN
args.Flags = win.NIF_INFO
args.State = win.NIS_HIDDEN
info := syscall.StringToUTF16(text)
copy(args.Info[:len(args.Info)-1], info)
@ -32,18 +32,18 @@ func notify(text string, opts options) error {
switch opts.icon {
case InfoIcon, QuestionIcon:
args.InfoFlags |= 0x1 // NIIF_INFO
args.InfoFlags |= win.NIIF_INFO
case WarningIcon:
args.InfoFlags |= 0x2 // NIIF_WARNING
args.InfoFlags |= win.NIIF_WARNING
case ErrorIcon:
args.InfoFlags |= 0x3 // NIIF_ERROR
args.InfoFlags |= win.NIIF_ERROR
default:
icon := getIcon(opts.icon)
if icon.handle != 0 {
defer icon.delete()
args.Icon = win.Handle(icon.handle)
args.Flags |= 0x00000002 // NIF_ICON
args.InfoFlags |= 0x4 // NIIF_USER
args.Flags |= win.NIF_ICON
args.InfoFlags |= win.NIIF_USER
}
}

View file

@ -23,8 +23,6 @@ const (
_WS_ZEN_BUTTON = _WS_ZEN_CONTROL
)
const nullptr win.Pointer = 0
func intptr(i int64) uintptr { return uintptr(i) }
func strptr(s string) *uint16 { return syscall.StringToUTF16Ptr(s) }
@ -56,7 +54,7 @@ func setup() context.CancelFunc {
var icc win.INITCOMMONCONTROLSEX
icc.Size = uint32(unsafe.Sizeof(icc))
icc.ICC = 0x00004020 // ICC_STANDARD_CLASSES|ICC_PROGRESS_CLASS
icc.ICC = win.ICC_STANDARD_CLASSES | win.ICC_DATE_CLASSES | win.ICC_PROGRESS_CLASS
win.InitCommonControlsEx(&icc)
return func() {
@ -264,13 +262,13 @@ func getIcon(i any) icon {
var resource uintptr
switch i {
case ErrorIcon:
resource = 32513 // IDI_ERROR
resource = win.IDI_ERROR
case QuestionIcon:
resource = 32514 // IDI_QUESTION
resource = win.IDI_QUESTION
case WarningIcon:
resource = 32515 // IDI_WARNING
resource = win.IDI_WARNING
case InfoIcon:
resource = 32516 // IDI_INFORMATION
resource = win.IDI_INFORMATION
}
if resource != 0 {
res.handle, _ = win.LoadIcon(0, resource)
@ -331,7 +329,7 @@ func registerClass(instance, icon win.Handle, proc uintptr) (*uint16, error) {
wcx.WndProc = proc
wcx.Icon = icon
wcx.Instance = instance
wcx.Background = 5 // COLOR_WINDOW
wcx.Background = win.COLOR_WINDOW
wcx.ClassName = strptr(name)
if err := win.RegisterClassEx(&wcx); err != nil {