| 
 | 1 | +package image_picker  | 
 | 2 | + | 
 | 3 | +import (  | 
 | 4 | +	"strings"  | 
 | 5 | +	"syscall"  | 
 | 6 | +	"unicode/utf16"  | 
 | 7 | +	"unsafe"  | 
 | 8 | + | 
 | 9 | +	"github.com/pkg/errors"  | 
 | 10 | +)  | 
 | 11 | + | 
 | 12 | +var (  | 
 | 13 | +	comdlg32         = syscall.NewLazyDLL("comdlg32.dll")  | 
 | 14 | +	getOpenFileNameW = comdlg32.NewProc("GetOpenFileNameW")  | 
 | 15 | +)  | 
 | 16 | + | 
 | 17 | +const (  | 
 | 18 | +	maxPath          = 260  | 
 | 19 | +	ofnExplorer      = 0x00080000  | 
 | 20 | +	ofnFileMustExist = 0x00001000  | 
 | 21 | +	ofnHideReadOnly  = 0x00000004  | 
 | 22 | +)  | 
 | 23 | + | 
 | 24 | +type openfilenameW struct {  | 
 | 25 | +	lStructSize       uint32  | 
 | 26 | +	hwndOwner         syscall.Handle  | 
 | 27 | +	hInstance         syscall.Handle  | 
 | 28 | +	lpstrFilter       *uint16  | 
 | 29 | +	lpstrCustomFilter *uint16  | 
 | 30 | +	nMaxCustFilter    uint32  | 
 | 31 | +	nFilterIndex      uint32  | 
 | 32 | +	lpstrFile         *uint16  | 
 | 33 | +	nMaxFile          uint32  | 
 | 34 | +	lpstrFileTitle    *uint16  | 
 | 35 | +	nMaxFileTitle     uint32  | 
 | 36 | +	lpstrInitialDir   *uint16  | 
 | 37 | +	lpstrTitle        *uint16  | 
 | 38 | +	flags             uint32  | 
 | 39 | +	nFileOffset       uint16  | 
 | 40 | +	nFileExtension    uint16  | 
 | 41 | +	lpstrDefExt       *uint16  | 
 | 42 | +	lCustData         uintptr  | 
 | 43 | +	lpfnHook          syscall.Handle  | 
 | 44 | +	lpTemplateName    *uint16  | 
 | 45 | +	pvReserved        unsafe.Pointer  | 
 | 46 | +	dwReserved        uint32  | 
 | 47 | +	flagsEx           uint32  | 
 | 48 | +}  | 
 | 49 | + | 
 | 50 | +func utf16PtrFromString(s string) *uint16 {  | 
 | 51 | +	b := utf16.Encode([]rune(s))  | 
 | 52 | +	return &b[0]  | 
 | 53 | +}  | 
 | 54 | + | 
 | 55 | +func stringFromUtf16Ptr(p *uint16) string {  | 
 | 56 | +	b := *(*[maxPath]uint16)(unsafe.Pointer(p))  | 
 | 57 | +	r := utf16.Decode(b[:])  | 
 | 58 | +	return strings.Trim(string(r), "\x00")  | 
 | 59 | +}  | 
 | 60 | + | 
 | 61 | +func getOpenFileName(lpofn *openfilenameW) bool {  | 
 | 62 | +	ret, _, _ := getOpenFileNameW.Call(uintptr(unsafe.Pointer(lpofn)), 0, 0)  | 
 | 63 | +	return ret != 0  | 
 | 64 | +}  | 
 | 65 | + | 
 | 66 | +func fileDialog(title string, fileType string) (string, error) {  | 
 | 67 | +	var ofn openfilenameW  | 
 | 68 | +	buf := make([]uint16, maxPath)  | 
 | 69 | + | 
 | 70 | +	t, _ := syscall.UTF16PtrFromString(title)  | 
 | 71 | + | 
 | 72 | +	ofn.lStructSize = uint32(unsafe.Sizeof(ofn))  | 
 | 73 | +	ofn.lpstrTitle = t  | 
 | 74 | +	ofn.lpstrFile = &buf[0]  | 
 | 75 | +	ofn.nMaxFile = uint32(len(buf))  | 
 | 76 | + | 
 | 77 | +	var filters string  | 
 | 78 | +	switch fileType {  | 
 | 79 | +	case "image":  | 
 | 80 | +		filters = "Images (*.jpeg,*.png,*.gif)\x00*.jpg;*.jpeg;*.png;*.gif\x00All Files (*.*)\x00*.*\x00\x00"  | 
 | 81 | +	case "video":  | 
 | 82 | +		filters = "Videos (*.webm,*.wmv,*.mpeg,*.mkv,*.mp4,*.avi,*.mov,*.flv)\x00*.webm;*.wmv;*.mpeg;*.mkv;*mp4;*.avi;*.mov;*.flv\x00All Files (*.*)\x00*.*\x00\x00"  | 
 | 83 | +	default:  | 
 | 84 | +		return "", errors.New("unsupported fileType")  | 
 | 85 | +	}  | 
 | 86 | + | 
 | 87 | +	if filters != "" {  | 
 | 88 | +		ofn.lpstrFilter = utf16PtrFromString(filters)  | 
 | 89 | +	}  | 
 | 90 | + | 
 | 91 | +	flags := ofnExplorer | ofnFileMustExist | ofnHideReadOnly  | 
 | 92 | + | 
 | 93 | +	ofn.flags = uint32(flags)  | 
 | 94 | + | 
 | 95 | +	if getOpenFileName(&ofn) {  | 
 | 96 | +		return stringFromUtf16Ptr(ofn.lpstrFile), nil  | 
 | 97 | +	}  | 
 | 98 | + | 
 | 99 | +	return "", nil  | 
 | 100 | + | 
 | 101 | +}  | 
0 commit comments