github.com/AlpineAIO/wails/v2@v2.0.0-beta.32.0.20240505041856-1047a8fa5fef/internal/go-common-file-dialog/cfd/vtblCommonFunc.go (about)

     1  //go:build windows
     2  // +build windows
     3  
     4  package cfd
     5  
     6  import (
     7  	"fmt"
     8  	"github.com/go-ole/go-ole"
     9  	"strings"
    10  	"syscall"
    11  	"unsafe"
    12  )
    13  
    14  func hresultToError(hr uintptr) error {
    15  	if hr < 0 {
    16  		return ole.NewError(hr)
    17  	}
    18  	return nil
    19  }
    20  
    21  func (vtbl *iUnknownVtbl) release(objPtr unsafe.Pointer) error {
    22  	ret, _, _ := syscall.Syscall(vtbl.Release,
    23  		0,
    24  		uintptr(objPtr),
    25  		0,
    26  		0)
    27  	return hresultToError(ret)
    28  }
    29  
    30  func (vtbl *iModalWindowVtbl) show(objPtr unsafe.Pointer, hwnd uintptr) error {
    31  	ret, _, _ := syscall.Syscall(vtbl.Show,
    32  		1,
    33  		uintptr(objPtr),
    34  		hwnd,
    35  		0)
    36  	return hresultToError(ret)
    37  }
    38  
    39  func (vtbl *iFileDialogVtbl) setFileTypes(objPtr unsafe.Pointer, filters []FileFilter) error {
    40  	cFileTypes := len(filters)
    41  	if cFileTypes < 0 {
    42  		return fmt.Errorf("must specify at least one filter")
    43  	}
    44  	comDlgFilterSpecs := make([]comDlgFilterSpec, cFileTypes)
    45  	for i := 0; i < cFileTypes; i++ {
    46  		filter := &filters[i]
    47  		comDlgFilterSpecs[i] = comDlgFilterSpec{
    48  			pszName: ole.SysAllocString(filter.DisplayName),
    49  			pszSpec: ole.SysAllocString(filter.Pattern),
    50  		}
    51  	}
    52  	ret, _, _ := syscall.Syscall(vtbl.SetFileTypes,
    53  		2,
    54  		uintptr(objPtr),
    55  		uintptr(cFileTypes),
    56  		uintptr(unsafe.Pointer(&comDlgFilterSpecs[0])))
    57  	return hresultToError(ret)
    58  }
    59  
    60  // Options are:
    61  // FOS_OVERWRITEPROMPT = 0x2,
    62  // FOS_STRICTFILETYPES = 0x4,
    63  // FOS_NOCHANGEDIR = 0x8,
    64  // FOS_PICKFOLDERS = 0x20,
    65  // FOS_FORCEFILESYSTEM = 0x40,
    66  // FOS_ALLNONSTORAGEITEMS = 0x80,
    67  // FOS_NOVALIDATE = 0x100,
    68  // FOS_ALLOWMULTISELECT = 0x200,
    69  // FOS_PATHMUSTEXIST = 0x800,
    70  // FOS_FILEMUSTEXIST = 0x1000,
    71  // FOS_CREATEPROMPT = 0x2000,
    72  // FOS_SHAREAWARE = 0x4000,
    73  // FOS_NOREADONLYRETURN = 0x8000,
    74  // FOS_NOTESTFILECREATE = 0x10000,
    75  // FOS_HIDEMRUPLACES = 0x20000,
    76  // FOS_HIDEPINNEDPLACES = 0x40000,
    77  // FOS_NODEREFERENCELINKS = 0x100000,
    78  // FOS_OKBUTTONNEEDSINTERACTION = 0x200000,
    79  // FOS_DONTADDTORECENT = 0x2000000,
    80  // FOS_FORCESHOWHIDDEN = 0x10000000,
    81  // FOS_DEFAULTNOMINIMODE = 0x20000000,
    82  // FOS_FORCEPREVIEWPANEON = 0x40000000,
    83  // FOS_SUPPORTSTREAMABLEITEMS = 0x80000000
    84  func (vtbl *iFileDialogVtbl) setOptions(objPtr unsafe.Pointer, options uint32) error {
    85  	ret, _, _ := syscall.Syscall(vtbl.SetOptions,
    86  		1,
    87  		uintptr(objPtr),
    88  		uintptr(options),
    89  		0)
    90  	return hresultToError(ret)
    91  }
    92  
    93  func (vtbl *iFileDialogVtbl) getOptions(objPtr unsafe.Pointer) (uint32, error) {
    94  	var options uint32
    95  	ret, _, _ := syscall.Syscall(vtbl.GetOptions,
    96  		1,
    97  		uintptr(objPtr),
    98  		uintptr(unsafe.Pointer(&options)),
    99  		0)
   100  	return options, hresultToError(ret)
   101  }
   102  
   103  func (vtbl *iFileDialogVtbl) addOption(objPtr unsafe.Pointer, option uint32) error {
   104  	if options, err := vtbl.getOptions(objPtr); err == nil {
   105  		return vtbl.setOptions(objPtr, options|option)
   106  	} else {
   107  		return err
   108  	}
   109  }
   110  
   111  func (vtbl *iFileDialogVtbl) removeOption(objPtr unsafe.Pointer, option uint32) error {
   112  	if options, err := vtbl.getOptions(objPtr); err == nil {
   113  		return vtbl.setOptions(objPtr, options&^option)
   114  	} else {
   115  		return err
   116  	}
   117  }
   118  
   119  func (vtbl *iFileDialogVtbl) setDefaultFolder(objPtr unsafe.Pointer, path string) error {
   120  	shellItem, err := newIShellItem(path)
   121  	if err != nil {
   122  		return err
   123  	}
   124  	defer shellItem.vtbl.release(unsafe.Pointer(shellItem))
   125  	ret, _, _ := syscall.Syscall(vtbl.SetDefaultFolder,
   126  		1,
   127  		uintptr(objPtr),
   128  		uintptr(unsafe.Pointer(shellItem)),
   129  		0)
   130  	return hresultToError(ret)
   131  }
   132  
   133  func (vtbl *iFileDialogVtbl) setFolder(objPtr unsafe.Pointer, path string) error {
   134  	shellItem, err := newIShellItem(path)
   135  	if err != nil {
   136  		return err
   137  	}
   138  	defer shellItem.vtbl.release(unsafe.Pointer(shellItem))
   139  	ret, _, _ := syscall.Syscall(vtbl.SetFolder,
   140  		1,
   141  		uintptr(objPtr),
   142  		uintptr(unsafe.Pointer(shellItem)),
   143  		0)
   144  	return hresultToError(ret)
   145  }
   146  
   147  func (vtbl *iFileDialogVtbl) setTitle(objPtr unsafe.Pointer, title string) error {
   148  	titlePtr := ole.SysAllocString(title)
   149  	ret, _, _ := syscall.Syscall(vtbl.SetTitle,
   150  		1,
   151  		uintptr(objPtr),
   152  		uintptr(unsafe.Pointer(titlePtr)),
   153  		0)
   154  	return hresultToError(ret)
   155  }
   156  
   157  func (vtbl *iFileDialogVtbl) close(objPtr unsafe.Pointer) error {
   158  	ret, _, _ := syscall.Syscall(vtbl.Close,
   159  		1,
   160  		uintptr(objPtr),
   161  		0,
   162  		0)
   163  	return hresultToError(ret)
   164  }
   165  
   166  func (vtbl *iFileDialogVtbl) getResult(objPtr unsafe.Pointer) (*iShellItem, error) {
   167  	var shellItem *iShellItem
   168  	ret, _, _ := syscall.Syscall(vtbl.GetResult,
   169  		1,
   170  		uintptr(objPtr),
   171  		uintptr(unsafe.Pointer(&shellItem)),
   172  		0)
   173  	return shellItem, hresultToError(ret)
   174  }
   175  
   176  func (vtbl *iFileDialogVtbl) getResultString(objPtr unsafe.Pointer) (string, error) {
   177  	shellItem, err := vtbl.getResult(objPtr)
   178  	if err != nil {
   179  		return "", err
   180  	}
   181  	if shellItem == nil {
   182  		return "", ErrCancelled
   183  	}
   184  	defer shellItem.vtbl.release(unsafe.Pointer(shellItem))
   185  	return shellItem.vtbl.getDisplayName(unsafe.Pointer(shellItem))
   186  }
   187  
   188  func (vtbl *iFileDialogVtbl) setClientGuid(objPtr unsafe.Pointer, guid *ole.GUID) error {
   189  	ret, _, _ := syscall.Syscall(vtbl.SetClientGuid,
   190  		1,
   191  		uintptr(objPtr),
   192  		uintptr(unsafe.Pointer(guid)),
   193  		0)
   194  	return hresultToError(ret)
   195  }
   196  
   197  func (vtbl *iFileDialogVtbl) setDefaultExtension(objPtr unsafe.Pointer, defaultExtension string) error {
   198  	if defaultExtension[0] == '.' {
   199  		defaultExtension = strings.TrimPrefix(defaultExtension, ".")
   200  	}
   201  	defaultExtensionPtr := ole.SysAllocString(defaultExtension)
   202  	ret, _, _ := syscall.Syscall(vtbl.SetDefaultExtension,
   203  		1,
   204  		uintptr(objPtr),
   205  		uintptr(unsafe.Pointer(defaultExtensionPtr)),
   206  		0)
   207  	return hresultToError(ret)
   208  }
   209  
   210  func (vtbl *iFileDialogVtbl) setFileName(objPtr unsafe.Pointer, fileName string) error {
   211  	fileNamePtr := ole.SysAllocString(fileName)
   212  	ret, _, _ := syscall.Syscall(vtbl.SetFileName,
   213  		1,
   214  		uintptr(objPtr),
   215  		uintptr(unsafe.Pointer(fileNamePtr)),
   216  		0)
   217  	return hresultToError(ret)
   218  }
   219  
   220  func (vtbl *iFileDialogVtbl) setSelectedFileFilterIndex(objPtr unsafe.Pointer, index uint) error {
   221  	ret, _, _ := syscall.Syscall(vtbl.SetFileTypeIndex,
   222  		1,
   223  		uintptr(objPtr),
   224  		uintptr(index+1), // SetFileTypeIndex counts from 1
   225  		0)
   226  	return hresultToError(ret)
   227  }