mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-02 04:40:41 +08:00
201 lines
6.3 KiB
Go
201 lines
6.3 KiB
Go
//go:build windows
|
|
// +build windows
|
|
|
|
package cfd
|
|
|
|
import (
|
|
"github.com/go-ole/go-ole"
|
|
"github.com/google/uuid"
|
|
"syscall"
|
|
"unsafe"
|
|
)
|
|
|
|
var (
|
|
fileOpenDialogCLSID = ole.NewGUID("{DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7}")
|
|
fileOpenDialogIID = ole.NewGUID("{d57c7288-d4ad-4768-be02-9d969532d960}")
|
|
)
|
|
|
|
type iFileOpenDialog struct {
|
|
vtbl *iFileOpenDialogVtbl
|
|
parentWindowHandle uintptr
|
|
}
|
|
|
|
type iFileOpenDialogVtbl struct {
|
|
iFileDialogVtbl
|
|
|
|
GetResults uintptr // func (ppenum **IShellItemArray) HRESULT
|
|
GetSelectedItems uintptr
|
|
}
|
|
|
|
func newIFileOpenDialog() (*iFileOpenDialog, error) {
|
|
if unknown, err := ole.CreateInstance(fileOpenDialogCLSID, fileOpenDialogIID); err == nil {
|
|
return (*iFileOpenDialog)(unsafe.Pointer(unknown)), nil
|
|
} else {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
func (fileOpenDialog *iFileOpenDialog) Show() error {
|
|
return fileOpenDialog.vtbl.show(unsafe.Pointer(fileOpenDialog), fileOpenDialog.parentWindowHandle)
|
|
}
|
|
|
|
func (fileOpenDialog *iFileOpenDialog) SetParentWindowHandle(hwnd uintptr) {
|
|
fileOpenDialog.parentWindowHandle = hwnd
|
|
}
|
|
|
|
func (fileOpenDialog *iFileOpenDialog) ShowAndGetResult() (string, error) {
|
|
isMultiselect, err := fileOpenDialog.isMultiselect()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if isMultiselect {
|
|
// We should panic as this error is caused by the developer using the library
|
|
panic("use ShowAndGetResults for open multiple files dialog")
|
|
}
|
|
if err := fileOpenDialog.Show(); err != nil {
|
|
return "", err
|
|
}
|
|
return fileOpenDialog.GetResult()
|
|
}
|
|
|
|
func (fileOpenDialog *iFileOpenDialog) ShowAndGetResults() ([]string, error) {
|
|
isMultiselect, err := fileOpenDialog.isMultiselect()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !isMultiselect {
|
|
// We should panic as this error is caused by the developer using the library
|
|
panic("use ShowAndGetResult for open single file dialog")
|
|
}
|
|
if err := fileOpenDialog.Show(); err != nil {
|
|
return nil, err
|
|
}
|
|
return fileOpenDialog.GetResults()
|
|
}
|
|
|
|
func (fileOpenDialog *iFileOpenDialog) SetTitle(title string) error {
|
|
return fileOpenDialog.vtbl.setTitle(unsafe.Pointer(fileOpenDialog), title)
|
|
}
|
|
|
|
func (fileOpenDialog *iFileOpenDialog) GetResult() (string, error) {
|
|
isMultiselect, err := fileOpenDialog.isMultiselect()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if isMultiselect {
|
|
// We should panic as this error is caused by the developer using the library
|
|
panic("use GetResults for open multiple files dialog")
|
|
}
|
|
return fileOpenDialog.vtbl.getResultString(unsafe.Pointer(fileOpenDialog))
|
|
}
|
|
|
|
func (fileOpenDialog *iFileOpenDialog) Release() error {
|
|
return fileOpenDialog.vtbl.release(unsafe.Pointer(fileOpenDialog))
|
|
}
|
|
|
|
func (fileOpenDialog *iFileOpenDialog) SetDefaultFolder(defaultFolderPath string) error {
|
|
return fileOpenDialog.vtbl.setDefaultFolder(unsafe.Pointer(fileOpenDialog), defaultFolderPath)
|
|
}
|
|
|
|
func (fileOpenDialog *iFileOpenDialog) SetFolder(defaultFolderPath string) error {
|
|
return fileOpenDialog.vtbl.setFolder(unsafe.Pointer(fileOpenDialog), defaultFolderPath)
|
|
}
|
|
|
|
func (fileOpenDialog *iFileOpenDialog) SetFileFilters(filter []FileFilter) error {
|
|
return fileOpenDialog.vtbl.setFileTypes(unsafe.Pointer(fileOpenDialog), filter)
|
|
}
|
|
|
|
func (fileOpenDialog *iFileOpenDialog) SetRole(role string) error {
|
|
return fileOpenDialog.vtbl.setClientGuid(unsafe.Pointer(fileOpenDialog), StringToUUID(role))
|
|
}
|
|
|
|
// This should only be callable when the user asks for a multi select because
|
|
// otherwise they will be given the Dialog interface which does not expose this function.
|
|
func (fileOpenDialog *iFileOpenDialog) GetResults() ([]string, error) {
|
|
isMultiselect, err := fileOpenDialog.isMultiselect()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !isMultiselect {
|
|
// We should panic as this error is caused by the developer using the library
|
|
panic("use GetResult for open single file dialog")
|
|
}
|
|
return fileOpenDialog.vtbl.getResultsStrings(unsafe.Pointer(fileOpenDialog))
|
|
}
|
|
|
|
func (fileOpenDialog *iFileOpenDialog) SetDefaultExtension(defaultExtension string) error {
|
|
return fileOpenDialog.vtbl.setDefaultExtension(unsafe.Pointer(fileOpenDialog), defaultExtension)
|
|
}
|
|
|
|
func (fileOpenDialog *iFileOpenDialog) SetFileName(initialFileName string) error {
|
|
return fileOpenDialog.vtbl.setFileName(unsafe.Pointer(fileOpenDialog), initialFileName)
|
|
}
|
|
|
|
func (fileOpenDialog *iFileOpenDialog) SetSelectedFileFilterIndex(index uint) error {
|
|
return fileOpenDialog.vtbl.setSelectedFileFilterIndex(unsafe.Pointer(fileOpenDialog), index)
|
|
}
|
|
|
|
func (fileOpenDialog *iFileOpenDialog) setPickFolders(pickFolders bool) error {
|
|
const FosPickfolders = 0x20
|
|
if pickFolders {
|
|
return fileOpenDialog.vtbl.addOption(unsafe.Pointer(fileOpenDialog), FosPickfolders)
|
|
} else {
|
|
return fileOpenDialog.vtbl.removeOption(unsafe.Pointer(fileOpenDialog), FosPickfolders)
|
|
}
|
|
}
|
|
|
|
const FosAllowMultiselect = 0x200
|
|
|
|
func (fileOpenDialog *iFileOpenDialog) isMultiselect() (bool, error) {
|
|
options, err := fileOpenDialog.vtbl.getOptions(unsafe.Pointer(fileOpenDialog))
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return options&FosAllowMultiselect != 0, nil
|
|
}
|
|
|
|
func (fileOpenDialog *iFileOpenDialog) setIsMultiselect(isMultiselect bool) error {
|
|
if isMultiselect {
|
|
return fileOpenDialog.vtbl.addOption(unsafe.Pointer(fileOpenDialog), FosAllowMultiselect)
|
|
} else {
|
|
return fileOpenDialog.vtbl.removeOption(unsafe.Pointer(fileOpenDialog), FosAllowMultiselect)
|
|
}
|
|
}
|
|
|
|
func (vtbl *iFileOpenDialogVtbl) getResults(objPtr unsafe.Pointer) (*iShellItemArray, error) {
|
|
var shellItemArray *iShellItemArray
|
|
ret, _, _ := syscall.SyscallN(vtbl.GetResults,
|
|
uintptr(objPtr),
|
|
uintptr(unsafe.Pointer(&shellItemArray)),
|
|
0)
|
|
return shellItemArray, hresultToError(ret)
|
|
}
|
|
|
|
func (vtbl *iFileOpenDialogVtbl) getResultsStrings(objPtr unsafe.Pointer) ([]string, error) {
|
|
shellItemArray, err := vtbl.getResults(objPtr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if shellItemArray == nil {
|
|
return nil, ErrorCancelled
|
|
}
|
|
defer shellItemArray.vtbl.release(unsafe.Pointer(shellItemArray))
|
|
count, err := shellItemArray.vtbl.getCount(unsafe.Pointer(shellItemArray))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var results []string
|
|
for i := uintptr(0); i < count; i++ {
|
|
newItem, err := shellItemArray.vtbl.getItemAt(unsafe.Pointer(shellItemArray), i)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
results = append(results, newItem)
|
|
}
|
|
return results, nil
|
|
}
|
|
|
|
func StringToUUID(str string) *ole.GUID {
|
|
return ole.NewGUID(uuid.NewSHA1(uuid.Nil, []byte(str)).String())
|
|
}
|