Refactor (windows).

This commit is contained in:
Nuno Cruces 2022-06-22 00:58:14 +01:00
parent 6928e74895
commit e2dc86414f
7 changed files with 265 additions and 169 deletions

View file

@ -89,11 +89,11 @@ func (dlg *calendarDialog) setup(text string, opts options) (time.Time, error) {
}
if opts.time != nil {
var date _SYSTEMTIME
var date win.SYSTEMTIME
year, month, day := opts.time.Date()
date.year = uint16(year)
date.month = uint16(month)
date.day = uint16(day)
date.Year = uint16(year)
date.Month = uint16(month)
date.Day = uint16(day)
win.SendMessagePointer(dlg.dateCtl, win.MCM_SETCURSEL, 0, unsafe.Pointer(&date))
}
@ -168,9 +168,9 @@ func calendarProc(wnd win.HWND, msg uint32, wparam uintptr, lparam *unsafe.Point
default:
return 1
case win.IDOK, win.IDYES:
var date _SYSTEMTIME
var date win.SYSTEMTIME
win.SendMessagePointer(dlg.dateCtl, win.MCM_GETCURSEL, 0, unsafe.Pointer(&date))
dlg.out = time.Date(int(date.year), time.Month(date.month), int(date.day), 0, 0, 0, 0, time.UTC)
dlg.out = time.Date(int(date.Year), time.Month(date.Month), int(date.Day), 0, 0, 0, 0, time.UTC)
case win.IDCANCEL:
dlg.err = ErrCanceled
case win.IDNO:

View file

@ -3,7 +3,6 @@ package zenity
import (
"fmt"
"path/filepath"
"reflect"
"syscall"
"unicode/utf16"
"unsafe"
@ -201,22 +200,21 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error)
defer win.CoUninitialize()
}
var dialog *_IFileOpenDialog
var dialog *win.IFileOpenDialog
err = win.CoCreateInstance(
_CLSID_FileOpenDialog, nil, win.CLSCTX_ALL,
_IID_IFileOpenDialog, unsafe.Pointer(&dialog))
win.CLSID_FileOpenDialog, nil, win.CLSCTX_ALL,
win.IID_IFileOpenDialog, unsafe.Pointer(&dialog))
if err != nil {
if multi {
return "", nil, fmt.Errorf("%w: multiple directory", ErrUnsupported)
}
return browseForFolder(opts)
}
defer dialog.Call(dialog.Release)
defer dialog.Release()
var flgs int
hr, _, _ := dialog.Call(dialog.GetOptions, uintptr(unsafe.Pointer(&flgs)))
if int32(hr) < 0 {
return "", nil, syscall.Errno(hr)
flgs, err := dialog.GetOptions()
if err != nil {
return "", nil, err
}
flgs |= _FOS_NOCHANGEDIR | _FOS_PICKFOLDERS | _FOS_FORCEFILESYSTEM
if multi {
@ -225,24 +223,21 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error)
if opts.showHidden {
flgs |= _FOS_FORCESHOWHIDDEN
}
hr, _, _ = dialog.Call(dialog.SetOptions, uintptr(flgs))
if int32(hr) < 0 {
return "", nil, syscall.Errno(hr)
err = dialog.SetOptions(flgs)
if err != nil {
return "", nil, err
}
if opts.title != nil {
ptr := strptr(*opts.title)
dialog.Call(dialog.SetTitle, uintptr(unsafe.Pointer(ptr)))
dialog.SetTitle(strptr(*opts.title))
}
if opts.filename != "" {
var item *win.IShellItem
ptr := strptr(opts.filename)
win.SHCreateItemFromParsingName(ptr, nil, _IID_IShellItem, &item)
if int32(hr) >= 0 && item != nil {
dialog.Call(dialog.SetFolder, uintptr(unsafe.Pointer(item)))
item.Call(item.Release)
win.SHCreateItemFromParsingName(strptr(opts.filename), nil, win.IID_IShellItem, &item)
if item != nil {
dialog.SetFolder(item)
item.Release()
}
}
@ -255,59 +250,54 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error)
}
owner, _ := opts.attach.(win.HWND)
hr, _, _ = dialog.Call(dialog.Show, uintptr(owner))
err = dialog.Show(owner)
if opts.ctx != nil && opts.ctx.Err() != nil {
return "", nil, opts.ctx.Err()
}
if hr == uintptr(win.E_CANCELED) {
if err == win.E_CANCELED {
return "", nil, ErrCanceled
}
if int32(hr) < 0 {
return "", nil, syscall.Errno(hr)
if err != nil {
return "", nil, err
}
shellItemPath := func(obj *win.COMObject, trap uintptr, a ...uintptr) error {
var item *win.IShellItem
hr, _, _ := obj.Call(trap, append(a, uintptr(unsafe.Pointer(&item)))...)
if int32(hr) < 0 {
return syscall.Errno(hr)
}
defer item.Call(item.Release)
var ptr win.Pointer
hr, _, _ = item.Call(item.GetDisplayName,
_SIGDN_FILESYSPATH, uintptr(unsafe.Pointer(&ptr)))
if int32(hr) < 0 {
return syscall.Errno(hr)
}
defer win.CoTaskMemFree(ptr)
var res []uint16
hdr := (*reflect.SliceHeader)(unsafe.Pointer(&res))
hdr.Data, hdr.Len, hdr.Cap = uintptr(ptr), 32768, 32768
str = syscall.UTF16ToString(res)
shellItemPath := func(item *win.IShellItem) error {
defer item.Release()
str, err := item.GetDisplayName(_SIGDN_FILESYSPATH)
if err == nil {
lst = append(lst, str)
return nil
}
return err
}
if multi {
var items *_IShellItemArray
hr, _, _ = dialog.Call(dialog.GetResults, uintptr(unsafe.Pointer(&items)))
if int32(hr) < 0 {
return "", nil, syscall.Errno(hr)
items, err := dialog.GetResults()
if err != nil {
return "", nil, err
}
defer items.Call(items.Release)
defer items.Release()
var count uint32
hr, _, _ = items.Call(items.GetCount, uintptr(unsafe.Pointer(&count)))
if int32(hr) < 0 {
return "", nil, syscall.Errno(hr)
count, err := items.GetCount()
if err != nil {
return "", nil, err
}
for i := uint32(0); i < count; i++ {
item, err := items.GetItemAt(i)
if err == nil {
err = shellItemPath(item)
}
if err != nil {
return "", nil, err
}
for i := uintptr(0); i < uintptr(count) && err == nil; i++ {
err = shellItemPath(&items.COMObject, items.GetItemAt, i)
}
} else {
err = shellItemPath(&dialog.COMObject, dialog.GetResult)
item, err := dialog.GetResult()
if err == nil {
err = shellItemPath(item)
}
if err != nil {
return "", nil, err
}
}
return
}
@ -389,70 +379,3 @@ func initFilters(filters FileFilters) []uint16 {
}
return res
}
// https://github.com/wine-mirror/wine/blob/master/include/shobjidl.idl
var (
_IID_IShellItem = uuid("\x1e\x6d\x82\x43\x18\xe7\xee\x42\xbc\x55\xa1\xe2\x61\xc3\x7b\xfe")
_IID_IFileOpenDialog = uuid("\x88\x72\x7c\xd5\xad\xd4\x68\x47\xbe\x02\x9d\x96\x95\x32\xd9\x60")
_CLSID_FileOpenDialog = uuid("\x9c\x5a\x1c\xdc\x8a\xe8\xde\x4d\xa5\xa1\x60\xf8\x2a\x20\xae\xf7")
)
type _IFileOpenDialog struct {
win.COMObject
*_IFileOpenDialogVtbl
}
type _IShellItemArray struct {
win.COMObject
*_IShellItemArrayVtbl
}
type _IFileOpenDialogVtbl struct {
_IFileDialogVtbl
GetResults uintptr
GetSelectedItems uintptr
}
type _IFileDialogVtbl struct {
_IModalWindowVtbl
SetFileTypes uintptr
SetFileTypeIndex uintptr
GetFileTypeIndex uintptr
Advise uintptr
Unadvise uintptr
SetOptions uintptr
GetOptions uintptr
SetDefaultFolder uintptr
SetFolder uintptr
GetFolder uintptr
GetCurrentSelection uintptr
SetFileName uintptr
GetFileName uintptr
SetTitle uintptr
SetOkButtonLabel uintptr
SetFileNameLabel uintptr
GetResult uintptr
AddPlace uintptr
SetDefaultExtension uintptr
Close uintptr
SetClientGuid uintptr
ClearClientData uintptr
SetFilter uintptr
}
type _IModalWindowVtbl struct {
_IUnknownVtbl
Show uintptr
}
type _IShellItemArrayVtbl struct {
_IUnknownVtbl
BindToHandler uintptr
GetPropertyStore uintptr
GetPropertyDescriptionList uintptr
GetAttributes uintptr
GetCount uintptr
GetItemAt uintptr
EnumItems uintptr
}

View file

@ -3,6 +3,7 @@
package win
import (
"reflect"
"syscall"
"unsafe"
@ -33,12 +34,18 @@ func CoUninitialize() { windows.CoUninitialize() }
// https://github.com/wine-mirror/wine/blob/master/include/unknwn.idl
type IUnknownVtbl struct {
type _IUnknownBase struct{ COMObject }
type _IUnknownVtbl struct {
QueryInterface uintptr
AddRef uintptr
Release uintptr
}
func (c *_IUnknownBase) Release() {
vtbl := (*(**_IUnknownVtbl)(unsafe.Pointer(c)))
c.Call(vtbl.Release)
}
type COMObject struct{}
//go:uintptrescapes
@ -57,3 +64,7 @@ func (o *COMObject) Call(trap uintptr, a ...uintptr) (r1, r2 uintptr, lastErr er
//sys CoCreateInstance(clsid uintptr, unkOuter *COMObject, clsContext int32, iid uintptr, address unsafe.Pointer) (res error) = ole32.CoCreateInstance
//sys CoTaskMemFree(address Pointer) = ole32.CoTaskMemFree
func uuid(s string) uintptr {
return (*reflect.StringHeader)(unsafe.Pointer(&s)).Data
}

View file

@ -2,6 +2,12 @@
package win
import (
"reflect"
"syscall"
"unsafe"
)
const (
BIF_RETURNONLYFSDIRS = 0x00000001
@ -43,13 +49,131 @@ type NOTIFYICONDATA struct {
// BalloonIcon Handle // NOTIFYICONDATAA_V3_SIZE
}
type IShellItem struct {
COMObject
*_IShellItemVtbl
// https://github.com/wine-mirror/wine/blob/master/include/shobjidl.idl
var (
IID_IShellItem = uuid("\x1e\x6d\x82\x43\x18\xe7\xee\x42\xbc\x55\xa1\xe2\x61\xc3\x7b\xfe")
IID_IFileOpenDialog = uuid("\x88\x72\x7c\xd5\xad\xd4\x68\x47\xbe\x02\x9d\x96\x95\x32\xd9\x60")
CLSID_FileOpenDialog = uuid("\x9c\x5a\x1c\xdc\x8a\xe8\xde\x4d\xa5\xa1\x60\xf8\x2a\x20\xae\xf7")
)
type IFileOpenDialog struct {
_IFileOpenDialogBase
_ *_IFileOpenDialogVtbl
}
type _IFileOpenDialogBase struct{ _IFileDialogBase }
type _IFileOpenDialogVtbl struct {
_IFileDialogVtbl
GetResults uintptr
GetSelectedItems uintptr
}
func (c *_IFileOpenDialogBase) GetResults() (res *IShellItemArray, err error) {
vtbl := (*(**_IFileOpenDialogVtbl)(unsafe.Pointer(c)))
hr, _, _ := c.Call(vtbl.GetResults, uintptr(unsafe.Pointer(&res)))
if hr != 0 {
err = syscall.Errno(hr)
}
return
}
type _IFileDialogBase struct{ _IModalWindowBase }
type _IFileDialogVtbl struct {
_IModalWindowVtbl
SetFileTypes uintptr
SetFileTypeIndex uintptr
GetFileTypeIndex uintptr
Advise uintptr
Unadvise uintptr
SetOptions uintptr
GetOptions uintptr
SetDefaultFolder uintptr
SetFolder uintptr
GetFolder uintptr
GetCurrentSelection uintptr
SetFileName uintptr
GetFileName uintptr
SetTitle uintptr
SetOkButtonLabel uintptr
SetFileNameLabel uintptr
GetResult uintptr
AddPlace uintptr
SetDefaultExtension uintptr
Close uintptr
SetClientGuid uintptr
ClearClientData uintptr
SetFilter uintptr
}
func (c *_IFileDialogBase) SetOptions(fos int) (err error) {
vtbl := (*(**_IFileDialogVtbl)(unsafe.Pointer(c)))
hr, _, _ := c.Call(vtbl.SetOptions, uintptr(fos))
if hr != 0 {
err = syscall.Errno(hr)
}
return
}
func (c *_IFileDialogBase) GetOptions() (fos int, err error) {
vtbl := (*(**_IFileDialogVtbl)(unsafe.Pointer(c)))
hr, _, _ := c.Call(vtbl.GetOptions, uintptr(unsafe.Pointer(&fos)))
if hr != 0 {
err = syscall.Errno(hr)
}
return
}
func (c *_IFileDialogBase) SetFolder(item *IShellItem) (err error) {
vtbl := (*(**_IFileDialogVtbl)(unsafe.Pointer(c)))
hr, _, _ := c.Call(vtbl.SetFolder, uintptr(unsafe.Pointer(item)))
if hr != 0 {
err = syscall.Errno(hr)
}
return
}
func (c *_IFileDialogBase) SetTitle(title *uint16) (err error) {
vtbl := (*(**_IFileDialogVtbl)(unsafe.Pointer(c)))
hr, _, _ := c.Call(vtbl.SetTitle, uintptr(unsafe.Pointer(title)))
if hr != 0 {
err = syscall.Errno(hr)
}
return
}
func (c *_IFileDialogBase) GetResult() (item *IShellItem, err error) {
vtbl := (*(**_IFileDialogVtbl)(unsafe.Pointer(c)))
hr, _, _ := c.Call(vtbl.GetResult, uintptr(unsafe.Pointer(&item)))
if hr != 0 {
err = syscall.Errno(hr)
}
return
}
type _IModalWindowBase struct{ _IUnknownBase }
type _IModalWindowVtbl struct {
_IUnknownVtbl
Show uintptr
}
func (c *_IModalWindowBase) Show(wnd HWND) (err error) {
vtbl := (*(**_IModalWindowVtbl)(unsafe.Pointer(c)))
hr, _, _ := c.Call(vtbl.Show, uintptr(wnd))
if hr != 0 {
err = syscall.Errno(hr)
}
return
}
type IShellItem struct {
_IShellItemBase
_ *_IShellItemVtbl
}
type _IShellItemBase struct{ _IUnknownBase }
type _IShellItemVtbl struct {
IUnknownVtbl
_IUnknownVtbl
BindToHandler uintptr
GetParent uintptr
GetDisplayName uintptr
@ -57,6 +181,56 @@ type _IShellItemVtbl struct {
Compare uintptr
}
func (c *_IShellItemBase) GetDisplayName(name int) (res string, err error) {
var ptr uintptr
vtbl := (*(**_IShellItemVtbl)(unsafe.Pointer(c)))
hr, _, _ := c.Call(vtbl.GetDisplayName, uintptr(name), uintptr(unsafe.Pointer(&ptr)))
if hr != 0 {
err = syscall.Errno(hr)
} else {
var buf []uint16
hdr := (*reflect.SliceHeader)(unsafe.Pointer(&buf))
hdr.Data, hdr.Len, hdr.Cap = uintptr(ptr), 32768, 32768
res = syscall.UTF16ToString(buf)
}
return
}
type IShellItemArray struct {
_IShellItemArrayBase
_ *_IShellItemArrayVtbl
}
type _IShellItemArrayBase struct{ _IUnknownBase }
type _IShellItemArrayVtbl struct {
_IUnknownVtbl
BindToHandler uintptr
GetPropertyStore uintptr
GetPropertyDescriptionList uintptr
GetAttributes uintptr
GetCount uintptr
GetItemAt uintptr
EnumItems uintptr
}
func (c *_IShellItemArrayBase) GetCount() (numItems uint32, err error) {
vtbl := (*(**_IShellItemArrayVtbl)(unsafe.Pointer(c)))
hr, _, _ := c.Call(vtbl.GetCount, uintptr(unsafe.Pointer(&numItems)))
if hr != 0 {
err = syscall.Errno(hr)
}
return
}
func (c *_IShellItemArrayBase) GetItemAt(index uint32) (item *IShellItem, err error) {
vtbl := (*(**_IShellItemArrayVtbl)(unsafe.Pointer(c)))
hr, _, _ := c.Call(vtbl.GetItemAt, uintptr(index), uintptr(unsafe.Pointer(&item)))
if hr != 0 {
err = syscall.Errno(hr)
}
return
}
//sys SHBrowseForFolder(bi *BROWSEINFO) (ret Pointer) = shell32.SHBrowseForFolder
//sys SHCreateItemFromParsingName(path *uint16, bc *COMObject, iid uintptr, item **IShellItem) (res error) = shell32.SHCreateItemFromParsingName
//sys ShellNotifyIcon(message uint32, data *NOTIFYICONDATA) (ret int, err error) = shell32.Shell_NotifyIconW

View file

@ -353,6 +353,15 @@ type NONCLIENTMETRICS struct {
MessageFont LOGFONT
}
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-cwpretstruct
type CWPRETSTRUCT struct {
Result uintptr
LParam uintptr
WParam uintptr
Message uint32
Wnd HWND
}
//sys CallNextHookEx(hk Handle, code int32, wparam uintptr, lparam unsafe.Pointer) (ret uintptr) = user32.CallNextHookEx
//sys CreateIconFromResource(resBits []byte, icon bool, ver uint32) (ret Handle, err error) = user32.CreateIconFromResource
//sys CreateWindowEx(exStyle uint32, className *uint16, windowName *uint16, style uint32, x int, y int, width int, height int, parent HWND, menu Handle, instance Handle, param unsafe.Pointer) (ret HWND, err error) = user32.CreateWindowExW

View file

@ -9,6 +9,18 @@ type Handle = windows.Handle
type HWND = windows.HWND
type Pointer uintptr
// https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-systemtime
type SYSTEMTIME struct {
Year uint16
Month uint16
DayOfWeek uint16
Day uint16
Hour uint16
Minute uint16
Second uint16
Milliseconds uint16
}
func RtlGetNtVersionNumbers() (majorVersion, minorVersion, buildNumber uint32) {
return windows.RtlGetNtVersionNumbers()
}

View file

@ -127,7 +127,7 @@ func newDialogHook(ctx context.Context, icon any, title *string, init func(wnd w
return &hook, nil
}
func dialogHookProc(code int32, wparam uintptr, lparam *_CWPRETSTRUCT) uintptr {
func dialogHookProc(code int32, wparam uintptr, lparam *win.CWPRETSTRUCT) uintptr {
if lparam.Message == win.WM_INITDIALOG {
tid := win.GetCurrentThreadId()
hook := (*dialogHook)(loadBackRef(uintptr(tid)))
@ -360,36 +360,3 @@ func enableVisualStyles() (cookie uintptr) {
}
return
}
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-cwpretstruct
type _CWPRETSTRUCT struct {
Result uintptr
LParam uintptr
WParam uintptr
Message uint32
Wnd win.HWND
}
// https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-systemtime
type _SYSTEMTIME struct {
year uint16
month uint16
dayOfWeek uint16
day uint16
hour uint16
minute uint16
second uint16
milliseconds uint16
}
// https://github.com/wine-mirror/wine/blob/master/include/unknwn.idl
type _IUnknownVtbl struct {
QueryInterface uintptr
AddRef uintptr
Release uintptr
}
func uuid(s string) uintptr {
return (*reflect.StringHeader)(unsafe.Pointer(&s)).Data
}