Initialize COM around file dialogs.

This commit is contained in:
Nuno Cruces 2024-02-05 10:20:14 +00:00
parent 341ccb89d4
commit 3f5b602117
2 changed files with 43 additions and 8 deletions

View file

@ -1,8 +1,10 @@
package zenity package zenity
import ( import (
"context"
"fmt" "fmt"
"path/filepath" "path/filepath"
"runtime"
"syscall" "syscall"
"unicode/utf16" "unicode/utf16"
"unsafe" "unsafe"
@ -36,6 +38,12 @@ func selectFile(opts options) (string, error) {
args.MaxFile = uint32(len(res)) args.MaxFile = uint32(len(res))
args.InitialDir, args.DefExt = initDirNameExt(opts.filename, res[:]) args.InitialDir, args.DefExt = initDirNameExt(opts.filename, res[:])
uninit, err := coInitialize()
if err != nil {
return "", err
}
defer uninit()
defer setup(args.Owner)() defer setup(args.Owner)()
unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil) unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil)
if err != nil { if err != nil {
@ -79,6 +87,12 @@ func selectFileMultiple(opts options) ([]string, error) {
args.MaxFile = uint32(len(res)) args.MaxFile = uint32(len(res))
args.InitialDir, args.DefExt = initDirNameExt(opts.filename, res[:]) args.InitialDir, args.DefExt = initDirNameExt(opts.filename, res[:])
uninit, err := coInitialize()
if err != nil {
return nil, err
}
defer uninit()
defer setup(args.Owner)() defer setup(args.Owner)()
unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil) unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil)
if err != nil { if err != nil {
@ -153,6 +167,12 @@ func selectFileSave(opts options) (string, error) {
args.MaxFile = uint32(len(res)) args.MaxFile = uint32(len(res))
args.InitialDir, args.DefExt = initDirNameExt(opts.filename, res[:]) args.InitialDir, args.DefExt = initDirNameExt(opts.filename, res[:])
uninit, err := coInitialize()
if err != nil {
return "", err
}
defer uninit()
defer setup(args.Owner)() defer setup(args.Owner)()
unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil) unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil)
if err != nil { if err != nil {
@ -171,16 +191,14 @@ func selectFileSave(opts options) (string, error) {
} }
func pickFolders(opts options, multi bool) (string, []string, error) { func pickFolders(opts options, multi bool) (string, []string, error) {
owner, _ := opts.attach.(win.HWND) uninit, err := coInitialize()
defer setup(owner)()
err := win.CoInitializeEx(0, win.COINIT_APARTMENTTHREADED|win.COINIT_DISABLE_OLE1DDE)
if err != win.RPC_E_CHANGED_MODE {
if err != nil { if err != nil {
return "", nil, err return "", nil, err
} }
defer win.CoUninitialize() defer uninit()
}
owner, _ := opts.attach.(win.HWND)
defer setup(owner)()
var dialog *win.IFileOpenDialog var dialog *win.IFileOpenDialog
err = win.CoCreateInstance( err = win.CoCreateInstance(
@ -320,6 +338,22 @@ func browseForFolderCallback(wnd win.HWND, msg uint32, lparam, data uintptr) uin
return 0 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) { func initDirNameExt(filename string, name []uint16) (dir *uint16, ext *uint16) {
d, n, _ := splitDirAndName(filename) d, n, _ := splitDirAndName(filename)
e := filepath.Ext(n) e := filepath.Ext(n)

View file

@ -24,6 +24,7 @@ const (
E_CANCELED = windows.ERROR_CANCELLED | windows.FACILITY_WIN32<<16 | 0x80000000 E_CANCELED = windows.ERROR_CANCELLED | windows.FACILITY_WIN32<<16 | 0x80000000
RPC_E_CHANGED_MODE = syscall.Errno(windows.RPC_E_CHANGED_MODE) 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 { func CoInitializeEx(reserved uintptr, coInit uint32) error {