From b988db5bd2f809be41bea8da33e5d01d0fa312a6 Mon Sep 17 00:00:00 2001 From: Nuno Cruces Date: Thu, 19 May 2022 23:39:21 +0100 Subject: [PATCH] Window icons (windows). --- color_windows.go | 2 +- const_windows.go | 2 ++ file_windows.go | 53 ++++++++++++++++++++++++++++++--------------- msg_windows.go | 11 ++-------- util_windows.go | 56 +++++++++++++++++++++++++++--------------------- 5 files changed, 72 insertions(+), 52 deletions(-) diff --git a/color_windows.go b/color_windows.go index eb736b5..32eb9e0 100644 --- a/color_windows.go +++ b/color_windows.go @@ -49,7 +49,7 @@ func selectColor(opts options) (color.Color, error) { defer setup()() if opts.ctx != nil || opts.title != nil { - unhook, err := hookDialogTitle(opts.ctx, opts.title) + unhook, err := hookDialog(opts.ctx, opts.windowIcon, opts.title, nil) if err != nil { return nil, err } diff --git a/const_windows.go b/const_windows.go index 2beb71f..318fd12 100644 --- a/const_windows.go +++ b/const_windows.go @@ -58,6 +58,7 @@ const ( _WM_DESTROY = 0x0002 _WM_CLOSE = 0x0010 _WM_SETFONT = 0x0030 + _WM_SETICON = 0x0080 _WM_NCCREATE = 0x0081 _WM_NCDESTROY = 0x0082 _WM_COMMAND = 0x0111 @@ -74,6 +75,7 @@ const ( _PBM_SETPOS = _WM_USER + 2 _PBM_SETRANGE32 = _WM_USER + 6 _PBM_SETMARQUEE = _WM_USER + 10 + _STM_SETICON = 0x0170 _GWL_STYLE = -16 diff --git a/file_windows.go b/file_windows.go index 1a5361b..e0a2b90 100644 --- a/file_windows.go +++ b/file_windows.go @@ -13,8 +13,26 @@ var ( getOpenFileName = comdlg32.NewProc("GetOpenFileNameW") getSaveFileName = comdlg32.NewProc("GetSaveFileNameW") shBrowseForFolder = shell32.NewProc("SHBrowseForFolderW") - shGetPathFromIDListEx = shell32.NewProc("SHGetPathFromIDListEx") shCreateItemFromParsingName = shell32.NewProc("SHCreateItemFromParsingName") + shGetPathFromIDListEx = shell32.NewProc("SHGetPathFromIDListEx") +) + +const ( + _OFN_OVERWRITEPROMPT = 0x00000002 + _OFN_NOCHANGEDIR = 0x00000008 + _OFN_ALLOWMULTISELECT = 0x00000200 + _OFN_PATHMUSTEXIST = 0x00000800 + _OFN_FILEMUSTEXIST = 0x00001000 + _OFN_CREATEPROMPT = 0x00002000 + _OFN_NOREADONLYRETURN = 0x00008000 + _OFN_EXPLORER = 0x00080000 + _OFN_FORCESHOWHIDDEN = 0x10000000 + + _FOS_NOCHANGEDIR = 0x00000008 + _FOS_PICKFOLDERS = 0x00000020 + _FOS_FORCEFILESYSTEM = 0x00000040 + _FOS_ALLOWMULTISELECT = 0x00000200 + _FOS_FORCESHOWHIDDEN = 0x10000000 ) func selectFile(opts options) (string, error) { @@ -25,13 +43,13 @@ func selectFile(opts options) (string, error) { var args _OPENFILENAME args.StructSize = uint32(unsafe.Sizeof(args)) - args.Flags = 0x81008 // OFN_NOCHANGEDIR|OFN_FILEMUSTEXIST|OFN_EXPLORER + args.Flags = _OFN_NOCHANGEDIR | _OFN_FILEMUSTEXIST | _OFN_EXPLORER if opts.title != nil { args.Title = syscall.StringToUTF16Ptr(*opts.title) } if opts.showHidden { - args.Flags |= 0x10000000 // OFN_FORCESHOWHIDDEN + args.Flags |= _OFN_FORCESHOWHIDDEN } if opts.fileFilters != nil { args.Filter = &initFilters(opts.fileFilters)[0] @@ -45,7 +63,7 @@ func selectFile(opts options) (string, error) { defer setup()() if opts.ctx != nil { - unhook, err := hookDialog(opts.ctx, nil) + unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil) if err != nil { return "", err } @@ -70,13 +88,13 @@ func selectFileMultiple(opts options) ([]string, error) { var args _OPENFILENAME args.StructSize = uint32(unsafe.Sizeof(args)) - args.Flags = 0x81208 // OFN_NOCHANGEDIR|OFN_ALLOWMULTISELECT|OFN_FILEMUSTEXIST|OFN_EXPLORER + args.Flags = _OFN_NOCHANGEDIR | _OFN_ALLOWMULTISELECT | _OFN_FILEMUSTEXIST | _OFN_EXPLORER if opts.title != nil { args.Title = syscall.StringToUTF16Ptr(*opts.title) } if opts.showHidden { - args.Flags |= 0x10000000 // OFN_FORCESHOWHIDDEN + args.Flags |= _OFN_FORCESHOWHIDDEN } if opts.fileFilters != nil { args.Filter = &initFilters(opts.fileFilters)[0] @@ -90,7 +108,7 @@ func selectFileMultiple(opts options) ([]string, error) { defer setup()() if opts.ctx != nil { - unhook, err := hookDialog(opts.ctx, nil) + unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil) if err != nil { return nil, err } @@ -140,19 +158,19 @@ func selectFileSave(opts options) (string, error) { var args _OPENFILENAME args.StructSize = uint32(unsafe.Sizeof(args)) - args.Flags = 0x88808 // OFN_NOCHANGEDIR|OFN_PATHMUSTEXIST|OFN_NOREADONLYRETURN|OFN_EXPLORER + args.Flags = _OFN_NOCHANGEDIR | _OFN_PATHMUSTEXIST | _OFN_NOREADONLYRETURN | _OFN_EXPLORER if opts.title != nil { args.Title = syscall.StringToUTF16Ptr(*opts.title) } if opts.confirmOverwrite { - args.Flags |= 0x2 // OFN_OVERWRITEPROMPT + args.Flags |= _OFN_OVERWRITEPROMPT } if opts.confirmCreate { - args.Flags |= 0x2000 // OFN_CREATEPROMPT + args.Flags |= _OFN_CREATEPROMPT } if opts.showHidden { - args.Flags |= 0x10000000 // OFN_FORCESHOWHIDDEN + args.Flags |= _OFN_FORCESHOWHIDDEN } if opts.fileFilters != nil { args.Filter = &initFilters(opts.fileFilters)[0] @@ -166,7 +184,7 @@ func selectFileSave(opts options) (string, error) { defer setup()() if opts.ctx != nil { - unhook, err := hookDialog(opts.ctx, nil) + unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil) if err != nil { return "", err } @@ -211,13 +229,14 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error) if int32(hr) < 0 { return "", nil, syscall.Errno(hr) } + flgs |= _FOS_NOCHANGEDIR | _FOS_PICKFOLDERS | _FOS_FORCEFILESYSTEM if multi { - flgs |= 0x200 // FOS_ALLOWMULTISELECT + flgs |= _FOS_ALLOWMULTISELECT } if opts.showHidden { - flgs |= 0x10000000 // FOS_FORCESHOWHIDDEN + flgs |= _FOS_FORCESHOWHIDDEN } - hr, _, _ = dialog.Call(dialog.SetOptions, uintptr(flgs|0x68)) // FOS_NOCHANGEDIR|FOS_PICKFOLDERS|FOS_FORCEFILESYSTEM + hr, _, _ = dialog.Call(dialog.SetOptions, uintptr(flgs)) if int32(hr) < 0 { return "", nil, syscall.Errno(hr) } @@ -242,7 +261,7 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error) } if opts.ctx != nil { - unhook, err := hookDialog(opts.ctx, nil) + unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil) if err != nil { return "", nil, err } @@ -320,7 +339,7 @@ func browseForFolder(opts options) (string, []string, error) { } if opts.ctx != nil { - unhook, err := hookDialog(opts.ctx, nil) + unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil) if err != nil { return "", nil, err } diff --git a/msg_windows.go b/msg_windows.go index b4d271b..def918d 100644 --- a/msg_windows.go +++ b/msg_windows.go @@ -88,14 +88,7 @@ func message(kind messageKind, text string, opts options) error { } func hookMessageDialog(kind messageKind, opts options) (unhook context.CancelFunc, err error) { - return hookDialog(opts.ctx, func(wnd uintptr) { - if opts.windowIcon != nil { - icon := getIcon(opts.windowIcon) - if icon.handle != 0 { - defer icon.delete() - sendMessage.Call(wnd, 0x0080 /*WM_SETICON*/, 0, icon.handle) - } - } + return hookDialog(opts.ctx, opts.windowIcon, nil, func(wnd uintptr) { enumChildWindows.Call(wnd, syscall.NewCallback(hookMessageDialogCallback), uintptr(unsafe.Pointer(&opts))) @@ -122,7 +115,7 @@ func hookMessageDialogCallback(wnd uintptr, lparam *options) uintptr { icon := getIcon(lparam.icon) if icon.handle != 0 { defer icon.delete() - sendMessage.Call(wnd, 0x0170 /*STM_SETICON*/, icon.handle, 0) + sendMessage.Call(wnd, _STM_SETICON, icon.handle, 0) } } return 1 diff --git a/util_windows.go b/util_windows.go index 2fecb00..d854991 100644 --- a/util_windows.go +++ b/util_windows.go @@ -156,11 +156,11 @@ func commDlgError() error { } } -func hookDialog(ctx context.Context, initDialog func(wnd uintptr)) (unhook context.CancelFunc, err error) { +func hookDialog(ctx context.Context, icon any, title *string, init func(wnd uintptr)) (unhook context.CancelFunc, err error) { if ctx != nil && ctx.Err() != nil { return nil, ctx.Err() } - hook, err := newDialogHook(ctx, initDialog) + hook, err := newDialogHook(ctx, icon, title, init) if err != nil { return nil, err } @@ -168,15 +168,17 @@ func hookDialog(ctx context.Context, initDialog func(wnd uintptr)) (unhook conte } type dialogHook struct { - ctx context.Context - tid uintptr - wnd uintptr - hook uintptr - done chan struct{} - init func(wnd uintptr) + ctx context.Context + tid uintptr + wnd uintptr + hook uintptr + done chan struct{} + icon any + title *string + init func(wnd uintptr) } -func newDialogHook(ctx context.Context, initDialog func(wnd uintptr)) (*dialogHook, error) { +func newDialogHook(ctx context.Context, icon any, title *string, init func(wnd uintptr)) (*dialogHook, error) { tid, _, _ := getCurrentThreadId.Call() hk, _, err := setWindowsHookEx.Call(5, // WH_CBT syscall.NewCallback(dialogHookProc), 0, tid) @@ -185,10 +187,12 @@ func newDialogHook(ctx context.Context, initDialog func(wnd uintptr)) (*dialogHo } hook := dialogHook{ - ctx: ctx, - tid: tid, - hook: hk, - init: initDialog, + ctx: ctx, + tid: tid, + hook: hk, + icon: icon, + title: title, + init: init, } if ctx != nil { hook.done = make(chan struct{}) @@ -206,8 +210,20 @@ func dialogHookProc(code int32, wparam, lparam uintptr) uintptr { atomic.StoreUintptr(&hook.wnd, wparam) if hook.ctx != nil && hook.ctx.Err() != nil { sendMessage.Call(wparam, _WM_SYSCOMMAND, _SC_CLOSE, 0) - } else if hook.init != nil { - hook.init(wparam) + } else { + if hook.icon != nil { + icon := getIcon(hook.icon) + if icon.handle != 0 { + defer icon.delete() + sendMessage.Call(wparam, _WM_SETICON, 0, icon.handle) + } + } + if hook.title != nil { + setWindowText.Call(wparam, strptr(*hook.title)) + } + if hook.init != nil { + hook.init(wparam) + } } } next, _, _ := callNextHookEx.Call( @@ -233,16 +249,6 @@ func (h *dialogHook) wait() { } } -func hookDialogTitle(ctx context.Context, title *string) (unhook context.CancelFunc, err error) { - var init func(wnd uintptr) - if title != nil { - init = func(wnd uintptr) { - setWindowText.Call(wnd, strptr(*title)) - } - } - return hookDialog(ctx, init) -} - var backRefs struct { sync.Mutex m map[uintptr]unsafe.Pointer