Use IFileOpenDialog where available.
This commit is contained in:
parent
3f5b602117
commit
c56588920f
2 changed files with 65 additions and 49 deletions
|
@ -13,9 +13,12 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func selectFile(opts options) (string, error) {
|
func selectFile(opts options) (string, error) {
|
||||||
|
name, _, shown, err := fileOpenDialog(opts, false)
|
||||||
|
if shown || opts.ctx != nil && opts.ctx.Err() != nil {
|
||||||
|
return name, err
|
||||||
|
}
|
||||||
if opts.directory {
|
if opts.directory {
|
||||||
res, _, err := pickFolders(opts, false)
|
return browseForFolder(opts)
|
||||||
return res, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var args win.OPENFILENAME
|
var args win.OPENFILENAME
|
||||||
|
@ -38,12 +41,6 @@ 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 {
|
||||||
|
@ -62,9 +59,12 @@ func selectFile(opts options) (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func selectFileMultiple(opts options) ([]string, error) {
|
func selectFileMultiple(opts options) ([]string, error) {
|
||||||
|
_, list, shown, err := fileOpenDialog(opts, true)
|
||||||
|
if shown || opts.ctx != nil && opts.ctx.Err() != nil {
|
||||||
|
return list, err
|
||||||
|
}
|
||||||
if opts.directory {
|
if opts.directory {
|
||||||
_, res, err := pickFolders(opts, true)
|
return nil, fmt.Errorf("%w: multiple directory", ErrUnsupported)
|
||||||
return res, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var args win.OPENFILENAME
|
var args win.OPENFILENAME
|
||||||
|
@ -87,12 +87,6 @@ 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 {
|
||||||
|
@ -137,8 +131,7 @@ func selectFileMultiple(opts options) ([]string, error) {
|
||||||
|
|
||||||
func selectFileSave(opts options) (string, error) {
|
func selectFileSave(opts options) (string, error) {
|
||||||
if opts.directory {
|
if opts.directory {
|
||||||
res, _, err := pickFolders(opts, false)
|
return selectFile(opts)
|
||||||
return res, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var args win.OPENFILENAME
|
var args win.OPENFILENAME
|
||||||
|
@ -167,12 +160,6 @@ 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 {
|
||||||
|
@ -190,10 +177,10 @@ func selectFileSave(opts options) (string, error) {
|
||||||
return syscall.UTF16ToString(res[:]), nil
|
return syscall.UTF16ToString(res[:]), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func pickFolders(opts options, multi bool) (string, []string, error) {
|
func fileOpenDialog(opts options, multi bool) (string, []string, bool, error) {
|
||||||
uninit, err := coInitialize()
|
uninit, err := coInitialize()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, err
|
return "", nil, false, err
|
||||||
}
|
}
|
||||||
defer uninit()
|
defer uninit()
|
||||||
|
|
||||||
|
@ -205,27 +192,27 @@ func pickFolders(opts options, multi bool) (string, []string, error) {
|
||||||
win.CLSID_FileOpenDialog, nil, win.CLSCTX_ALL,
|
win.CLSID_FileOpenDialog, nil, win.CLSCTX_ALL,
|
||||||
win.IID_IFileOpenDialog, unsafe.Pointer(&dialog))
|
win.IID_IFileOpenDialog, unsafe.Pointer(&dialog))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if multi {
|
return "", nil, false, err
|
||||||
return "", nil, fmt.Errorf("%w: multiple directory", ErrUnsupported)
|
|
||||||
}
|
|
||||||
return browseForFolder(opts)
|
|
||||||
}
|
}
|
||||||
defer dialog.Release()
|
defer dialog.Release()
|
||||||
|
|
||||||
flgs, err := dialog.GetOptions()
|
flgs, err := dialog.GetOptions()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, err
|
return "", nil, false, err
|
||||||
}
|
}
|
||||||
flgs |= win.FOS_NOCHANGEDIR | win.FOS_PICKFOLDERS | win.FOS_FORCEFILESYSTEM
|
flgs |= win.FOS_NOCHANGEDIR | win.FOS_FILEMUSTEXIST | win.FOS_FORCEFILESYSTEM
|
||||||
if multi {
|
if multi {
|
||||||
flgs |= win.FOS_ALLOWMULTISELECT
|
flgs |= win.FOS_ALLOWMULTISELECT
|
||||||
}
|
}
|
||||||
|
if opts.directory {
|
||||||
|
flgs |= win.FOS_PICKFOLDERS
|
||||||
|
}
|
||||||
if opts.showHidden {
|
if opts.showHidden {
|
||||||
flgs |= win.FOS_FORCESHOWHIDDEN
|
flgs |= win.FOS_FORCESHOWHIDDEN
|
||||||
}
|
}
|
||||||
err = dialog.SetOptions(flgs)
|
err = dialog.SetOptions(flgs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, err
|
return "", nil, false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.title != nil {
|
if opts.title != nil {
|
||||||
|
@ -234,7 +221,12 @@ func pickFolders(opts options, multi bool) (string, []string, error) {
|
||||||
|
|
||||||
if opts.filename != "" {
|
if opts.filename != "" {
|
||||||
var item *win.IShellItem
|
var item *win.IShellItem
|
||||||
win.SHCreateItemFromParsingName(strptr(opts.filename), nil, win.IID_IShellItem, &item)
|
dir, name, _ := splitDirAndName(opts.filename)
|
||||||
|
dialog.SetFileName(strptr(name))
|
||||||
|
if ext := filepath.Ext(name); len(ext) > 1 {
|
||||||
|
dialog.SetDefaultExtension(strptr(ext[1:]))
|
||||||
|
}
|
||||||
|
win.SHCreateItemFromParsingName(strptr(dir), nil, win.IID_IShellItem, &item)
|
||||||
if item != nil {
|
if item != nil {
|
||||||
defer item.Release()
|
defer item.Release()
|
||||||
dialog.SetFolder(item)
|
dialog.SetFolder(item)
|
||||||
|
@ -243,48 +235,48 @@ func pickFolders(opts options, multi bool) (string, []string, error) {
|
||||||
|
|
||||||
unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil)
|
unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, err
|
return "", nil, false, err
|
||||||
}
|
}
|
||||||
defer unhook()
|
defer unhook()
|
||||||
|
|
||||||
err = dialog.Show(owner)
|
err = dialog.Show(owner)
|
||||||
if opts.ctx != nil && opts.ctx.Err() != nil {
|
if opts.ctx != nil && opts.ctx.Err() != nil {
|
||||||
return "", nil, opts.ctx.Err()
|
return "", nil, true, opts.ctx.Err()
|
||||||
}
|
}
|
||||||
if err == win.E_CANCELED {
|
if err == win.E_CANCELED {
|
||||||
return "", nil, ErrCanceled
|
return "", nil, true, ErrCanceled
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, err
|
return "", nil, true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if multi {
|
if multi {
|
||||||
items, err := dialog.GetResults()
|
items, err := dialog.GetResults()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, err
|
return "", nil, true, err
|
||||||
}
|
}
|
||||||
defer items.Release()
|
defer items.Release()
|
||||||
|
|
||||||
count, err := items.GetCount()
|
count, err := items.GetCount()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, err
|
return "", nil, true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var lst []string
|
var lst []string
|
||||||
for i := uint32(0); i < count && err == nil; i++ {
|
for i := uint32(0); i < count && err == nil; i++ {
|
||||||
str, err := shellItemPath(items.GetItemAt(i))
|
str, err := shellItemPath(items.GetItemAt(i))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, err
|
return "", nil, true, err
|
||||||
}
|
}
|
||||||
lst = append(lst, str)
|
lst = append(lst, str)
|
||||||
}
|
}
|
||||||
return "", lst, nil
|
return "", lst, true, nil
|
||||||
} else {
|
} else {
|
||||||
str, err := shellItemPath(dialog.GetResult())
|
str, err := shellItemPath(dialog.GetResult())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, err
|
return "", nil, true, err
|
||||||
}
|
}
|
||||||
return str, nil, nil
|
return str, nil, true, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -296,7 +288,13 @@ func shellItemPath(item *win.IShellItem, err error) (string, error) {
|
||||||
return item.GetDisplayName(win.SIGDN_FILESYSPATH)
|
return item.GetDisplayName(win.SIGDN_FILESYSPATH)
|
||||||
}
|
}
|
||||||
|
|
||||||
func browseForFolder(opts options) (string, []string, error) {
|
func browseForFolder(opts options) (string, error) {
|
||||||
|
uninit, err := coInitialize()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer uninit()
|
||||||
|
|
||||||
var args win.BROWSEINFO
|
var args win.BROWSEINFO
|
||||||
args.Owner, _ = opts.attach.(win.HWND)
|
args.Owner, _ = opts.attach.(win.HWND)
|
||||||
args.Flags = win.BIF_RETURNONLYFSDIRS
|
args.Flags = win.BIF_RETURNONLYFSDIRS
|
||||||
|
@ -311,16 +309,16 @@ func browseForFolder(opts options) (string, []string, error) {
|
||||||
|
|
||||||
unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil)
|
unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, err
|
return "", err
|
||||||
}
|
}
|
||||||
defer unhook()
|
defer unhook()
|
||||||
|
|
||||||
ptr := win.SHBrowseForFolder(&args)
|
ptr := win.SHBrowseForFolder(&args)
|
||||||
if opts.ctx != nil && opts.ctx.Err() != nil {
|
if opts.ctx != nil && opts.ctx.Err() != nil {
|
||||||
return "", nil, opts.ctx.Err()
|
return "", opts.ctx.Err()
|
||||||
}
|
}
|
||||||
if ptr == nil {
|
if ptr == nil {
|
||||||
return "", nil, ErrCanceled
|
return "", ErrCanceled
|
||||||
}
|
}
|
||||||
defer win.CoTaskMemFree(unsafe.Pointer(ptr))
|
defer win.CoTaskMemFree(unsafe.Pointer(ptr))
|
||||||
|
|
||||||
|
@ -328,7 +326,7 @@ func browseForFolder(opts options) (string, []string, error) {
|
||||||
win.SHGetPathFromIDListEx(ptr, &res[0], len(res), 0)
|
win.SHGetPathFromIDListEx(ptr, &res[0], len(res), 0)
|
||||||
|
|
||||||
str := syscall.UTF16ToString(res[:])
|
str := syscall.UTF16ToString(res[:])
|
||||||
return str, []string{str}, nil
|
return str, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func browseForFolderCallback(wnd win.HWND, msg uint32, lparam, data uintptr) uintptr {
|
func browseForFolderCallback(wnd win.HWND, msg uint32, lparam, data uintptr) uintptr {
|
||||||
|
|
|
@ -197,6 +197,15 @@ func (u *IFileDialog) SetFolder(item *IShellItem) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *IFileDialog) SetFileName(name *uint16) (err error) {
|
||||||
|
vtbl := *(**iFileDialogVtbl)(unsafe.Pointer(u))
|
||||||
|
hr, _, _ := u.call(vtbl.SetFileName, uintptr(unsafe.Pointer(name)))
|
||||||
|
if hr != 0 {
|
||||||
|
err = syscall.Errno(hr)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (u *IFileDialog) SetTitle(title *uint16) (err error) {
|
func (u *IFileDialog) SetTitle(title *uint16) (err error) {
|
||||||
vtbl := *(**iFileDialogVtbl)(unsafe.Pointer(u))
|
vtbl := *(**iFileDialogVtbl)(unsafe.Pointer(u))
|
||||||
hr, _, _ := u.call(vtbl.SetTitle, uintptr(unsafe.Pointer(title)))
|
hr, _, _ := u.call(vtbl.SetTitle, uintptr(unsafe.Pointer(title)))
|
||||||
|
@ -206,6 +215,15 @@ func (u *IFileDialog) SetTitle(title *uint16) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *IFileDialog) SetDefaultExtension(extension *uint16) (err error) {
|
||||||
|
vtbl := *(**iFileDialogVtbl)(unsafe.Pointer(u))
|
||||||
|
hr, _, _ := u.call(vtbl.SetDefaultExtension, uintptr(unsafe.Pointer(extension)))
|
||||||
|
if hr != 0 {
|
||||||
|
err = syscall.Errno(hr)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (u *IFileDialog) GetResult() (item *IShellItem, err error) {
|
func (u *IFileDialog) GetResult() (item *IShellItem, err error) {
|
||||||
vtbl := *(**iFileDialogVtbl)(unsafe.Pointer(u))
|
vtbl := *(**iFileDialogVtbl)(unsafe.Pointer(u))
|
||||||
hr, _, _ := u.call(vtbl.GetResult, uintptr(unsafe.Pointer(&item)))
|
hr, _, _ := u.call(vtbl.GetResult, uintptr(unsafe.Pointer(&item)))
|
||||||
|
|
Loading…
Reference in a new issue