Use IFileSaveDialog where available.

This commit is contained in:
Nuno Cruces 2024-02-07 13:00:08 +00:00
parent c56588920f
commit 77da6e29f3
2 changed files with 96 additions and 0 deletions

View file

@ -130,6 +130,10 @@ func selectFileMultiple(opts options) ([]string, error) {
} }
func selectFileSave(opts options) (string, error) { func selectFileSave(opts options) (string, error) {
name, shown, err := fileSaveDialog(opts)
if shown || opts.ctx != nil && opts.ctx.Err() != nil {
return name, err
}
if opts.directory { if opts.directory {
return selectFile(opts) return selectFile(opts)
} }
@ -280,6 +284,86 @@ func fileOpenDialog(opts options, multi bool) (string, []string, bool, error) {
} }
} }
func fileSaveDialog(opts options) (string, bool, error) {
uninit, err := coInitialize()
if err != nil {
return "", false, err
}
defer uninit()
owner, _ := opts.attach.(win.HWND)
defer setup(owner)()
var dialog *win.IFileSaveDialog
err = win.CoCreateInstance(
win.CLSID_FileSaveDialog, nil, win.CLSCTX_ALL,
win.IID_IFileSaveDialog, unsafe.Pointer(&dialog))
if err != nil {
return "", false, err
}
defer dialog.Release()
flgs, err := dialog.GetOptions()
if err != nil {
return "", false, err
}
flgs |= win.FOS_NOCHANGEDIR | win.FOS_PATHMUSTEXIST | win.FOS_NOREADONLYRETURN | win.FOS_FORCEFILESYSTEM
if opts.confirmOverwrite {
flgs |= win.FOS_OVERWRITEPROMPT
}
if opts.confirmCreate {
flgs |= win.FOS_CREATEPROMPT
}
if opts.showHidden {
flgs |= win.FOS_FORCESHOWHIDDEN
}
err = dialog.SetOptions(flgs)
if err != nil {
return "", false, err
}
if opts.title != nil {
dialog.SetTitle(strptr(*opts.title))
}
if opts.filename != "" {
var item *win.IShellItem
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 {
defer item.Release()
dialog.SetFolder(item)
}
}
unhook, err := hookDialog(opts.ctx, opts.windowIcon, nil, nil)
if err != nil {
return "", false, err
}
defer unhook()
err = dialog.Show(owner)
if opts.ctx != nil && opts.ctx.Err() != nil {
return "", true, opts.ctx.Err()
}
if err == win.E_CANCELED {
return "", true, ErrCanceled
}
if err != nil {
return "", true, err
}
str, err := shellItemPath(dialog.GetResult())
if err != nil {
return "", true, err
}
return str, true, nil
}
func shellItemPath(item *win.IShellItem, err error) (string, error) { func shellItemPath(item *win.IShellItem, err error) (string, error) {
if err != nil { if err != nil {
return "", err return "", err

View file

@ -123,7 +123,9 @@ type IDLIST struct{}
var ( var (
IID_IShellItem = guid("\x1e\x6d\x82\x43\x18\xe7\xee\x42\xbc\x55\xa1\xe2\x61\xc3\x7b\xfe") IID_IShellItem = guid("\x1e\x6d\x82\x43\x18\xe7\xee\x42\xbc\x55\xa1\xe2\x61\xc3\x7b\xfe")
IID_IFileOpenDialog = guid("\x88\x72\x7c\xd5\xad\xd4\x68\x47\xbe\x02\x9d\x96\x95\x32\xd9\x60") IID_IFileOpenDialog = guid("\x88\x72\x7c\xd5\xad\xd4\x68\x47\xbe\x02\x9d\x96\x95\x32\xd9\x60")
IID_IFileSaveDialog = guid("\x23\xcd\xbc\x84\xde\x5f\xdb\x4c\xae\xa4\xaf\x64\xb8\x3d\x78\xab")
CLSID_FileOpenDialog = guid("\x9c\x5a\x1c\xdc\x8a\xe8\xde\x4d\xa5\xa1\x60\xf8\x2a\x20\xae\xf7") CLSID_FileOpenDialog = guid("\x9c\x5a\x1c\xdc\x8a\xe8\xde\x4d\xa5\xa1\x60\xf8\x2a\x20\xae\xf7")
CLSID_FileSaveDialog = guid("\xf3\xe2\xb4\xc0\x21\xba\x73\x47\x8d\xba\x33\x5e\xc9\x46\xeb\x8b")
) )
type IFileOpenDialog struct{ IFileDialog } type IFileOpenDialog struct{ IFileDialog }
@ -142,6 +144,16 @@ func (u *IFileOpenDialog) GetResults() (res *IShellItemArray, err error) {
return return
} }
type IFileSaveDialog struct{ IFileDialog }
type IFileSaveDialogVtbl struct {
iFileDialogVtbl
SetSaveAsItem uintptr
SetProperties uintptr
SetCollectedProperties uintptr
GetProperties uintptr
ApplyProperties uintptr
}
type IFileDialog struct{ IModalWindow } type IFileDialog struct{ IModalWindow }
type iFileDialogVtbl struct { type iFileDialogVtbl struct {
iModalWindowVtbl iModalWindowVtbl