File API, windows fixes.

This commit is contained in:
Nuno Cruces 2020-01-03 01:44:23 +00:00
parent 6bd07cf824
commit 339101c9f4
6 changed files with 198 additions and 130 deletions

44
file.go
View File

@ -1,6 +1,50 @@
package zenity package zenity
type opts struct {
title string
}
type Option func(*opts)
func (o *opts) Title(title string) {
o.title = title
}
type fileopts struct {
opts
filename string
overwrite bool
filters []FileFilter
}
type FileOption func(*fileopts)
func Filename(filename string) FileOption {
return func(o *fileopts) {
o.filename = filename
}
}
func ConfirmOverwrite(o *fileopts) {
o.overwrite = true
}
type FileFilter struct { type FileFilter struct {
Name string Name string
Exts []string Exts []string
} }
type FileFilters []FileFilter
func (f FileFilters) New() FileOption {
return func(o *fileopts) {
o.filters = f
}
}
func fileoptsParse(options []FileOption) (res fileopts) {
for _, o := range options {
o(&res)
}
return
}

View File

@ -8,13 +8,15 @@ import (
"strings" "strings"
) )
func SelectFile(title, defaultPath string, filters []FileFilter) (string, error) { func SelectFile(options ...FileOption) (string, error) {
opts := fileoptsParse(options)
cmd := exec.Command("osascript", "-l", "JavaScript") cmd := exec.Command("osascript", "-l", "JavaScript")
cmd.Stdin = scriptExpand(scriptData{ cmd.Stdin = scriptExpand(scriptData{
Operation: "chooseFile", Operation: "chooseFile",
Title: title, Prompt: opts.title,
DefaultPath: defaultPath, Location: opts.filename,
Filter: appleFilters(filters), Type: appleFilters(opts.filters),
}) })
out, err := cmd.Output() out, err := cmd.Output()
if err != nil { if err != nil {
@ -26,14 +28,16 @@ func SelectFile(title, defaultPath string, filters []FileFilter) (string, error)
return string(out), nil return string(out), nil
} }
func SelectFileMutiple(title, defaultPath string, filters []FileFilter) ([]string, error) { func SelectFileMutiple(options ...FileOption) ([]string, error) {
opts := fileoptsParse(options)
cmd := exec.Command("osascript", "-l", "JavaScript") cmd := exec.Command("osascript", "-l", "JavaScript")
cmd.Stdin = scriptExpand(scriptData{ cmd.Stdin = scriptExpand(scriptData{
Operation: "chooseFile", Operation: "chooseFile",
Multiple: true, Multiple: true,
Title: title, Prompt: opts.title,
DefaultPath: defaultPath, Location: opts.filename,
Filter: appleFilters(filters), Type: appleFilters(opts.filters),
}) })
out, err := cmd.Output() out, err := cmd.Output()
if err != nil { if err != nil {
@ -48,12 +52,14 @@ func SelectFileMutiple(title, defaultPath string, filters []FileFilter) ([]strin
return strings.Split(string(out), "\x00"), nil return strings.Split(string(out), "\x00"), nil
} }
func SelectFileSave(title, defaultPath string, confirmOverwrite bool, filters []FileFilter) (string, error) { func SelectFileSave(options ...FileOption) (string, error) {
opts := fileoptsParse(options)
cmd := exec.Command("osascript", "-l", "JavaScript") cmd := exec.Command("osascript", "-l", "JavaScript")
cmd.Stdin = scriptExpand(scriptData{ cmd.Stdin = scriptExpand(scriptData{
Operation: "chooseFileName", Operation: "chooseFileName",
Title: title, Prompt: opts.title,
DefaultPath: defaultPath, Location: opts.filename,
}) })
out, err := cmd.Output() out, err := cmd.Output()
if err != nil { if err != nil {
@ -65,12 +71,14 @@ func SelectFileSave(title, defaultPath string, confirmOverwrite bool, filters []
return string(out), nil return string(out), nil
} }
func SelectDirectory(title, defaultPath string) (string, error) { func SelectDirectory(options ...FileOption) (string, error) {
opts := fileoptsParse(options)
cmd := exec.Command("osascript", "-l", "JavaScript") cmd := exec.Command("osascript", "-l", "JavaScript")
cmd.Stdin = scriptExpand(scriptData{ cmd.Stdin = scriptExpand(scriptData{
Operation: "chooseFolder", Operation: "chooseFolder",
Title: title, Prompt: opts.title,
DefaultPath: defaultPath, Location: opts.filename,
}) })
out, err := cmd.Output() out, err := cmd.Output()
if err != nil { if err != nil {
@ -93,11 +101,11 @@ func appleFilters(filters []FileFilter) []string {
} }
type scriptData struct { type scriptData struct {
Operation string Operation string
Title string Prompt string
DefaultPath string Location string
Filter []string Type []string
Multiple bool Multiple bool
} }
func scriptExpand(data scriptData) io.Reader { func scriptExpand(data scriptData) io.Reader {
@ -118,14 +126,14 @@ app.includeStandardAdditions = true;
app.activate(); app.activate();
var opts = {}; var opts = {};
opts.withPrompt = {{.Title}}; opts.withPrompt = {{.Prompt}};
opts.multipleSelectionsAllowed = {{.Multiple}}; opts.multipleSelectionsAllowed = {{.Multiple}};
{{if .DefaultPath}} {{if .Location}}
opts.defaultLocation = {{.DefaultPath}}; opts.defaultLocation = {{.Location}};
{{end}} {{end}}
{{if .Filter}} {{if .Type}}
opts.ofType = {{.Filter}}; opts.ofType = {{.Type}};
{{end}} {{end}}
var res; var res;

View File

@ -5,15 +5,17 @@ import (
"strings" "strings"
) )
func SelectFile(title, defaultPath string, filters []FileFilter) (string, error) { func SelectFile(options ...FileOption) (string, error) {
opts := fileoptsParse(options)
args := []string{"--file-selection"} args := []string{"--file-selection"}
if title != "" { if opts.title != "" {
args = append(args, "--title="+title) args = append(args, "--title="+opts.title)
} }
if defaultPath != "" { if opts.filename != "" {
args = append(args, "--filename="+defaultPath) args = append(args, "--filename="+opts.filename)
} }
args = append(args, zenityFilters(filters)...) args = append(args, zenityFilters(opts.filters)...)
cmd := exec.Command("zenity", args...) cmd := exec.Command("zenity", args...)
out, err := cmd.Output() out, err := cmd.Output()
if err, ok := err.(*exec.ExitError); ok && err.ExitCode() == 1 { if err, ok := err.(*exec.ExitError); ok && err.ExitCode() == 1 {
@ -28,15 +30,17 @@ func SelectFile(title, defaultPath string, filters []FileFilter) (string, error)
return string(out), nil return string(out), nil
} }
func SelectFileMutiple(title, defaultPath string, filters []FileFilter) ([]string, error) { func SelectFileMutiple(options ...FileOption) ([]string, error) {
opts := fileoptsParse(options)
args := []string{"--file-selection", "--multiple", "--separator=\x1e"} args := []string{"--file-selection", "--multiple", "--separator=\x1e"}
if title != "" { if opts.title != "" {
args = append(args, "--title="+title) args = append(args, "--title="+opts.title)
} }
if defaultPath != "" { if opts.filename != "" {
args = append(args, "--filename="+defaultPath) args = append(args, "--filename="+opts.filename)
} }
args = append(args, zenityFilters(filters)...) args = append(args, zenityFilters(opts.filters)...)
cmd := exec.Command("zenity", args...) cmd := exec.Command("zenity", args...)
out, err := cmd.Output() out, err := cmd.Output()
if err, ok := err.(*exec.ExitError); ok && err.ExitCode() == 1 { if err, ok := err.(*exec.ExitError); ok && err.ExitCode() == 1 {
@ -51,18 +55,20 @@ func SelectFileMutiple(title, defaultPath string, filters []FileFilter) ([]strin
return strings.Split(string(out), "\x1e"), nil return strings.Split(string(out), "\x1e"), nil
} }
func SelectFileSave(title, defaultPath string, confirmOverwrite bool, filters []FileFilter) (string, error) { func SelectFileSave(options ...FileOption) (string, error) {
opts := fileoptsParse(options)
args := []string{"--file-selection", "--save"} args := []string{"--file-selection", "--save"}
if title != "" { if opts.title != "" {
args = append(args, "--title="+title) args = append(args, "--title="+opts.title)
} }
if defaultPath != "" { if opts.filename != "" {
args = append(args, "--filename="+defaultPath) args = append(args, "--filename="+opts.filename)
} }
if confirmOverwrite { if opts.overwrite {
args = append(args, "--confirm-overwrite") args = append(args, "--confirm-overwrite")
} }
args = append(args, zenityFilters(filters)...) args = append(args, zenityFilters(opts.filters)...)
cmd := exec.Command("zenity", args...) cmd := exec.Command("zenity", args...)
out, err := cmd.Output() out, err := cmd.Output()
if err, ok := err.(*exec.ExitError); ok && err.ExitCode() == 1 { if err, ok := err.(*exec.ExitError); ok && err.ExitCode() == 1 {
@ -77,13 +83,15 @@ func SelectFileSave(title, defaultPath string, confirmOverwrite bool, filters []
return string(out), nil return string(out), nil
} }
func SelectDirectory(title, defaultPath string) (string, error) { func SelectDirectory(options ...FileOption) (string, error) {
opts := fileoptsParse(options)
args := []string{"--file-selection", "--directory"} args := []string{"--file-selection", "--directory"}
if title != "" { if opts.title != "" {
args = append(args, "--title="+title) args = append(args, "--title="+opts.title)
} }
if defaultPath != "" { if opts.filename != "" {
args = append(args, "--filename="+defaultPath) args = append(args, "--filename="+opts.filename)
} }
cmd := exec.Command("zenity", args...) cmd := exec.Command("zenity", args...)
out, err := cmd.Output() out, err := cmd.Output()

View File

@ -5,11 +5,11 @@ import "testing"
const defaultPath = "" const defaultPath = ""
func TestSelectFile(t *testing.T) { func TestSelectFile(t *testing.T) {
res, err := SelectFile("", defaultPath, []FileFilter{ res, err := SelectFile(Filename(defaultPath), FileFilters{
{"Go files", []string{".go"}}, {"Go files", []string{".go"}},
{"Web files", []string{".html", ".js", ".css"}}, {"Web files", []string{".html", ".js", ".css"}},
{"Image files", []string{".png", ".gif", ".ico", ".jpg", ".webp"}}, {"Image files", []string{".png", ".gif", ".ico", ".jpg", ".webp"}},
}) }.New())
if err != nil { if err != nil {
t.Error(err) t.Error(err)
@ -19,11 +19,11 @@ func TestSelectFile(t *testing.T) {
} }
func TestSelectFileMutiple(t *testing.T) { func TestSelectFileMutiple(t *testing.T) {
res, err := SelectFileMutiple("", defaultPath, []FileFilter{ res, err := SelectFileMutiple(Filename(defaultPath), FileFilters{
{"Go files", []string{".go"}}, {"Go files", []string{".go"}},
{"Web files", []string{".html", ".js", ".css"}}, {"Web files", []string{".html", ".js", ".css"}},
{"Image files", []string{".png", ".gif", ".ico", ".jpg", ".webp"}}, {"Image files", []string{".png", ".gif", ".ico", ".jpg", ".webp"}},
}) }.New())
if err != nil { if err != nil {
t.Error(err) t.Error(err)
@ -33,11 +33,11 @@ func TestSelectFileMutiple(t *testing.T) {
} }
func TestSelectFileSave(t *testing.T) { func TestSelectFileSave(t *testing.T) {
res, err := SelectFileSave("", defaultPath, true, []FileFilter{ res, err := SelectFileSave(Filename(defaultPath), ConfirmOverwrite, FileFilters{
{"Go files", []string{".go"}}, {"Go files", []string{".go"}},
{"Web files", []string{".html", ".js", ".css"}}, {"Web files", []string{".html", ".js", ".css"}},
{"Image files", []string{".png", ".gif", ".ico", ".jpg", ".webp"}}, {"Image files", []string{".png", ".gif", ".ico", ".jpg", ".webp"}},
}) }.New())
if err != nil { if err != nil {
t.Error(err) t.Error(err)
@ -47,7 +47,7 @@ func TestSelectFileSave(t *testing.T) {
} }
func TestSelectDirectory(t *testing.T) { func TestSelectDirectory(t *testing.T) {
res, err := SelectDirectory("", defaultPath) res, err := SelectDirectory(Filename(defaultPath))
if err != nil { if err != nil {
t.Error(err) t.Error(err)

View File

@ -1,10 +1,10 @@
package zenity package zenity
import ( import (
"errors"
"fmt" "fmt"
"path/filepath" "path/filepath"
"reflect" "reflect"
"runtime"
"syscall" "syscall"
"unicode/utf16" "unicode/utf16"
"unsafe" "unsafe"
@ -27,60 +27,58 @@ var (
shCreateItemFromParsingName = shell32.NewProc("SHCreateItemFromParsingName") shCreateItemFromParsingName = shell32.NewProc("SHCreateItemFromParsingName")
) )
func SelectFile(title, defaultPath string, filters []FileFilter) (string, error) { func SelectFile(options ...FileOption) (string, error) {
var args _OPENFILENAME var args _OPENFILENAME
args.StructSize = uint32(unsafe.Sizeof(args)) args.StructSize = uint32(unsafe.Sizeof(args))
args.Flags = 0x80008 // OFN_NOCHANGEDIR|OFN_EXPLORER args.Flags = 0x80008 // OFN_NOCHANGEDIR|OFN_EXPLORER
if title != "" { opts := fileoptsParse(options)
args.Title = syscall.StringToUTF16Ptr(title) if opts.title != "" {
args.Title = syscall.StringToUTF16Ptr(opts.title)
} }
if defaultPath != "" { if opts.filename != "" {
args.InitialDir = syscall.StringToUTF16Ptr(defaultPath) args.InitialDir = syscall.StringToUTF16Ptr(opts.filename)
} }
args.Filter = &windowsFilters(filters)[0] args.Filter = &windowsFilters(opts.filters)[0]
res := [32768]uint16{} res := [32768]uint16{}
args.File = &res[0] args.File = &res[0]
args.MaxFile = uint32(len(res)) args.MaxFile = uint32(len(res))
runtime.LockOSThread()
defer runtime.UnlockOSThread()
n, _, _ := getOpenFileName.Call(uintptr(unsafe.Pointer(&args))) n, _, _ := getOpenFileName.Call(uintptr(unsafe.Pointer(&args)))
if n == 0 { if n == 0 {
n, _, _ = commDlgExtendedError.Call() return "", commDlgError()
if n == 0 {
return "", nil
} else {
return "", fmt.Errorf("Common Dialog error: %x", n)
}
} }
return syscall.UTF16ToString(res[:]), nil return syscall.UTF16ToString(res[:]), nil
} }
func SelectFileMutiple(title, defaultPath string, filters []FileFilter) ([]string, error) { func SelectFileMutiple(options ...FileOption) ([]string, error) {
var args _OPENFILENAME var args _OPENFILENAME
args.StructSize = uint32(unsafe.Sizeof(args)) args.StructSize = uint32(unsafe.Sizeof(args))
args.Flags = 0x80208 // OFN_NOCHANGEDIR|OFN_ALLOWMULTISELECT|OFN_EXPLORER args.Flags = 0x80208 // OFN_NOCHANGEDIR|OFN_ALLOWMULTISELECT|OFN_EXPLORER
if title != "" { opts := fileoptsParse(options)
args.Title = syscall.StringToUTF16Ptr(title) if opts.title != "" {
args.Title = syscall.StringToUTF16Ptr(opts.title)
} }
if defaultPath != "" { if opts.filename != "" {
args.InitialDir = syscall.StringToUTF16Ptr(defaultPath) args.InitialDir = syscall.StringToUTF16Ptr(opts.filename)
} }
args.Filter = &windowsFilters(filters)[0] args.Filter = &windowsFilters(opts.filters)[0]
res := [32768 + 1024*256]uint16{} res := [32768 + 1024*256]uint16{}
args.File = &res[0] args.File = &res[0]
args.MaxFile = uint32(len(res)) args.MaxFile = uint32(len(res))
runtime.LockOSThread()
defer runtime.UnlockOSThread()
n, _, _ := getOpenFileName.Call(uintptr(unsafe.Pointer(&args))) n, _, _ := getOpenFileName.Call(uintptr(unsafe.Pointer(&args)))
if n == 0 { if n == 0 {
n, _, _ = commDlgExtendedError.Call() return nil, commDlgError()
if n == 0 {
return nil, nil
} else {
return nil, fmt.Errorf("Common Dialog error: %x", n)
}
} }
var i int var i int
@ -110,72 +108,78 @@ func SelectFileMutiple(title, defaultPath string, filters []FileFilter) ([]strin
return split, nil return split, nil
} }
func SelectFileSave(title, defaultPath string, confirmOverwrite bool, filters []FileFilter) (string, error) { func SelectFileSave(options ...FileOption) (string, error) {
var args _OPENFILENAME var args _OPENFILENAME
args.StructSize = uint32(unsafe.Sizeof(args)) args.StructSize = uint32(unsafe.Sizeof(args))
args.Flags = 0x80008 // OFN_NOCHANGEDIR|OFN_EXPLORER args.Flags = 0x80008 // OFN_NOCHANGEDIR|OFN_EXPLORER
if title != "" { opts := fileoptsParse(options)
args.Title = syscall.StringToUTF16Ptr(title) if opts.title != "" {
args.Title = syscall.StringToUTF16Ptr(opts.title)
} }
if defaultPath != "" { if opts.filename != "" {
args.InitialDir = syscall.StringToUTF16Ptr(defaultPath) args.InitialDir = syscall.StringToUTF16Ptr(opts.filename)
} }
if confirmOverwrite { if opts.overwrite {
args.Flags |= 0x2 // OFN_OVERWRITEPROMPT args.Flags |= 0x2 // OFN_OVERWRITEPROMPT
} }
args.Filter = &windowsFilters(filters)[0] args.Filter = &windowsFilters(opts.filters)[0]
res := [32768]uint16{} res := [32768]uint16{}
args.File = &res[0] args.File = &res[0]
args.MaxFile = uint32(len(res)) args.MaxFile = uint32(len(res))
runtime.LockOSThread()
defer runtime.UnlockOSThread()
n, _, _ := getSaveFileName.Call(uintptr(unsafe.Pointer(&args))) n, _, _ := getSaveFileName.Call(uintptr(unsafe.Pointer(&args)))
if n == 0 { if n == 0 {
n, _, _ = commDlgExtendedError.Call() return "", commDlgError()
if n == 0 {
return "", nil
} else {
return "", fmt.Errorf("Common Dialog error: %x", n)
}
} }
return syscall.UTF16ToString(res[:]), nil return syscall.UTF16ToString(res[:]), nil
} }
func SelectDirectory(title, defaultPath string) (string, error) { func SelectDirectory(options ...FileOption) (string, error) {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
hr, _, _ := coInitializeEx.Call(0, 0x6) // COINIT_APARTMENTTHREADED|COINIT_DISABLE_OLE1DDE hr, _, _ := coInitializeEx.Call(0, 0x6) // COINIT_APARTMENTTHREADED|COINIT_DISABLE_OLE1DDE
if hr < 0 { if hr != 0x80010106 { // RPC_E_CHANGED_MODE
return "", errors.New("COM initialization failed.") if int32(hr) < 0 {
return "", syscall.Errno(hr)
}
defer coUninitialize.Call()
} }
defer coUninitialize.Call()
opts := fileoptsParse(options)
var dialog *_IFileOpenDialog var dialog *_IFileOpenDialog
hr, _, _ = coCreateInstance.Call( hr, _, _ = coCreateInstance.Call(
_CLSID_FileOpenDialog, 0, 0x17, // CLSCTX_ALL _CLSID_FileOpenDialog, 0, 0x17, // CLSCTX_ALL
_IID_IFileOpenDialog, uintptr(unsafe.Pointer(&dialog))) _IID_IFileOpenDialog, uintptr(unsafe.Pointer(&dialog)))
if hr < 0 || dialog == nil { if int32(hr) < 0 {
return browseForFolder(title, defaultPath) return browseForFolder(opts.title)
} }
defer dialog.Call(dialog.vtbl.Release) defer dialog.Call(dialog.vtbl.Release)
var opts int var flgs int
hr, _, _ = dialog.Call(dialog.vtbl.GetOptions, uintptr(unsafe.Pointer(&opts))) hr, _, _ = dialog.Call(dialog.vtbl.GetOptions, uintptr(unsafe.Pointer(&flgs)))
if hr < 0 { if int32(hr) < 0 {
return "", fmt.Errorf("IFileOpenDialog.GetOptions error: %x", hr) return "", syscall.Errno(hr)
} }
hr, _, _ = dialog.Call(dialog.vtbl.SetOptions, uintptr(opts|0x68)) // FOS_NOCHANGEDIR|FOS_PICKFOLDERS|FOS_FORCEFILESYSTEM hr, _, _ = dialog.Call(dialog.vtbl.SetOptions, uintptr(flgs|0x68)) // FOS_NOCHANGEDIR|FOS_PICKFOLDERS|FOS_FORCEFILESYSTEM
if hr < 0 { if int32(hr) < 0 {
return "", fmt.Errorf("IFileOpenDialog.SetOptions error: %x", hr) return "", syscall.Errno(hr)
} }
if title != "" { if opts.title != "" {
ptr := syscall.StringToUTF16Ptr(title) ptr := syscall.StringToUTF16Ptr(opts.title)
dialog.Call(dialog.vtbl.SetTitle, uintptr(unsafe.Pointer(ptr))) dialog.Call(dialog.vtbl.SetTitle, uintptr(unsafe.Pointer(ptr)))
} }
if defaultPath != "" { if opts.filename != "" {
var item *_IShellItem var item *_IShellItem
ptr := syscall.StringToUTF16Ptr(defaultPath) ptr := syscall.StringToUTF16Ptr(opts.filename)
hr, _, _ = shCreateItemFromParsingName.Call( hr, _, _ = shCreateItemFromParsingName.Call(
uintptr(unsafe.Pointer(ptr)), 0, uintptr(unsafe.Pointer(ptr)), 0,
_IID_IShellItem, _IID_IShellItem,
@ -188,17 +192,17 @@ func SelectDirectory(title, defaultPath string) (string, error) {
} }
hr, _, _ = dialog.Call(dialog.vtbl.Show, 0) hr, _, _ = dialog.Call(dialog.vtbl.Show, 0)
if hr < 0 { if hr == 0x800704c7 { // ERROR_CANCELLED
return "", fmt.Errorf("IFileOpenDialog.Show error: %x", hr) return "", nil
}
if int32(hr) < 0 {
return "", syscall.Errno(hr)
} }
var item *_IShellItem var item *_IShellItem
hr, _, _ = dialog.Call(dialog.vtbl.GetResult, uintptr(unsafe.Pointer(&item))) hr, _, _ = dialog.Call(dialog.vtbl.GetResult, uintptr(unsafe.Pointer(&item)))
if hr < 0 { if int32(hr) < 0 {
return "", fmt.Errorf("IFileOpenDialog.GetResult error: %x", hr) return "", syscall.Errno(hr)
}
if item == nil {
return "", nil
} }
defer item.Call(item.vtbl.Release) defer item.Call(item.vtbl.Release)
@ -206,8 +210,8 @@ func SelectDirectory(title, defaultPath string) (string, error) {
hr, _, _ = item.Call(item.vtbl.GetDisplayName, hr, _, _ = item.Call(item.vtbl.GetDisplayName,
0x80058000, // SIGDN_FILESYSPATH 0x80058000, // SIGDN_FILESYSPATH
uintptr(unsafe.Pointer(&ptr))) uintptr(unsafe.Pointer(&ptr)))
if hr < 0 { if int32(hr) < 0 {
return "", fmt.Errorf("IShellItem.GetDisplayName error: %x", hr) return "", syscall.Errno(hr)
} }
defer coTaskMemFree.Call(ptr) defer coTaskMemFree.Call(ptr)
@ -215,7 +219,7 @@ func SelectDirectory(title, defaultPath string) (string, error) {
return syscall.UTF16ToString(*(*[]uint16)(unsafe.Pointer(&res))), nil return syscall.UTF16ToString(*(*[]uint16)(unsafe.Pointer(&res))), nil
} }
func browseForFolder(title, defaultPath string) (string, error) { func browseForFolder(title string) (string, error) {
var args _BROWSEINFO var args _BROWSEINFO
args.Flags = 0x1 // BIF_RETURNONLYFSDIRS args.Flags = 0x1 // BIF_RETURNONLYFSDIRS
@ -253,6 +257,15 @@ func windowsFilters(filters []FileFilter) []uint16 {
return res return res
} }
func commDlgError() error {
n, _, _ := commDlgExtendedError.Call()
if n == 0 {
return nil
} else {
return fmt.Errorf("Common Dialog error: %x", n)
}
}
type _OPENFILENAME struct { type _OPENFILENAME struct {
StructSize uint32 StructSize uint32
Owner uintptr Owner uintptr

View File

@ -1,10 +1,5 @@
package zenity package zenity
import (
"syscall"
)
func init() { func init() {
user32 := syscall.NewLazyDLL("user32.dll")
user32.NewProc("SetProcessDPIAware").Call() user32.NewProc("SetProcessDPIAware").Call()
} }