From 3f5b6021175dddf5c392571ee27ffeb3a81be269 Mon Sep 17 00:00:00 2001 From: Nuno Cruces Date: Mon, 5 Feb 2024 10:20:14 +0000 Subject: [PATCH] Initialize COM around file dialogs. --- file_windows.go | 50 ++++++++++++++++++++++++++++++++++++------- internal/win/ole32.go | 1 + 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/file_windows.go b/file_windows.go index 15ad749..c29d84b 100644 --- a/file_windows.go +++ b/file_windows.go @@ -1,8 +1,10 @@ package zenity import ( + "context" "fmt" "path/filepath" + "runtime" "syscall" "unicode/utf16" "unsafe" @@ -36,6 +38,12 @@ func selectFile(opts options) (string, error) { args.MaxFile = uint32(len(res)) args.InitialDir, args.DefExt = initDirNameExt(opts.filename, res[:]) + uninit, err := coInitialize() + if err != nil { + return "", err + } + defer uninit() + defer setup(args.Owner)() unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil) if err != nil { @@ -79,6 +87,12 @@ func selectFileMultiple(opts options) ([]string, error) { args.MaxFile = uint32(len(res)) args.InitialDir, args.DefExt = initDirNameExt(opts.filename, res[:]) + uninit, err := coInitialize() + if err != nil { + return nil, err + } + defer uninit() + defer setup(args.Owner)() unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil) if err != nil { @@ -153,6 +167,12 @@ func selectFileSave(opts options) (string, error) { args.MaxFile = uint32(len(res)) args.InitialDir, args.DefExt = initDirNameExt(opts.filename, res[:]) + uninit, err := coInitialize() + if err != nil { + return "", err + } + defer uninit() + defer setup(args.Owner)() unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil) if err != nil { @@ -171,17 +191,15 @@ func selectFileSave(opts options) (string, error) { } func pickFolders(opts options, multi bool) (string, []string, error) { + uninit, err := coInitialize() + if err != nil { + return "", nil, err + } + defer uninit() + owner, _ := opts.attach.(win.HWND) defer setup(owner)() - err := win.CoInitializeEx(0, win.COINIT_APARTMENTTHREADED|win.COINIT_DISABLE_OLE1DDE) - if err != win.RPC_E_CHANGED_MODE { - if err != nil { - return "", nil, err - } - defer win.CoUninitialize() - } - var dialog *win.IFileOpenDialog err = win.CoCreateInstance( win.CLSID_FileOpenDialog, nil, win.CLSCTX_ALL, @@ -320,6 +338,22 @@ func browseForFolderCallback(wnd win.HWND, msg uint32, lparam, data uintptr) uin return 0 } +func coInitialize() (context.CancelFunc, error) { + runtime.LockOSThread() + err := win.CoInitializeEx(0, win.COINIT_APARTMENTTHREADED|win.COINIT_DISABLE_OLE1DDE) + if err == nil || err == win.S_FALSE { + return func() { + win.CoUninitialize() + runtime.UnlockOSThread() + }, nil + } + if err == win.RPC_E_CHANGED_MODE { + return runtime.UnlockOSThread, nil + } + runtime.UnlockOSThread() + return nil, err +} + func initDirNameExt(filename string, name []uint16) (dir *uint16, ext *uint16) { d, n, _ := splitDirAndName(filename) e := filepath.Ext(n) diff --git a/internal/win/ole32.go b/internal/win/ole32.go index be88c70..9b13e36 100644 --- a/internal/win/ole32.go +++ b/internal/win/ole32.go @@ -24,6 +24,7 @@ const ( E_CANCELED = windows.ERROR_CANCELLED | windows.FACILITY_WIN32<<16 | 0x80000000 RPC_E_CHANGED_MODE = syscall.Errno(windows.RPC_E_CHANGED_MODE) + S_FALSE = syscall.Errno(windows.S_FALSE) ) func CoInitializeEx(reserved uintptr, coInit uint32) error {