Refactor (windows).
This commit is contained in:
parent
176a3d48a1
commit
d33a18d05a
13 changed files with 403 additions and 220 deletions
|
@ -1,6 +1,10 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -Eeuo pipefail
|
set -Eeuo pipefail
|
||||||
|
|
||||||
|
cd "${BASH_SOURCE%/*}"
|
||||||
|
|
||||||
|
go generate ../../...
|
||||||
|
|
||||||
TAG=$(git tag --points-at HEAD)
|
TAG=$(git tag --points-at HEAD)
|
||||||
echo 'package main; const tag = "'$TAG'"' > tag.go
|
echo 'package main; const tag = "'$TAG'"' > tag.go
|
||||||
|
|
||||||
|
|
|
@ -4,11 +4,11 @@ import (
|
||||||
"image/color"
|
"image/color"
|
||||||
"sync"
|
"sync"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/ncruces/zenity/internal/win"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
chooseColor = comdlg32.NewProc("ChooseColorW")
|
|
||||||
|
|
||||||
savedColors [16]uint32
|
savedColors [16]uint32
|
||||||
colorsMutex sync.Mutex
|
colorsMutex sync.Mutex
|
||||||
)
|
)
|
||||||
|
@ -19,32 +19,26 @@ func init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
|
||||||
_CC_RGBINIT = 0x00000001
|
|
||||||
_CC_FULLOPEN = 0x00000002
|
|
||||||
_CC_PREVENTFULLOPEN = 0x00000004
|
|
||||||
)
|
|
||||||
|
|
||||||
func selectColor(opts options) (color.Color, error) {
|
func selectColor(opts options) (color.Color, error) {
|
||||||
// load custom colors
|
// load custom colors
|
||||||
colorsMutex.Lock()
|
colorsMutex.Lock()
|
||||||
customColors := savedColors
|
customColors := savedColors
|
||||||
colorsMutex.Unlock()
|
colorsMutex.Unlock()
|
||||||
|
|
||||||
var args _CHOOSECOLOR
|
var args win.CHOOSECOLOR
|
||||||
args.StructSize = uint32(unsafe.Sizeof(args))
|
args.StructSize = uint32(unsafe.Sizeof(args))
|
||||||
args.Owner, _ = opts.attach.(uintptr)
|
args.Owner, _ = opts.attach.(uintptr)
|
||||||
args.CustColors = &customColors
|
args.CustColors = &customColors
|
||||||
|
|
||||||
if opts.color != nil {
|
if opts.color != nil {
|
||||||
args.Flags |= _CC_RGBINIT
|
args.Flags |= win.CC_RGBINIT
|
||||||
n := color.NRGBAModel.Convert(opts.color).(color.NRGBA)
|
n := color.NRGBAModel.Convert(opts.color).(color.NRGBA)
|
||||||
args.RgbResult = uint32(n.R) | uint32(n.G)<<8 | uint32(n.B)<<16
|
args.RgbResult = uint32(n.R) | uint32(n.G)<<8 | uint32(n.B)<<16
|
||||||
}
|
}
|
||||||
if opts.showPalette {
|
if opts.showPalette {
|
||||||
args.Flags |= _CC_PREVENTFULLOPEN
|
args.Flags |= win.CC_PREVENTFULLOPEN
|
||||||
} else {
|
} else {
|
||||||
args.Flags |= _CC_FULLOPEN
|
args.Flags |= win.CC_FULLOPEN
|
||||||
}
|
}
|
||||||
|
|
||||||
defer setup()()
|
defer setup()()
|
||||||
|
@ -57,12 +51,12 @@ func selectColor(opts options) (color.Color, error) {
|
||||||
defer unhook()
|
defer unhook()
|
||||||
}
|
}
|
||||||
|
|
||||||
s, _, _ := chooseColor.Call(uintptr(unsafe.Pointer(&args)))
|
ok := win.ChooseColor(&args)
|
||||||
if opts.ctx != nil && opts.ctx.Err() != nil {
|
if opts.ctx != nil && opts.ctx.Err() != nil {
|
||||||
return nil, opts.ctx.Err()
|
return nil, opts.ctx.Err()
|
||||||
}
|
}
|
||||||
if s == 0 {
|
if !ok {
|
||||||
return nil, commDlgError()
|
return nil, win.CommDlgError()
|
||||||
}
|
}
|
||||||
|
|
||||||
// save custom colors back
|
// save custom colors back
|
||||||
|
@ -75,16 +69,3 @@ func selectColor(opts options) (color.Color, error) {
|
||||||
b := uint8(args.RgbResult >> 16)
|
b := uint8(args.RgbResult >> 16)
|
||||||
return color.RGBA{R: r, G: g, B: b, A: 255}, nil
|
return color.RGBA{R: r, G: g, B: b, A: 255}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://docs.microsoft.com/en-us/windows/win32/api/commdlg/ns-commdlg-choosecolorw-r1
|
|
||||||
type _CHOOSECOLOR struct {
|
|
||||||
StructSize uint32
|
|
||||||
Owner uintptr
|
|
||||||
Instance uintptr
|
|
||||||
RgbResult uint32
|
|
||||||
CustColors *[16]uint32
|
|
||||||
Flags uint32
|
|
||||||
CustData uintptr
|
|
||||||
FnHook uintptr
|
|
||||||
TemplateName *uint16
|
|
||||||
}
|
|
||||||
|
|
162
file_windows.go
162
file_windows.go
|
@ -7,27 +7,11 @@ import (
|
||||||
"syscall"
|
"syscall"
|
||||||
"unicode/utf16"
|
"unicode/utf16"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
"github.com/ncruces/zenity/internal/win"
|
||||||
getOpenFileName = comdlg32.NewProc("GetOpenFileNameW")
|
|
||||||
getSaveFileName = comdlg32.NewProc("GetSaveFileNameW")
|
|
||||||
shBrowseForFolder = shell32.NewProc("SHBrowseForFolderW")
|
|
||||||
shCreateItemFromParsingName = shell32.NewProc("SHCreateItemFromParsingName")
|
|
||||||
shGetPathFromIDListEx = shell32.NewProc("SHGetPathFromIDListEx")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
_OFN_OVERWRITEPROMPT = 0x00000002
|
|
||||||
_OFN_NOCHANGEDIR = 0x00000008
|
|
||||||
_OFN_ALLOWMULTISELECT = 0x00000200
|
|
||||||
_OFN_PATHMUSTEXIST = 0x00000800
|
|
||||||
_OFN_FILEMUSTEXIST = 0x00001000
|
|
||||||
_OFN_CREATEPROMPT = 0x00002000
|
|
||||||
_OFN_NOREADONLYRETURN = 0x00008000
|
|
||||||
_OFN_EXPLORER = 0x00080000
|
|
||||||
_OFN_FORCESHOWHIDDEN = 0x10000000
|
|
||||||
|
|
||||||
_FOS_NOCHANGEDIR = 0x00000008
|
_FOS_NOCHANGEDIR = 0x00000008
|
||||||
_FOS_PICKFOLDERS = 0x00000020
|
_FOS_PICKFOLDERS = 0x00000020
|
||||||
_FOS_FORCEFILESYSTEM = 0x00000040
|
_FOS_FORCEFILESYSTEM = 0x00000040
|
||||||
|
@ -41,16 +25,16 @@ func selectFile(opts options) (string, error) {
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var args _OPENFILENAME
|
var args win.OPENFILENAME
|
||||||
args.StructSize = uint32(unsafe.Sizeof(args))
|
args.StructSize = uint32(unsafe.Sizeof(args))
|
||||||
args.Owner, _ = opts.attach.(uintptr)
|
args.Owner, _ = opts.attach.(uintptr)
|
||||||
args.Flags = _OFN_NOCHANGEDIR | _OFN_FILEMUSTEXIST | _OFN_EXPLORER
|
args.Flags = win.OFN_NOCHANGEDIR | win.OFN_FILEMUSTEXIST | win.OFN_EXPLORER
|
||||||
|
|
||||||
if opts.title != nil {
|
if opts.title != nil {
|
||||||
args.Title = syscall.StringToUTF16Ptr(*opts.title)
|
args.Title = syscall.StringToUTF16Ptr(*opts.title)
|
||||||
}
|
}
|
||||||
if opts.showHidden {
|
if opts.showHidden {
|
||||||
args.Flags |= _OFN_FORCESHOWHIDDEN
|
args.Flags |= win.OFN_FORCESHOWHIDDEN
|
||||||
}
|
}
|
||||||
if opts.fileFilters != nil {
|
if opts.fileFilters != nil {
|
||||||
args.Filter = &initFilters(opts.fileFilters)[0]
|
args.Filter = &initFilters(opts.fileFilters)[0]
|
||||||
|
@ -71,12 +55,12 @@ func selectFile(opts options) (string, error) {
|
||||||
defer unhook()
|
defer unhook()
|
||||||
}
|
}
|
||||||
|
|
||||||
s, _, _ := getOpenFileName.Call(uintptr(unsafe.Pointer(&args)))
|
ok := win.GetOpenFileName(&args)
|
||||||
if opts.ctx != nil && opts.ctx.Err() != nil {
|
if opts.ctx != nil && opts.ctx.Err() != nil {
|
||||||
return "", opts.ctx.Err()
|
return "", opts.ctx.Err()
|
||||||
}
|
}
|
||||||
if s == 0 {
|
if !ok {
|
||||||
return "", commDlgError()
|
return "", win.CommDlgError()
|
||||||
}
|
}
|
||||||
return syscall.UTF16ToString(res[:]), nil
|
return syscall.UTF16ToString(res[:]), nil
|
||||||
}
|
}
|
||||||
|
@ -87,16 +71,16 @@ func selectFileMultiple(opts options) ([]string, error) {
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var args _OPENFILENAME
|
var args win.OPENFILENAME
|
||||||
args.StructSize = uint32(unsafe.Sizeof(args))
|
args.StructSize = uint32(unsafe.Sizeof(args))
|
||||||
args.Owner, _ = opts.attach.(uintptr)
|
args.Owner, _ = opts.attach.(uintptr)
|
||||||
args.Flags = _OFN_NOCHANGEDIR | _OFN_ALLOWMULTISELECT | _OFN_FILEMUSTEXIST | _OFN_EXPLORER
|
args.Flags = win.OFN_NOCHANGEDIR | win.OFN_ALLOWMULTISELECT | win.OFN_FILEMUSTEXIST | win.OFN_EXPLORER
|
||||||
|
|
||||||
if opts.title != nil {
|
if opts.title != nil {
|
||||||
args.Title = syscall.StringToUTF16Ptr(*opts.title)
|
args.Title = syscall.StringToUTF16Ptr(*opts.title)
|
||||||
}
|
}
|
||||||
if opts.showHidden {
|
if opts.showHidden {
|
||||||
args.Flags |= _OFN_FORCESHOWHIDDEN
|
args.Flags |= win.OFN_FORCESHOWHIDDEN
|
||||||
}
|
}
|
||||||
if opts.fileFilters != nil {
|
if opts.fileFilters != nil {
|
||||||
args.Filter = &initFilters(opts.fileFilters)[0]
|
args.Filter = &initFilters(opts.fileFilters)[0]
|
||||||
|
@ -117,12 +101,12 @@ func selectFileMultiple(opts options) ([]string, error) {
|
||||||
defer unhook()
|
defer unhook()
|
||||||
}
|
}
|
||||||
|
|
||||||
s, _, _ := getOpenFileName.Call(uintptr(unsafe.Pointer(&args)))
|
ok := win.GetOpenFileName(&args)
|
||||||
if opts.ctx != nil && opts.ctx.Err() != nil {
|
if opts.ctx != nil && opts.ctx.Err() != nil {
|
||||||
return nil, opts.ctx.Err()
|
return nil, opts.ctx.Err()
|
||||||
}
|
}
|
||||||
if s == 0 {
|
if !ok {
|
||||||
return nil, commDlgError()
|
return nil, win.CommDlgError()
|
||||||
}
|
}
|
||||||
|
|
||||||
var i int
|
var i int
|
||||||
|
@ -158,22 +142,22 @@ func selectFileSave(opts options) (string, error) {
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var args _OPENFILENAME
|
var args win.OPENFILENAME
|
||||||
args.StructSize = uint32(unsafe.Sizeof(args))
|
args.StructSize = uint32(unsafe.Sizeof(args))
|
||||||
args.Owner, _ = opts.attach.(uintptr)
|
args.Owner, _ = opts.attach.(uintptr)
|
||||||
args.Flags = _OFN_NOCHANGEDIR | _OFN_PATHMUSTEXIST | _OFN_NOREADONLYRETURN | _OFN_EXPLORER
|
args.Flags = win.OFN_NOCHANGEDIR | win.OFN_PATHMUSTEXIST | win.OFN_NOREADONLYRETURN | win.OFN_EXPLORER
|
||||||
|
|
||||||
if opts.title != nil {
|
if opts.title != nil {
|
||||||
args.Title = syscall.StringToUTF16Ptr(*opts.title)
|
args.Title = syscall.StringToUTF16Ptr(*opts.title)
|
||||||
}
|
}
|
||||||
if opts.confirmOverwrite {
|
if opts.confirmOverwrite {
|
||||||
args.Flags |= _OFN_OVERWRITEPROMPT
|
args.Flags |= win.OFN_OVERWRITEPROMPT
|
||||||
}
|
}
|
||||||
if opts.confirmCreate {
|
if opts.confirmCreate {
|
||||||
args.Flags |= _OFN_CREATEPROMPT
|
args.Flags |= win.OFN_CREATEPROMPT
|
||||||
}
|
}
|
||||||
if opts.showHidden {
|
if opts.showHidden {
|
||||||
args.Flags |= _OFN_FORCESHOWHIDDEN
|
args.Flags |= win.OFN_FORCESHOWHIDDEN
|
||||||
}
|
}
|
||||||
if opts.fileFilters != nil {
|
if opts.fileFilters != nil {
|
||||||
args.Filter = &initFilters(opts.fileFilters)[0]
|
args.Filter = &initFilters(opts.fileFilters)[0]
|
||||||
|
@ -194,12 +178,12 @@ func selectFileSave(opts options) (string, error) {
|
||||||
defer unhook()
|
defer unhook()
|
||||||
}
|
}
|
||||||
|
|
||||||
s, _, _ := getSaveFileName.Call(uintptr(unsafe.Pointer(&args)))
|
ok := win.GetSaveFileName(&args)
|
||||||
if opts.ctx != nil && opts.ctx.Err() != nil {
|
if opts.ctx != nil && opts.ctx.Err() != nil {
|
||||||
return "", opts.ctx.Err()
|
return "", opts.ctx.Err()
|
||||||
}
|
}
|
||||||
if s == 0 {
|
if !ok {
|
||||||
return "", commDlgError()
|
return "", win.CommDlgError()
|
||||||
}
|
}
|
||||||
return syscall.UTF16ToString(res[:]), nil
|
return syscall.UTF16ToString(res[:]), nil
|
||||||
}
|
}
|
||||||
|
@ -207,19 +191,19 @@ func selectFileSave(opts options) (string, error) {
|
||||||
func pickFolders(opts options, multi bool) (str string, lst []string, err error) {
|
func pickFolders(opts options, multi bool) (str string, lst []string, err error) {
|
||||||
defer setup()()
|
defer setup()()
|
||||||
|
|
||||||
hr, _, _ := coInitializeEx.Call(0, 0x6) // COINIT_APARTMENTTHREADED|COINIT_DISABLE_OLE1DDE
|
err = win.CoInitializeEx(0, 0x6) // COINIT_APARTMENTTHREADED|COINIT_DISABLE_OLE1DDE
|
||||||
if hr != 0x80010106 { // RPC_E_CHANGED_MODE
|
if err != win.RPC_E_CHANGED_MODE {
|
||||||
if int32(hr) < 0 {
|
if err != nil {
|
||||||
return "", nil, syscall.Errno(hr)
|
return "", nil, err
|
||||||
}
|
}
|
||||||
defer coUninitialize.Call()
|
defer win.CoUninitialize()
|
||||||
}
|
}
|
||||||
|
|
||||||
var dialog *_IFileOpenDialog
|
var dialog *_IFileOpenDialog
|
||||||
hr, _, _ = coCreateInstance.Call(
|
err = win.CoCreateInstance(
|
||||||
_CLSID_FileOpenDialog, 0, 0x17, // CLSCTX_ALL
|
_CLSID_FileOpenDialog, nil, 0x17, // CLSCTX_ALL
|
||||||
_IID_IFileOpenDialog, uintptr(unsafe.Pointer(&dialog)))
|
_IID_IFileOpenDialog, unsafe.Pointer(&dialog))
|
||||||
if int32(hr) < 0 {
|
if err != nil {
|
||||||
if multi {
|
if multi {
|
||||||
return "", nil, fmt.Errorf("%w: multiple directory", ErrUnsupported)
|
return "", nil, fmt.Errorf("%w: multiple directory", ErrUnsupported)
|
||||||
}
|
}
|
||||||
|
@ -228,7 +212,7 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error)
|
||||||
defer dialog.Call(dialog.Release)
|
defer dialog.Call(dialog.Release)
|
||||||
|
|
||||||
var flgs int
|
var flgs int
|
||||||
hr, _, _ = dialog.Call(dialog.GetOptions, uintptr(unsafe.Pointer(&flgs)))
|
hr, _, _ := dialog.Call(dialog.GetOptions, uintptr(unsafe.Pointer(&flgs)))
|
||||||
if int32(hr) < 0 {
|
if int32(hr) < 0 {
|
||||||
return "", nil, syscall.Errno(hr)
|
return "", nil, syscall.Errno(hr)
|
||||||
}
|
}
|
||||||
|
@ -250,12 +234,9 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.filename != "" {
|
if opts.filename != "" {
|
||||||
var item *_IShellItem
|
var item *win.IShellItem
|
||||||
ptr := syscall.StringToUTF16Ptr(opts.filename)
|
ptr := syscall.StringToUTF16Ptr(opts.filename)
|
||||||
hr, _, _ = shCreateItemFromParsingName.Call(
|
win.SHCreateItemFromParsingName(ptr, nil, _IID_IShellItem, &item)
|
||||||
uintptr(unsafe.Pointer(ptr)), 0,
|
|
||||||
_IID_IShellItem,
|
|
||||||
uintptr(unsafe.Pointer(&item)))
|
|
||||||
|
|
||||||
if int32(hr) >= 0 && item != nil {
|
if int32(hr) >= 0 && item != nil {
|
||||||
dialog.Call(dialog.SetFolder, uintptr(unsafe.Pointer(item)))
|
dialog.Call(dialog.SetFolder, uintptr(unsafe.Pointer(item)))
|
||||||
|
@ -283,8 +264,8 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error)
|
||||||
return "", nil, syscall.Errno(hr)
|
return "", nil, syscall.Errno(hr)
|
||||||
}
|
}
|
||||||
|
|
||||||
shellItemPath := func(obj *_COMObject, trap uintptr, a ...uintptr) error {
|
shellItemPath := func(obj *win.COMObject, trap uintptr, a ...uintptr) error {
|
||||||
var item *_IShellItem
|
var item *win.IShellItem
|
||||||
hr, _, _ := obj.Call(trap, append(a, uintptr(unsafe.Pointer(&item)))...)
|
hr, _, _ := obj.Call(trap, append(a, uintptr(unsafe.Pointer(&item)))...)
|
||||||
if int32(hr) < 0 {
|
if int32(hr) < 0 {
|
||||||
return syscall.Errno(hr)
|
return syscall.Errno(hr)
|
||||||
|
@ -298,11 +279,11 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error)
|
||||||
if int32(hr) < 0 {
|
if int32(hr) < 0 {
|
||||||
return syscall.Errno(hr)
|
return syscall.Errno(hr)
|
||||||
}
|
}
|
||||||
defer coTaskMemFree.Call(ptr)
|
defer win.CoTaskMemFree(ptr)
|
||||||
|
|
||||||
var res []uint16
|
var res []uint16
|
||||||
hdr := (*reflect.SliceHeader)(unsafe.Pointer(&res))
|
hdr := (*reflect.SliceHeader)(unsafe.Pointer(&res))
|
||||||
hdr.Data, hdr.Len, hdr.Cap = ptr, 32768, 32768
|
hdr.Data, hdr.Len, hdr.Cap = uintptr(ptr), 32768, 32768
|
||||||
str = syscall.UTF16ToString(res)
|
str = syscall.UTF16ToString(res)
|
||||||
lst = append(lst, str)
|
lst = append(lst, str)
|
||||||
return nil
|
return nil
|
||||||
|
@ -322,16 +303,16 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error)
|
||||||
return "", nil, syscall.Errno(hr)
|
return "", nil, syscall.Errno(hr)
|
||||||
}
|
}
|
||||||
for i := uintptr(0); i < uintptr(count) && err == nil; i++ {
|
for i := uintptr(0); i < uintptr(count) && err == nil; i++ {
|
||||||
err = shellItemPath(&items._COMObject, items.GetItemAt, i)
|
err = shellItemPath(&items.COMObject, items.GetItemAt, i)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
err = shellItemPath(&dialog._COMObject, dialog.GetResult)
|
err = shellItemPath(&dialog.COMObject, dialog.GetResult)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func browseForFolder(opts options) (string, []string, error) {
|
func browseForFolder(opts options) (string, []string, error) {
|
||||||
var args _BROWSEINFO
|
var args win.BROWSEINFO
|
||||||
args.Owner, _ = opts.attach.(uintptr)
|
args.Owner, _ = opts.attach.(uintptr)
|
||||||
args.Flags = 0x1 // BIF_RETURNONLYFSDIRS
|
args.Flags = 0x1 // BIF_RETURNONLYFSDIRS
|
||||||
|
|
||||||
|
@ -351,17 +332,17 @@ func browseForFolder(opts options) (string, []string, error) {
|
||||||
defer unhook()
|
defer unhook()
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr, _, _ := shBrowseForFolder.Call(uintptr(unsafe.Pointer(&args)))
|
ptr := win.SHBrowseForFolder(&args)
|
||||||
if opts.ctx != nil && opts.ctx.Err() != nil {
|
if opts.ctx != nil && opts.ctx.Err() != nil {
|
||||||
return "", nil, opts.ctx.Err()
|
return "", nil, opts.ctx.Err()
|
||||||
}
|
}
|
||||||
if ptr == 0 {
|
if ptr == 0 {
|
||||||
return "", nil, ErrCanceled
|
return "", nil, ErrCanceled
|
||||||
}
|
}
|
||||||
defer coTaskMemFree.Call(ptr)
|
defer win.CoTaskMemFree(ptr)
|
||||||
|
|
||||||
var res [32768]uint16
|
var res [32768]uint16
|
||||||
shGetPathFromIDListEx.Call(ptr, uintptr(unsafe.Pointer(&res[0])), uintptr(len(res)), 0)
|
win.SHGetPathFromIDListEx(ptr, &res[0], len(res), 0)
|
||||||
|
|
||||||
str := syscall.UTF16ToString(res[:])
|
str := syscall.UTF16ToString(res[:])
|
||||||
return str, []string{str}, nil
|
return str, []string{str}, nil
|
||||||
|
@ -408,45 +389,6 @@ func initFilters(filters FileFilters) []uint16 {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://docs.microsoft.com/en-us/windows/win32/api/commdlg/ns-commdlg-openfilenamew
|
|
||||||
type _OPENFILENAME struct {
|
|
||||||
StructSize uint32
|
|
||||||
Owner uintptr
|
|
||||||
Instance uintptr
|
|
||||||
Filter *uint16
|
|
||||||
CustomFilter *uint16
|
|
||||||
MaxCustomFilter uint32
|
|
||||||
FilterIndex uint32
|
|
||||||
File *uint16
|
|
||||||
MaxFile uint32
|
|
||||||
FileTitle *uint16
|
|
||||||
MaxFileTitle uint32
|
|
||||||
InitialDir *uint16
|
|
||||||
Title *uint16
|
|
||||||
Flags uint32
|
|
||||||
FileOffset uint16
|
|
||||||
FileExtension uint16
|
|
||||||
DefExt *uint16
|
|
||||||
CustData uintptr
|
|
||||||
FnHook uintptr
|
|
||||||
TemplateName *uint16
|
|
||||||
PvReserved uintptr
|
|
||||||
DwReserved uint32
|
|
||||||
FlagsEx uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://docs.microsoft.com/en-us/windows/win32/api/shlobj_core/ns-shlobj_core-browseinfow
|
|
||||||
type _BROWSEINFO struct {
|
|
||||||
Owner uintptr
|
|
||||||
Root uintptr
|
|
||||||
DisplayName *uint16
|
|
||||||
Title *uint16
|
|
||||||
Flags uint32
|
|
||||||
CallbackFunc uintptr
|
|
||||||
LParam *uint16
|
|
||||||
Image int32
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://github.com/wine-mirror/wine/blob/master/include/shobjidl.idl
|
// https://github.com/wine-mirror/wine/blob/master/include/shobjidl.idl
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -456,17 +398,12 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
type _IFileOpenDialog struct {
|
type _IFileOpenDialog struct {
|
||||||
_COMObject
|
win.COMObject
|
||||||
*_IFileOpenDialogVtbl
|
*_IFileOpenDialogVtbl
|
||||||
}
|
}
|
||||||
|
|
||||||
type _IShellItem struct {
|
|
||||||
_COMObject
|
|
||||||
*_IShellItemVtbl
|
|
||||||
}
|
|
||||||
|
|
||||||
type _IShellItemArray struct {
|
type _IShellItemArray struct {
|
||||||
_COMObject
|
win.COMObject
|
||||||
*_IShellItemArrayVtbl
|
*_IShellItemArrayVtbl
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -508,15 +445,6 @@ type _IModalWindowVtbl struct {
|
||||||
Show uintptr
|
Show uintptr
|
||||||
}
|
}
|
||||||
|
|
||||||
type _IShellItemVtbl struct {
|
|
||||||
_IUnknownVtbl
|
|
||||||
BindToHandler uintptr
|
|
||||||
GetParent uintptr
|
|
||||||
GetDisplayName uintptr
|
|
||||||
GetAttributes uintptr
|
|
||||||
Compare uintptr
|
|
||||||
}
|
|
||||||
|
|
||||||
type _IShellItemArrayVtbl struct {
|
type _IShellItemArrayVtbl struct {
|
||||||
_IUnknownVtbl
|
_IUnknownVtbl
|
||||||
BindToHandler uintptr
|
BindToHandler uintptr
|
||||||
|
|
4
go.mod
4
go.mod
|
@ -8,8 +8,8 @@ require (
|
||||||
github.com/ncruces/go-strftime v0.1.8
|
github.com/ncruces/go-strftime v0.1.8
|
||||||
github.com/randall77/makefat v0.0.0-20210315173500-7ddd0e42c844
|
github.com/randall77/makefat v0.0.0-20210315173500-7ddd0e42c844
|
||||||
go.uber.org/goleak v1.1.12 // test
|
go.uber.org/goleak v1.1.12 // test
|
||||||
golang.org/x/image v0.0.0-20220601225756-64ec528b34cd
|
golang.org/x/image v0.0.0-20220617043117-41969df76e82
|
||||||
golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d
|
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
|
8
go.sum
8
go.sum
|
@ -24,8 +24,8 @@ go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
|
||||||
go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/image v0.0.0-20220601225756-64ec528b34cd h1:9NbNcTg//wfC5JskFW4Z3sqwVnjmJKHxLAol1bW2qgw=
|
golang.org/x/image v0.0.0-20220617043117-41969df76e82 h1:KpZB5pUSBvrHltNEdK/tw0xlPeD13M6M6aGP32gKqiw=
|
||||||
golang.org/x/image v0.0.0-20220601225756-64ec528b34cd/go.mod h1:doUCurBvlfPMKfmIpRIywoHmhN3VyhnoFDbvIEWF4hY=
|
golang.org/x/image v0.0.0-20220617043117-41969df76e82/go.mod h1:doUCurBvlfPMKfmIpRIywoHmhN3VyhnoFDbvIEWF4hY=
|
||||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug=
|
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug=
|
||||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||||
|
@ -42,8 +42,8 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d h1:Zu/JngovGLVi6t2J3nmAf3AoTDwuzw85YZ3b9o4yU7s=
|
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c h1:aFV+BgZ4svzjfabn8ERpuB4JI4N6/rdy1iusx77G3oU=
|
||||||
golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
|
11
internal/win/comctl32.go
Normal file
11
internal/win/comctl32.go
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package win
|
||||||
|
|
||||||
|
// https://docs.microsoft.com/en-us/windows/win32/api/commctrl/ns-commctrl-initcommoncontrolsex
|
||||||
|
type INITCOMMONCONTROLSEX struct {
|
||||||
|
Size uint32
|
||||||
|
ICC uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
//sys InitCommonControlsEx(icc *INITCOMMONCONTROLSEX) (ok bool) = comctl32.InitCommonControlsEx
|
80
internal/win/comdlg32.go
Normal file
80
internal/win/comdlg32.go
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package win
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/ncruces/zenity/internal/zenutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
CC_RGBINIT = 0x00000001
|
||||||
|
CC_FULLOPEN = 0x00000002
|
||||||
|
CC_PREVENTFULLOPEN = 0x00000004
|
||||||
|
)
|
||||||
|
|
||||||
|
// https://docs.microsoft.com/en-us/windows/win32/api/commdlg/ns-commdlg-choosecolorw-r1
|
||||||
|
type CHOOSECOLOR struct {
|
||||||
|
StructSize uint32
|
||||||
|
Owner uintptr
|
||||||
|
Instance uintptr
|
||||||
|
RgbResult uint32
|
||||||
|
CustColors *[16]uint32
|
||||||
|
Flags uint32
|
||||||
|
CustData uintptr
|
||||||
|
FnHook uintptr
|
||||||
|
TemplateName *uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
OFN_OVERWRITEPROMPT = 0x00000002
|
||||||
|
OFN_NOCHANGEDIR = 0x00000008
|
||||||
|
OFN_ALLOWMULTISELECT = 0x00000200
|
||||||
|
OFN_PATHMUSTEXIST = 0x00000800
|
||||||
|
OFN_FILEMUSTEXIST = 0x00001000
|
||||||
|
OFN_CREATEPROMPT = 0x00002000
|
||||||
|
OFN_NOREADONLYRETURN = 0x00008000
|
||||||
|
OFN_EXPLORER = 0x00080000
|
||||||
|
OFN_FORCESHOWHIDDEN = 0x10000000
|
||||||
|
)
|
||||||
|
|
||||||
|
// https://docs.microsoft.com/en-us/windows/win32/api/commdlg/ns-commdlg-openfilenamew
|
||||||
|
type OPENFILENAME struct {
|
||||||
|
StructSize uint32
|
||||||
|
Owner uintptr
|
||||||
|
Instance uintptr
|
||||||
|
Filter *uint16
|
||||||
|
CustomFilter *uint16
|
||||||
|
MaxCustomFilter uint32
|
||||||
|
FilterIndex uint32
|
||||||
|
File *uint16
|
||||||
|
MaxFile uint32
|
||||||
|
FileTitle *uint16
|
||||||
|
MaxFileTitle uint32
|
||||||
|
InitialDir *uint16
|
||||||
|
Title *uint16
|
||||||
|
Flags uint32
|
||||||
|
FileOffset uint16
|
||||||
|
FileExtension uint16
|
||||||
|
DefExt *uint16
|
||||||
|
CustData uintptr
|
||||||
|
FnHook uintptr
|
||||||
|
TemplateName *uint16
|
||||||
|
PvReserved uintptr
|
||||||
|
DwReserved uint32
|
||||||
|
FlagsEx uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func CommDlgError() error {
|
||||||
|
if code := commDlgExtendedError(); code == 0 {
|
||||||
|
return zenutil.ErrCanceled
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("Common Dialog error: %x", code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//sys commDlgExtendedError() (code int) = comdlg32.CommDlgExtendedError
|
||||||
|
//sys ChooseColor(cc *CHOOSECOLOR) (ok bool) = comdlg32.ChooseColorW
|
||||||
|
//sys GetOpenFileName(ofn *OPENFILENAME) (ok bool) = comdlg32.GetOpenFileNameW
|
||||||
|
//sys GetSaveFileName(ofn *OPENFILENAME) (ok bool) = comdlg32.GetSaveFileNameW
|
47
internal/win/ole32.go
Normal file
47
internal/win/ole32.go
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package win
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
RPC_E_CHANGED_MODE syscall.Errno = 0x80010106
|
||||||
|
)
|
||||||
|
|
||||||
|
func CoInitializeEx(reserved uintptr, coInit uint32) error {
|
||||||
|
return windows.CoInitializeEx(reserved, coInit)
|
||||||
|
}
|
||||||
|
|
||||||
|
func CoUninitialize() { windows.CoUninitialize() }
|
||||||
|
|
||||||
|
// https://github.com/wine-mirror/wine/blob/master/include/unknwn.idl
|
||||||
|
|
||||||
|
type IUnknownVtbl struct {
|
||||||
|
QueryInterface uintptr
|
||||||
|
AddRef uintptr
|
||||||
|
Release uintptr
|
||||||
|
}
|
||||||
|
|
||||||
|
type COMObject struct{}
|
||||||
|
|
||||||
|
//go:uintptrescapes
|
||||||
|
func (o *COMObject) Call(trap uintptr, a ...uintptr) (r1, r2 uintptr, lastErr error) {
|
||||||
|
switch nargs := uintptr(len(a)); nargs {
|
||||||
|
case 0:
|
||||||
|
return syscall.Syscall(trap, nargs+1, uintptr(unsafe.Pointer(o)), 0, 0)
|
||||||
|
case 1:
|
||||||
|
return syscall.Syscall(trap, nargs+1, uintptr(unsafe.Pointer(o)), a[0], 0)
|
||||||
|
case 2:
|
||||||
|
return syscall.Syscall(trap, nargs+1, uintptr(unsafe.Pointer(o)), a[0], a[1])
|
||||||
|
default:
|
||||||
|
panic("COM call with too many arguments.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//sys CoTaskMemFree(address uintptr) = ole32.CoTaskMemFree
|
||||||
|
//sys CoCreateInstance(clsid uintptr, unkOuter unsafe.Pointer, clsContext int32, iid uintptr, address unsafe.Pointer) (ret error) = ole32.CoCreateInstance
|
5
internal/win/pkg.go
Normal file
5
internal/win/pkg.go
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
// Package win is internal. DO NOT USE.
|
||||||
|
package win
|
||||||
|
|
||||||
|
//go:generate -command mkwinsyscall go run golang.org/x/sys/windows/mkwinsyscall -output zsyscall_windows.go
|
||||||
|
//go:generate mkwinsyscall comctl32.go comdlg32.go ole32.go shell32.go
|
58
internal/win/shell32.go
Normal file
58
internal/win/shell32.go
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package win
|
||||||
|
|
||||||
|
const (
|
||||||
|
NIM_ADD = 0
|
||||||
|
NIM_DELETE = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
// https://docs.microsoft.com/en-us/windows/win32/api/shlobj_core/ns-shlobj_core-browseinfow
|
||||||
|
type BROWSEINFO struct {
|
||||||
|
Owner uintptr
|
||||||
|
Root uintptr
|
||||||
|
DisplayName *uint16
|
||||||
|
Title *uint16
|
||||||
|
Flags uint32
|
||||||
|
CallbackFunc uintptr
|
||||||
|
LParam *uint16
|
||||||
|
Image int32
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.microsoft.com/en-us/windows/win32/api/shellapi/ns-shellapi-notifyicondataw
|
||||||
|
type NOTIFYICONDATA struct {
|
||||||
|
StructSize uint32
|
||||||
|
Wnd uintptr
|
||||||
|
ID uint32
|
||||||
|
Flags uint32
|
||||||
|
CallbackMessage uint32
|
||||||
|
Icon uintptr
|
||||||
|
Tip [128]uint16 // NOTIFYICONDATAA_V1_SIZE
|
||||||
|
State uint32
|
||||||
|
StateMask uint32
|
||||||
|
Info [256]uint16
|
||||||
|
Version uint32
|
||||||
|
InfoTitle [64]uint16
|
||||||
|
InfoFlags uint32
|
||||||
|
// GuidItem [16]byte // NOTIFYICONDATAA_V2_SIZE
|
||||||
|
// BalloonIcon syscall.Handle // NOTIFYICONDATAA_V3_SIZE
|
||||||
|
}
|
||||||
|
|
||||||
|
type IShellItem struct {
|
||||||
|
COMObject
|
||||||
|
*_IShellItemVtbl
|
||||||
|
}
|
||||||
|
|
||||||
|
type _IShellItemVtbl struct {
|
||||||
|
IUnknownVtbl
|
||||||
|
BindToHandler uintptr
|
||||||
|
GetParent uintptr
|
||||||
|
GetDisplayName uintptr
|
||||||
|
GetAttributes uintptr
|
||||||
|
Compare uintptr
|
||||||
|
}
|
||||||
|
|
||||||
|
//sys SHBrowseForFolder(bi *BROWSEINFO) (ptr uintptr) = shell32.SHBrowseForFolder
|
||||||
|
//sys SHCreateItemFromParsingName(path *uint16, bc unsafe.Pointer, iid uintptr, item **IShellItem) (err error) = shell32.SHCreateItemFromParsingName
|
||||||
|
//sys SHGetPathFromIDListEx(ptr uintptr, path *uint16, pathLen int, opts int) (err error) = shell32.SHGetPathFromIDListEx
|
||||||
|
//sys ShellNotifyIcon(message uint32, data *NOTIFYICONDATA) (ret int, err error) = shell32.Shell_NotifyIconW
|
131
internal/win/zsyscall_windows.go
Normal file
131
internal/win/zsyscall_windows.go
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
// Code generated by 'go generate'; DO NOT EDIT.
|
||||||
|
|
||||||
|
package win
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ unsafe.Pointer
|
||||||
|
|
||||||
|
// Do the interface allocations only once for common
|
||||||
|
// Errno values.
|
||||||
|
const (
|
||||||
|
errnoERROR_IO_PENDING = 997
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
|
||||||
|
errERROR_EINVAL error = syscall.EINVAL
|
||||||
|
)
|
||||||
|
|
||||||
|
// errnoErr returns common boxed Errno values, to prevent
|
||||||
|
// allocations at runtime.
|
||||||
|
func errnoErr(e syscall.Errno) error {
|
||||||
|
switch e {
|
||||||
|
case 0:
|
||||||
|
return errERROR_EINVAL
|
||||||
|
case errnoERROR_IO_PENDING:
|
||||||
|
return errERROR_IO_PENDING
|
||||||
|
}
|
||||||
|
// TODO: add more here, after collecting data on the common
|
||||||
|
// error values see on Windows. (perhaps when running
|
||||||
|
// all.bat?)
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
modcomctl32 = windows.NewLazySystemDLL("comctl32.dll")
|
||||||
|
modcomdlg32 = windows.NewLazySystemDLL("comdlg32.dll")
|
||||||
|
modole32 = windows.NewLazySystemDLL("ole32.dll")
|
||||||
|
modshell32 = windows.NewLazySystemDLL("shell32.dll")
|
||||||
|
|
||||||
|
procInitCommonControlsEx = modcomctl32.NewProc("InitCommonControlsEx")
|
||||||
|
procChooseColorW = modcomdlg32.NewProc("ChooseColorW")
|
||||||
|
procCommDlgExtendedError = modcomdlg32.NewProc("CommDlgExtendedError")
|
||||||
|
procGetOpenFileNameW = modcomdlg32.NewProc("GetOpenFileNameW")
|
||||||
|
procGetSaveFileNameW = modcomdlg32.NewProc("GetSaveFileNameW")
|
||||||
|
procCoCreateInstance = modole32.NewProc("CoCreateInstance")
|
||||||
|
procCoTaskMemFree = modole32.NewProc("CoTaskMemFree")
|
||||||
|
procSHBrowseForFolder = modshell32.NewProc("SHBrowseForFolder")
|
||||||
|
procSHCreateItemFromParsingName = modshell32.NewProc("SHCreateItemFromParsingName")
|
||||||
|
procSHGetPathFromIDListEx = modshell32.NewProc("SHGetPathFromIDListEx")
|
||||||
|
procShell_NotifyIconW = modshell32.NewProc("Shell_NotifyIconW")
|
||||||
|
)
|
||||||
|
|
||||||
|
func InitCommonControlsEx(icc *INITCOMMONCONTROLSEX) (ok bool) {
|
||||||
|
r0, _, _ := syscall.Syscall(procInitCommonControlsEx.Addr(), 1, uintptr(unsafe.Pointer(icc)), 0, 0)
|
||||||
|
ok = r0 != 0
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func ChooseColor(cc *CHOOSECOLOR) (ok bool) {
|
||||||
|
r0, _, _ := syscall.Syscall(procChooseColorW.Addr(), 1, uintptr(unsafe.Pointer(cc)), 0, 0)
|
||||||
|
ok = r0 != 0
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func commDlgExtendedError() (code int) {
|
||||||
|
r0, _, _ := syscall.Syscall(procCommDlgExtendedError.Addr(), 0, 0, 0, 0)
|
||||||
|
code = int(r0)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetOpenFileName(ofn *OPENFILENAME) (ok bool) {
|
||||||
|
r0, _, _ := syscall.Syscall(procGetOpenFileNameW.Addr(), 1, uintptr(unsafe.Pointer(ofn)), 0, 0)
|
||||||
|
ok = r0 != 0
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetSaveFileName(ofn *OPENFILENAME) (ok bool) {
|
||||||
|
r0, _, _ := syscall.Syscall(procGetSaveFileNameW.Addr(), 1, uintptr(unsafe.Pointer(ofn)), 0, 0)
|
||||||
|
ok = r0 != 0
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func CoCreateInstance(clsid uintptr, unkOuter unsafe.Pointer, clsContext int32, iid uintptr, address unsafe.Pointer) (ret error) {
|
||||||
|
r0, _, _ := syscall.Syscall6(procCoCreateInstance.Addr(), 5, uintptr(clsid), uintptr(unkOuter), uintptr(clsContext), uintptr(iid), uintptr(address), 0)
|
||||||
|
if r0 != 0 {
|
||||||
|
ret = syscall.Errno(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func CoTaskMemFree(address uintptr) {
|
||||||
|
syscall.Syscall(procCoTaskMemFree.Addr(), 1, uintptr(address), 0, 0)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func SHBrowseForFolder(bi *BROWSEINFO) (ptr uintptr) {
|
||||||
|
r0, _, _ := syscall.Syscall(procSHBrowseForFolder.Addr(), 1, uintptr(unsafe.Pointer(bi)), 0, 0)
|
||||||
|
ptr = uintptr(r0)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func SHCreateItemFromParsingName(path *uint16, bc unsafe.Pointer, iid uintptr, item **IShellItem) (err error) {
|
||||||
|
r1, _, e1 := syscall.Syscall6(procSHCreateItemFromParsingName.Addr(), 4, uintptr(unsafe.Pointer(path)), uintptr(bc), uintptr(iid), uintptr(unsafe.Pointer(item)), 0, 0)
|
||||||
|
if r1 == 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func SHGetPathFromIDListEx(ptr uintptr, path *uint16, pathLen int, opts int) (err error) {
|
||||||
|
r1, _, e1 := syscall.Syscall6(procSHGetPathFromIDListEx.Addr(), 4, uintptr(ptr), uintptr(unsafe.Pointer(path)), uintptr(pathLen), uintptr(opts), 0, 0)
|
||||||
|
if r1 == 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func ShellNotifyIcon(message uint32, data *NOTIFYICONDATA) (ret int, err error) {
|
||||||
|
r0, _, e1 := syscall.Syscall(procShell_NotifyIconW.Addr(), 2, uintptr(message), uintptr(unsafe.Pointer(data)), 0)
|
||||||
|
ret = int(r0)
|
||||||
|
if ret == 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
|
@ -7,12 +7,12 @@ import (
|
||||||
"time"
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/ncruces/zenity/internal/win"
|
||||||
"github.com/ncruces/zenity/internal/zenutil"
|
"github.com/ncruces/zenity/internal/zenutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
rtlGetNtVersionNumbers = ntdll.NewProc("RtlGetNtVersionNumbers")
|
rtlGetNtVersionNumbers = ntdll.NewProc("RtlGetNtVersionNumbers")
|
||||||
shellNotifyIcon = shell32.NewProc("Shell_NotifyIconW")
|
|
||||||
wtsSendMessage = wtsapi32.NewProc("WTSSendMessageW")
|
wtsSendMessage = wtsapi32.NewProc("WTSSendMessageW")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ func notify(text string, opts options) error {
|
||||||
return opts.ctx.Err()
|
return opts.ctx.Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
var args _NOTIFYICONDATA
|
var args win.NOTIFYICONDATA
|
||||||
args.StructSize = uint32(unsafe.Sizeof(args))
|
args.StructSize = uint32(unsafe.Sizeof(args))
|
||||||
args.ID = rand.Uint32()
|
args.ID = rand.Uint32()
|
||||||
args.Flags = 0x00000010 // NIF_INFO
|
args.Flags = 0x00000010 // NIF_INFO
|
||||||
|
@ -55,7 +55,7 @@ func notify(text string, opts options) error {
|
||||||
runtime.LockOSThread()
|
runtime.LockOSThread()
|
||||||
defer runtime.UnlockOSThread()
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
s, _, err := shellNotifyIcon.Call(0 /* NIM_ADD */, uintptr(unsafe.Pointer(&args)))
|
s, err := win.ShellNotifyIcon(win.NIM_ADD, &args)
|
||||||
if s == 0 {
|
if s == 0 {
|
||||||
if errno, ok := err.(syscall.Errno); ok && errno == 0 {
|
if errno, ok := err.(syscall.Errno); ok && errno == 0 {
|
||||||
return wtsMessage(text, opts)
|
return wtsMessage(text, opts)
|
||||||
|
@ -81,7 +81,7 @@ func notify(text string, opts options) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
shellNotifyIcon.Call(2 /* NIM_DELETE */, uintptr(unsafe.Pointer(&args)))
|
win.ShellNotifyIcon(win.NIM_DELETE, &args)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,22 +125,3 @@ func wtsMessage(text string, opts options) error {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://docs.microsoft.com/en-us/windows/win32/api/shellapi/ns-shellapi-notifyicondataw
|
|
||||||
type _NOTIFYICONDATA struct {
|
|
||||||
StructSize uint32
|
|
||||||
Wnd uintptr
|
|
||||||
ID uint32
|
|
||||||
Flags uint32
|
|
||||||
CallbackMessage uint32
|
|
||||||
Icon uintptr
|
|
||||||
Tip [128]uint16 // NOTIFYICONDATAA_V1_SIZE
|
|
||||||
State uint32
|
|
||||||
StateMask uint32
|
|
||||||
Info [256]uint16
|
|
||||||
Version uint32
|
|
||||||
InfoTitle [64]uint16
|
|
||||||
InfoFlags uint32
|
|
||||||
// GuidItem [16]byte // NOTIFYICONDATAA_V2_SIZE
|
|
||||||
// BalloonIcon syscall.Handle // NOTIFYICONDATAA_V3_SIZE
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ package zenity
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
@ -13,23 +12,17 @@ import (
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/ncruces/zenity/internal/win"
|
||||||
"golang.org/x/sys/windows"
|
"golang.org/x/sys/windows"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
comctl32 = windows.NewLazySystemDLL("comctl32.dll")
|
|
||||||
comdlg32 = windows.NewLazySystemDLL("comdlg32.dll")
|
|
||||||
gdi32 = windows.NewLazySystemDLL("gdi32.dll")
|
gdi32 = windows.NewLazySystemDLL("gdi32.dll")
|
||||||
kernel32 = windows.NewLazySystemDLL("kernel32.dll")
|
kernel32 = windows.NewLazySystemDLL("kernel32.dll")
|
||||||
ntdll = windows.NewLazySystemDLL("ntdll.dll")
|
ntdll = windows.NewLazySystemDLL("ntdll.dll")
|
||||||
ole32 = windows.NewLazySystemDLL("ole32.dll")
|
|
||||||
shell32 = windows.NewLazySystemDLL("shell32.dll")
|
|
||||||
user32 = windows.NewLazySystemDLL("user32.dll")
|
user32 = windows.NewLazySystemDLL("user32.dll")
|
||||||
wtsapi32 = windows.NewLazySystemDLL("wtsapi32.dll")
|
wtsapi32 = windows.NewLazySystemDLL("wtsapi32.dll")
|
||||||
|
|
||||||
commDlgExtendedError = comdlg32.NewProc("CommDlgExtendedError")
|
|
||||||
initCommonControlsEx = comctl32.NewProc("InitCommonControlsEx")
|
|
||||||
|
|
||||||
createFontIndirect = gdi32.NewProc("CreateFontIndirectW")
|
createFontIndirect = gdi32.NewProc("CreateFontIndirectW")
|
||||||
deleteObject = gdi32.NewProc("DeleteObject")
|
deleteObject = gdi32.NewProc("DeleteObject")
|
||||||
getDeviceCaps = gdi32.NewProc("GetDeviceCaps")
|
getDeviceCaps = gdi32.NewProc("GetDeviceCaps")
|
||||||
|
@ -42,11 +35,6 @@ var (
|
||||||
getModuleHandle = kernel32.NewProc("GetModuleHandleW")
|
getModuleHandle = kernel32.NewProc("GetModuleHandleW")
|
||||||
getSystemDirectory = kernel32.NewProc("GetSystemDirectoryW")
|
getSystemDirectory = kernel32.NewProc("GetSystemDirectoryW")
|
||||||
|
|
||||||
coCreateInstance = ole32.NewProc("CoCreateInstance")
|
|
||||||
coInitializeEx = ole32.NewProc("CoInitializeEx")
|
|
||||||
coTaskMemFree = ole32.NewProc("CoTaskMemFree")
|
|
||||||
coUninitialize = ole32.NewProc("CoUninitialize")
|
|
||||||
|
|
||||||
callNextHookEx = user32.NewProc("CallNextHookEx")
|
callNextHookEx = user32.NewProc("CallNextHookEx")
|
||||||
createIconFromResource = user32.NewProc("CreateIconFromResource")
|
createIconFromResource = user32.NewProc("CreateIconFromResource")
|
||||||
createWindowEx = user32.NewProc("CreateWindowExW")
|
createWindowEx = user32.NewProc("CreateWindowExW")
|
||||||
|
@ -121,10 +109,10 @@ func setup() context.CancelFunc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var icc _INITCOMMONCONTROLSEX
|
var icc win.INITCOMMONCONTROLSEX
|
||||||
icc.Size = uint32(unsafe.Sizeof(icc))
|
icc.Size = uint32(unsafe.Sizeof(icc))
|
||||||
icc.ICC = 0x00004020 // ICC_STANDARD_CLASSES|ICC_PROGRESS_CLASS
|
icc.ICC = 0x00004020 // ICC_STANDARD_CLASSES|ICC_PROGRESS_CLASS
|
||||||
initCommonControlsEx.Call(uintptr(unsafe.Pointer(&icc)))
|
win.InitCommonControlsEx(&icc)
|
||||||
|
|
||||||
return func() {
|
return func() {
|
||||||
if restore != 0 {
|
if restore != 0 {
|
||||||
|
@ -147,15 +135,6 @@ func setupEnumCallback(wnd uintptr, lparam *uintptr) uintptr {
|
||||||
return 1 // continue enumeration
|
return 1 // continue enumeration
|
||||||
}
|
}
|
||||||
|
|
||||||
func commDlgError() error {
|
|
||||||
s, _, _ := commDlgExtendedError.Call()
|
|
||||||
if s == 0 {
|
|
||||||
return ErrCanceled
|
|
||||||
} else {
|
|
||||||
return fmt.Errorf("Common Dialog error: %x", s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func hookDialog(ctx context.Context, icon any, title *string, init func(wnd uintptr)) (unhook context.CancelFunc, err error) {
|
func hookDialog(ctx context.Context, icon any, title *string, init func(wnd uintptr)) (unhook context.CancelFunc, err error) {
|
||||||
if ctx != nil && ctx.Err() != nil {
|
if ctx != nil && ctx.Err() != nil {
|
||||||
return nil, ctx.Err()
|
return nil, ctx.Err()
|
||||||
|
@ -482,12 +461,6 @@ type _ACTCTX struct {
|
||||||
Module uintptr
|
Module uintptr
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://docs.microsoft.com/en-us/windows/win32/api/commctrl/ns-commctrl-initcommoncontrolsex
|
|
||||||
type _INITCOMMONCONTROLSEX struct {
|
|
||||||
Size uint32
|
|
||||||
ICC uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-cwpretstruct
|
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-cwpretstruct
|
||||||
type _CWPRETSTRUCT struct {
|
type _CWPRETSTRUCT struct {
|
||||||
Result uintptr
|
Result uintptr
|
||||||
|
@ -596,19 +569,3 @@ type _IUnknownVtbl struct {
|
||||||
func uuid(s string) uintptr {
|
func uuid(s string) uintptr {
|
||||||
return (*reflect.StringHeader)(unsafe.Pointer(&s)).Data
|
return (*reflect.StringHeader)(unsafe.Pointer(&s)).Data
|
||||||
}
|
}
|
||||||
|
|
||||||
type _COMObject struct{}
|
|
||||||
|
|
||||||
//go:uintptrescapes
|
|
||||||
func (o *_COMObject) Call(trap uintptr, a ...uintptr) (r1, r2 uintptr, lastErr error) {
|
|
||||||
switch nargs := uintptr(len(a)); nargs {
|
|
||||||
case 0:
|
|
||||||
return syscall.Syscall(trap, nargs+1, uintptr(unsafe.Pointer(o)), 0, 0)
|
|
||||||
case 1:
|
|
||||||
return syscall.Syscall(trap, nargs+1, uintptr(unsafe.Pointer(o)), a[0], 0)
|
|
||||||
case 2:
|
|
||||||
return syscall.Syscall(trap, nargs+1, uintptr(unsafe.Pointer(o)), a[0], a[1])
|
|
||||||
default:
|
|
||||||
panic("COM call with too many arguments.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue