Refactor (windows).
This commit is contained in:
parent
e2dc86414f
commit
762d54a00d
13 changed files with 225 additions and 152 deletions
|
@ -72,7 +72,6 @@ func TestCalendar_script(t *testing.T) {
|
|||
if skip, err := skip(err); skip {
|
||||
t.Skip("skipping:", err)
|
||||
}
|
||||
got.Date()
|
||||
if !DateEquals(got, tt.want) || err != tt.err {
|
||||
t.Errorf("Calendar() = %v, %v; want %v, %v", got, err, tt.want, tt.err)
|
||||
}
|
||||
|
|
|
@ -139,7 +139,7 @@ func TestSelectFile_script(t *testing.T) {
|
|||
t.Skip("skipping:", err)
|
||||
}
|
||||
if str == "" || err != nil {
|
||||
t.Errorf("SelectFile() = %q, %v; want [path], nil", str, err)
|
||||
t.Fatalf("SelectFile() = %q, %v; want [path], nil", str, err)
|
||||
}
|
||||
if _, serr := os.Stat(str); serr != nil {
|
||||
t.Errorf("SelectFile() = %q, %v; %v", str, err, serr)
|
||||
|
@ -152,7 +152,7 @@ func TestSelectFile_script(t *testing.T) {
|
|||
t.Skip("skipping:", err)
|
||||
}
|
||||
if str == "" || err != nil {
|
||||
t.Errorf("SelectFile() = %q, %v; want [path], nil", str, err)
|
||||
t.Fatalf("SelectFile() = %q, %v; want [path], nil", str, err)
|
||||
}
|
||||
if s, serr := os.Stat(str); serr != nil {
|
||||
t.Errorf("SelectFile() = %q, %v; %v", str, err, serr)
|
||||
|
@ -183,7 +183,7 @@ func TestSelectFileMultiple_script(t *testing.T) {
|
|||
t.Skip("skipping:", err)
|
||||
}
|
||||
if lst == nil || err != nil {
|
||||
t.Errorf("SelectFileMultiple() = %v, %v; want [path, path], nil", lst, err)
|
||||
t.Fatalf("SelectFileMultiple() = %v, %v; want [path, path], nil", lst, err)
|
||||
}
|
||||
for _, str := range lst {
|
||||
if _, serr := os.Stat(str); serr != nil {
|
||||
|
@ -201,7 +201,7 @@ func TestSelectFileMultiple_script(t *testing.T) {
|
|||
t.Skip("was not unsupported:", err)
|
||||
}
|
||||
if lst == nil || err != nil {
|
||||
t.Errorf("SelectFileMultiple() = %v, %v; want [path, path], nil", lst, err)
|
||||
t.Fatalf("SelectFileMultiple() = %v, %v; want [path, path], nil", lst, err)
|
||||
}
|
||||
for _, str := range lst {
|
||||
if s, serr := os.Stat(str); serr != nil {
|
||||
|
|
|
@ -10,16 +10,6 @@ import (
|
|||
"github.com/ncruces/zenity/internal/win"
|
||||
)
|
||||
|
||||
const (
|
||||
_FOS_NOCHANGEDIR = 0x00000008
|
||||
_FOS_PICKFOLDERS = 0x00000020
|
||||
_FOS_FORCEFILESYSTEM = 0x00000040
|
||||
_FOS_ALLOWMULTISELECT = 0x00000200
|
||||
_FOS_FORCESHOWHIDDEN = 0x10000000
|
||||
|
||||
_SIGDN_FILESYSPATH = 0x80058000
|
||||
)
|
||||
|
||||
func selectFile(opts options) (string, error) {
|
||||
if opts.directory {
|
||||
res, _, err := pickFolders(opts, false)
|
||||
|
@ -189,10 +179,10 @@ func selectFileSave(opts options) (string, error) {
|
|||
return syscall.UTF16ToString(res[:]), nil
|
||||
}
|
||||
|
||||
func pickFolders(opts options, multi bool) (str string, lst []string, err error) {
|
||||
func pickFolders(opts options, multi bool) (string, []string, error) {
|
||||
defer setup()()
|
||||
|
||||
err = win.CoInitializeEx(0, win.COINIT_APARTMENTTHREADED|win.COINIT_DISABLE_OLE1DDE)
|
||||
err := win.CoInitializeEx(0, win.COINIT_APARTMENTTHREADED|win.COINIT_DISABLE_OLE1DDE)
|
||||
if err != win.RPC_E_CHANGED_MODE {
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
|
@ -216,12 +206,12 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error)
|
|||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
flgs |= _FOS_NOCHANGEDIR | _FOS_PICKFOLDERS | _FOS_FORCEFILESYSTEM
|
||||
flgs |= win.FOS_NOCHANGEDIR | win.FOS_PICKFOLDERS | win.FOS_FORCEFILESYSTEM
|
||||
if multi {
|
||||
flgs |= _FOS_ALLOWMULTISELECT
|
||||
flgs |= win.FOS_ALLOWMULTISELECT
|
||||
}
|
||||
if opts.showHidden {
|
||||
flgs |= _FOS_FORCESHOWHIDDEN
|
||||
flgs |= win.FOS_FORCESHOWHIDDEN
|
||||
}
|
||||
err = dialog.SetOptions(flgs)
|
||||
if err != nil {
|
||||
|
@ -236,8 +226,8 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error)
|
|||
var item *win.IShellItem
|
||||
win.SHCreateItemFromParsingName(strptr(opts.filename), nil, win.IID_IShellItem, &item)
|
||||
if item != nil {
|
||||
defer item.Release()
|
||||
dialog.SetFolder(item)
|
||||
item.Release()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -261,15 +251,6 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error)
|
|||
return "", nil, err
|
||||
}
|
||||
|
||||
shellItemPath := func(item *win.IShellItem) error {
|
||||
defer item.Release()
|
||||
str, err := item.GetDisplayName(_SIGDN_FILESYSPATH)
|
||||
if err == nil {
|
||||
lst = append(lst, str)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if multi {
|
||||
items, err := dialog.GetResults()
|
||||
if err != nil {
|
||||
|
@ -281,25 +262,31 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error)
|
|||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
for i := uint32(0); i < count; i++ {
|
||||
item, err := items.GetItemAt(i)
|
||||
if err == nil {
|
||||
err = shellItemPath(item)
|
||||
}
|
||||
|
||||
var lst []string
|
||||
for i := uint32(0); i < count && err == nil; i++ {
|
||||
str, err := shellItemPath(items.GetItemAt(i))
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
lst = append(lst, str)
|
||||
}
|
||||
return "", lst, nil
|
||||
} else {
|
||||
item, err := dialog.GetResult()
|
||||
if err == nil {
|
||||
err = shellItemPath(item)
|
||||
}
|
||||
str, err := shellItemPath(dialog.GetResult())
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
return str, nil, nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func shellItemPath(item *win.IShellItem, err error) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer item.Release()
|
||||
return item.GetDisplayName(win.SIGDN_FILESYSPATH)
|
||||
}
|
||||
|
||||
func browseForFolder(opts options) (string, []string, error) {
|
||||
|
@ -327,10 +314,10 @@ func browseForFolder(opts options) (string, []string, error) {
|
|||
if opts.ctx != nil && opts.ctx.Err() != nil {
|
||||
return "", nil, opts.ctx.Err()
|
||||
}
|
||||
if ptr == nullptr {
|
||||
if ptr == nil {
|
||||
return "", nil, ErrCanceled
|
||||
}
|
||||
defer win.CoTaskMemFree(ptr)
|
||||
defer win.CoTaskMemFree(unsafe.Pointer(ptr))
|
||||
|
||||
var res [32768]uint16
|
||||
win.SHGetPathFromIDListEx(ptr, &res[0], len(res), 0)
|
||||
|
|
|
@ -2,6 +2,26 @@
|
|||
|
||||
package win
|
||||
|
||||
const (
|
||||
ICC_LISTVIEW_CLASSES = 0x00000001
|
||||
ICC_TREEVIEW_CLASSES = 0x00000002
|
||||
ICC_BAR_CLASSES = 0x00000004
|
||||
ICC_TAB_CLASSES = 0x00000008
|
||||
ICC_UPDOWN_CLASS = 0x00000010
|
||||
ICC_PROGRESS_CLASS = 0x00000020
|
||||
ICC_HOTKEY_CLASS = 0x00000040
|
||||
ICC_ANIMATE_CLASS = 0x00000080
|
||||
ICC_WIN95_CLASSES = 0x000000FF
|
||||
ICC_DATE_CLASSES = 0x00000100
|
||||
ICC_USEREX_CLASSES = 0x00000200
|
||||
ICC_COOL_CLASSES = 0x00000400
|
||||
ICC_INTERNET_CLASSES = 0x00000800
|
||||
ICC_PAGESCROLLER_CLASS = 0x00001000
|
||||
ICC_NATIVEFNTCTL_CLASS = 0x00002000
|
||||
ICC_STANDARD_CLASSES = 0x00004000
|
||||
ICC_LINK_CLASS = 0x00008000
|
||||
)
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/commctrl/ns-commctrl-initcommoncontrolsex
|
||||
type INITCOMMONCONTROLSEX struct {
|
||||
Size uint32
|
||||
|
|
|
@ -32,38 +32,41 @@ func CoInitializeEx(reserved uintptr, coInit uint32) error {
|
|||
|
||||
func CoUninitialize() { windows.CoUninitialize() }
|
||||
|
||||
func CoTaskMemFree(address unsafe.Pointer) { windows.CoTaskMemFree(address) }
|
||||
|
||||
// https://github.com/wine-mirror/wine/blob/master/include/unknwn.idl
|
||||
|
||||
type _IUnknownBase struct{ COMObject }
|
||||
type _IUnknownVtbl struct {
|
||||
type IUnknown struct{}
|
||||
type iUnknownVtbl struct {
|
||||
QueryInterface uintptr
|
||||
AddRef uintptr
|
||||
Release uintptr
|
||||
}
|
||||
|
||||
func (c *_IUnknownBase) Release() {
|
||||
vtbl := (*(**_IUnknownVtbl)(unsafe.Pointer(c)))
|
||||
c.Call(vtbl.Release)
|
||||
func (u *IUnknown) Release() {
|
||||
vtbl := *(**iUnknownVtbl)(unsafe.Pointer(u))
|
||||
u.call(vtbl.Release)
|
||||
}
|
||||
|
||||
type COMObject struct{}
|
||||
|
||||
//go:uintptrescapes
|
||||
func (o *COMObject) Call(trap uintptr, a ...uintptr) (r1, r2 uintptr, lastErr error) {
|
||||
func (u *IUnknown) 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)
|
||||
return syscall.Syscall(trap, nargs+1, uintptr(unsafe.Pointer(u)), 0, 0)
|
||||
case 1:
|
||||
return syscall.Syscall(trap, nargs+1, uintptr(unsafe.Pointer(o)), a[0], 0)
|
||||
return syscall.Syscall(trap, nargs+1, uintptr(unsafe.Pointer(u)), a[0], 0)
|
||||
case 2:
|
||||
return syscall.Syscall(trap, nargs+1, uintptr(unsafe.Pointer(o)), a[0], a[1])
|
||||
return syscall.Syscall(trap, nargs+1, uintptr(unsafe.Pointer(u)), a[0], a[1])
|
||||
default:
|
||||
panic("COM call with too many arguments.")
|
||||
}
|
||||
}
|
||||
|
||||
//sys CoCreateInstance(clsid uintptr, unkOuter *COMObject, clsContext int32, iid uintptr, address unsafe.Pointer) (res error) = ole32.CoCreateInstance
|
||||
//sys CoTaskMemFree(address Pointer) = ole32.CoTaskMemFree
|
||||
// https://github.com/wine-mirror/wine/blob/master/include/objidl.idl
|
||||
|
||||
type IBindCtx struct{ IUnknown }
|
||||
|
||||
//sys CoCreateInstance(clsid uintptr, unkOuter *IUnknown, clsContext int32, iid uintptr, address unsafe.Pointer) (res error) = ole32.CoCreateInstance
|
||||
|
||||
func uuid(s string) uintptr {
|
||||
return (*reflect.StringHeader)(unsafe.Pointer(&s)).Data
|
||||
|
|
|
@ -14,8 +14,73 @@ const (
|
|||
BFFM_INITIALIZED = 1
|
||||
BFFM_SETSELECTION = WM_USER + 103
|
||||
|
||||
NIM_ADD = 0
|
||||
NIM_DELETE = 2
|
||||
// ShellNotifyIcon messages
|
||||
NIM_ADD = 0
|
||||
NIM_MODIFY = 1
|
||||
NIM_DELETE = 2
|
||||
NIM_SETFOCUS = 3
|
||||
NIM_SETVERSION = 4
|
||||
|
||||
// NOTIFYICONDATA flags
|
||||
NIF_MESSAGE = 0x01
|
||||
NIF_ICON = 0x02
|
||||
NIF_TIP = 0x04
|
||||
NIF_STATE = 0x08
|
||||
NIF_INFO = 0x10
|
||||
NIF_GUID = 0x20
|
||||
NIF_REALTIME = 0x40
|
||||
NIF_SHOWTIP = 0x80
|
||||
|
||||
// NOTIFYICONDATA info flags
|
||||
NIIF_NONE = 0x00
|
||||
NIIF_INFO = 0x01
|
||||
NIIF_WARNING = 0x02
|
||||
NIIF_ERROR = 0x03
|
||||
NIIF_USER = 0x04
|
||||
NIIF_NOSOUND = 0x10
|
||||
NIIF_LARGE_ICON = 0x20
|
||||
NIIF_RESPECT_QUIET_TIME = 0x80
|
||||
NIIF_ICON_MASK = 0x0F
|
||||
|
||||
// NOTIFYICONDATA state
|
||||
NIS_HIDDEN = 0x1
|
||||
NIS_SHAREDICON = 0x2
|
||||
|
||||
// IFileOpenDialog options
|
||||
FOS_OVERWRITEPROMPT = 0x2
|
||||
FOS_STRICTFILETYPES = 0x4
|
||||
FOS_NOCHANGEDIR = 0x8
|
||||
FOS_PICKFOLDERS = 0x20
|
||||
FOS_FORCEFILESYSTEM = 0x40
|
||||
FOS_ALLNONSTORAGEITEMS = 0x80
|
||||
FOS_NOVALIDATE = 0x100
|
||||
FOS_ALLOWMULTISELECT = 0x200
|
||||
FOS_PATHMUSTEXIST = 0x800
|
||||
FOS_FILEMUSTEXIST = 0x1000
|
||||
FOS_CREATEPROMPT = 0x2000
|
||||
FOS_SHAREAWARE = 0x4000
|
||||
FOS_NOREADONLYRETURN = 0x8000
|
||||
FOS_NOTESTFILECREATE = 0x10000
|
||||
FOS_HIDEMRUPLACES = 0x20000
|
||||
FOS_HIDEPINNEDPLACES = 0x40000
|
||||
FOS_NODEREFERENCELINKS = 0x100000
|
||||
FOS_OKBUTTONNEEDSINTERACTION = 0x200000
|
||||
FOS_DONTADDTORECENT = 0x2000000
|
||||
FOS_FORCESHOWHIDDEN = 0x10000000
|
||||
FOS_DEFAULTNOMINIMODE = 0x20000000
|
||||
FOS_FORCEPREVIEWPANEON = 0x40000000
|
||||
FOS_SUPPORTSTREAMABLEITEMS = 0x80000000
|
||||
|
||||
SIGDN_NORMALDISPLAY = 0x00000000
|
||||
SIGDN_PARENTRELATIVEPARSING = ^(^0x18001 + 0x80000000)
|
||||
SIGDN_DESKTOPABSOLUTEPARSING = ^(^0x28000 + 0x80000000)
|
||||
SIGDN_PARENTRELATIVEEDITING = ^(^0x31001 + 0x80000000)
|
||||
SIGDN_DESKTOPABSOLUTEEDITING = ^(^0x4c000 + 0x80000000)
|
||||
SIGDN_FILESYSPATH = ^(^0x58000 + 0x80000000)
|
||||
SIGDN_URL = ^(^0x68000 + 0x80000000)
|
||||
SIGDN_PARENTRELATIVEFORADDRESSBAR = ^(^0x7c001 + 0x80000000)
|
||||
SIGDN_PARENTRELATIVE = ^(^0x80001 + 0x80000000)
|
||||
SIGDN_PARENTRELATIVEFORUI = ^(^0x94001 + 0x80000000)
|
||||
)
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/shlobj_core/ns-shlobj_core-browseinfow
|
||||
|
@ -49,6 +114,8 @@ type NOTIFYICONDATA struct {
|
|||
// BalloonIcon Handle // NOTIFYICONDATAA_V3_SIZE
|
||||
}
|
||||
|
||||
type IDLIST struct{}
|
||||
|
||||
// https://github.com/wine-mirror/wine/blob/master/include/shobjidl.idl
|
||||
|
||||
var (
|
||||
|
@ -57,30 +124,25 @@ var (
|
|||
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
|
||||
type IFileOpenDialog struct{ IFileDialog }
|
||||
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)))
|
||||
func (u *IFileOpenDialog) GetResults() (res *IShellItemArray, err error) {
|
||||
vtbl := *(**iFileOpenDialogVtbl)(unsafe.Pointer(u))
|
||||
hr, _, _ := u.call(vtbl.GetResults, uintptr(unsafe.Pointer(&res)))
|
||||
if hr != 0 {
|
||||
err = syscall.Errno(hr)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type _IFileDialogBase struct{ _IModalWindowBase }
|
||||
type _IFileDialogVtbl struct {
|
||||
_IModalWindowVtbl
|
||||
type IFileDialog struct{ IModalWindow }
|
||||
type iFileDialogVtbl struct {
|
||||
iModalWindowVtbl
|
||||
SetFileTypes uintptr
|
||||
SetFileTypeIndex uintptr
|
||||
GetFileTypeIndex uintptr
|
||||
|
@ -106,74 +168,69 @@ type _IFileDialogVtbl struct {
|
|||
SetFilter uintptr
|
||||
}
|
||||
|
||||
func (c *_IFileDialogBase) SetOptions(fos int) (err error) {
|
||||
vtbl := (*(**_IFileDialogVtbl)(unsafe.Pointer(c)))
|
||||
hr, _, _ := c.Call(vtbl.SetOptions, uintptr(fos))
|
||||
func (u *IFileDialog) SetOptions(fos int) (err error) {
|
||||
vtbl := *(**iFileDialogVtbl)(unsafe.Pointer(u))
|
||||
hr, _, _ := u.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)))
|
||||
func (u *IFileDialog) GetOptions() (fos int, err error) {
|
||||
vtbl := *(**iFileDialogVtbl)(unsafe.Pointer(u))
|
||||
hr, _, _ := u.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)))
|
||||
func (u *IFileDialog) SetFolder(item *IShellItem) (err error) {
|
||||
vtbl := *(**iFileDialogVtbl)(unsafe.Pointer(u))
|
||||
hr, _, _ := u.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)))
|
||||
func (u *IFileDialog) SetTitle(title *uint16) (err error) {
|
||||
vtbl := *(**iFileDialogVtbl)(unsafe.Pointer(u))
|
||||
hr, _, _ := u.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)))
|
||||
func (u *IFileDialog) GetResult() (item *IShellItem, err error) {
|
||||
vtbl := *(**iFileDialogVtbl)(unsafe.Pointer(u))
|
||||
hr, _, _ := u.call(vtbl.GetResult, uintptr(unsafe.Pointer(&item)))
|
||||
if hr != 0 {
|
||||
err = syscall.Errno(hr)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type _IModalWindowBase struct{ _IUnknownBase }
|
||||
type _IModalWindowVtbl struct {
|
||||
_IUnknownVtbl
|
||||
type IModalWindow struct{ IUnknown }
|
||||
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))
|
||||
func (u *IModalWindow) Show(wnd HWND) (err error) {
|
||||
vtbl := *(**iModalWindowVtbl)(unsafe.Pointer(u))
|
||||
hr, _, _ := u.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
|
||||
type IShellItem struct{ IUnknown }
|
||||
type iShellItemVtbl struct {
|
||||
iUnknownVtbl
|
||||
BindToHandler uintptr
|
||||
GetParent uintptr
|
||||
GetDisplayName uintptr
|
||||
|
@ -181,10 +238,10 @@ type _IShellItemVtbl struct {
|
|||
Compare uintptr
|
||||
}
|
||||
|
||||
func (c *_IShellItemBase) GetDisplayName(name int) (res string, err error) {
|
||||
func (u *IShellItem) 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)))
|
||||
vtbl := *(**iShellItemVtbl)(unsafe.Pointer(u))
|
||||
hr, _, _ := u.call(vtbl.GetDisplayName, uintptr(name), uintptr(unsafe.Pointer(&ptr)))
|
||||
if hr != 0 {
|
||||
err = syscall.Errno(hr)
|
||||
} else {
|
||||
|
@ -196,14 +253,9 @@ func (c *_IShellItemBase) GetDisplayName(name int) (res string, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
type IShellItemArray struct {
|
||||
_IShellItemArrayBase
|
||||
_ *_IShellItemArrayVtbl
|
||||
}
|
||||
|
||||
type _IShellItemArrayBase struct{ _IUnknownBase }
|
||||
type _IShellItemArrayVtbl struct {
|
||||
_IUnknownVtbl
|
||||
type IShellItemArray struct{ IUnknown }
|
||||
type iShellItemArrayVtbl struct {
|
||||
iUnknownVtbl
|
||||
BindToHandler uintptr
|
||||
GetPropertyStore uintptr
|
||||
GetPropertyDescriptionList uintptr
|
||||
|
@ -213,25 +265,25 @@ type _IShellItemArrayVtbl struct {
|
|||
EnumItems uintptr
|
||||
}
|
||||
|
||||
func (c *_IShellItemArrayBase) GetCount() (numItems uint32, err error) {
|
||||
vtbl := (*(**_IShellItemArrayVtbl)(unsafe.Pointer(c)))
|
||||
hr, _, _ := c.Call(vtbl.GetCount, uintptr(unsafe.Pointer(&numItems)))
|
||||
func (u *IShellItemArray) GetCount() (numItems uint32, err error) {
|
||||
vtbl := *(**iShellItemArrayVtbl)(unsafe.Pointer(u))
|
||||
hr, _, _ := u.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)))
|
||||
func (u *IShellItemArray) GetItemAt(index uint32) (item *IShellItem, err error) {
|
||||
vtbl := *(**iShellItemArrayVtbl)(unsafe.Pointer(u))
|
||||
hr, _, _ := u.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 SHBrowseForFolder(bi *BROWSEINFO) (ret *IDLIST) = shell32.SHBrowseForFolder
|
||||
//sys SHCreateItemFromParsingName(path *uint16, bc *IBindCtx, iid uintptr, item **IShellItem) (res error) = shell32.SHCreateItemFromParsingName
|
||||
//sys ShellNotifyIcon(message uint32, data *NOTIFYICONDATA) (ret int, err error) = shell32.Shell_NotifyIconW
|
||||
//sys SHGetPathFromIDListEx(ptr Pointer, path *uint16, pathLen int, opts int) (ok bool) = shell32.SHGetPathFromIDListEx
|
||||
//sys SHGetPathFromIDListEx(ptr *IDLIST, path *uint16, pathLen int, opts int) (ok bool) = shell32.SHGetPathFromIDListEx
|
||||
|
|
|
@ -19,6 +19,9 @@ const (
|
|||
IDYES = 6
|
||||
IDNO = 7
|
||||
|
||||
// Control IDs
|
||||
IDC_STATIC_OK = 20
|
||||
|
||||
// MessageBox types
|
||||
MB_OK = windows.MB_OK
|
||||
MB_OKCANCEL = windows.MB_OKCANCEL
|
||||
|
@ -60,7 +63,7 @@ const (
|
|||
STM_SETICON = 0x0170
|
||||
|
||||
// CreateWindow
|
||||
CW_USEDEFAULT = 0x80000000
|
||||
CW_USEDEFAULT = -0x80000000
|
||||
|
||||
// Window classes
|
||||
PROGRESS_CLASS = "msctls_progress32"
|
||||
|
@ -217,18 +220,34 @@ const (
|
|||
// SetWindowsHookEx types
|
||||
WH_CALLWNDPROCRET = 12
|
||||
|
||||
USER_DEFAULT_SCREEN_DPI = 96
|
||||
// System colors
|
||||
COLOR_WINDOW = 5
|
||||
|
||||
// DPI awareness
|
||||
USER_DEFAULT_SCREEN_DPI = 96
|
||||
DPI_AWARENESS_CONTEXT_UNAWARE = ^uintptr(1) + 1
|
||||
DPI_AWARENESS_CONTEXT_SYSTEM_AWARE = ^uintptr(2) + 1
|
||||
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE = ^uintptr(3) + 1
|
||||
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 = ^uintptr(4) + 1
|
||||
DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED = ^uintptr(5) + 1
|
||||
|
||||
// LoadImage type
|
||||
IMAGE_BITMAP = 0
|
||||
IMAGE_ICON = 1
|
||||
IMAGE_CURSOR = 2
|
||||
|
||||
// LoadIcon resources
|
||||
IDI_APPLICATION = 32512
|
||||
IDI_ERROR = 32513
|
||||
IDI_HAND = 32513
|
||||
IDI_QUESTION = 32514
|
||||
IDI_WARNING = 32515
|
||||
IDI_EXCLAMATION = 32515
|
||||
IDI_ASTERISK = 32516
|
||||
IDI_INFORMATION = 32516
|
||||
IDI_WINLOGO = 32517
|
||||
IDI_SHIELD = 32518
|
||||
|
||||
// LoadResource (image/icon) flags
|
||||
LR_DEFAULTCOLOR = 0x00000000
|
||||
LR_MONOCHROME = 0x00000001
|
||||
|
|
|
@ -7,7 +7,7 @@ import "golang.org/x/sys/windows"
|
|||
|
||||
type Handle = windows.Handle
|
||||
type HWND = windows.HWND
|
||||
type Pointer uintptr
|
||||
type Pointer = windows.Pointer
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-systemtime
|
||||
type SYSTEMTIME struct {
|
||||
|
|
|
@ -62,7 +62,6 @@ var (
|
|||
procGetModuleHandleW = modkernel32.NewProc("GetModuleHandleW")
|
||||
procReleaseActCtx = modkernel32.NewProc("ReleaseActCtx")
|
||||
procCoCreateInstance = modole32.NewProc("CoCreateInstance")
|
||||
procCoTaskMemFree = modole32.NewProc("CoTaskMemFree")
|
||||
procSHBrowseForFolder = modshell32.NewProc("SHBrowseForFolder")
|
||||
procSHCreateItemFromParsingName = modshell32.NewProc("SHCreateItemFromParsingName")
|
||||
procSHGetPathFromIDListEx = modshell32.NewProc("SHGetPathFromIDListEx")
|
||||
|
@ -199,7 +198,7 @@ func ReleaseActCtx(actCtx Handle) {
|
|||
return
|
||||
}
|
||||
|
||||
func CoCreateInstance(clsid uintptr, unkOuter *COMObject, clsContext int32, iid uintptr, address unsafe.Pointer) (res error) {
|
||||
func CoCreateInstance(clsid uintptr, unkOuter *IUnknown, clsContext int32, iid uintptr, address unsafe.Pointer) (res error) {
|
||||
r0, _, _ := syscall.Syscall6(procCoCreateInstance.Addr(), 5, uintptr(clsid), uintptr(unsafe.Pointer(unkOuter)), uintptr(clsContext), uintptr(iid), uintptr(address), 0)
|
||||
if r0 != 0 {
|
||||
res = syscall.Errno(r0)
|
||||
|
@ -207,18 +206,13 @@ func CoCreateInstance(clsid uintptr, unkOuter *COMObject, clsContext int32, iid
|
|||
return
|
||||
}
|
||||
|
||||
func CoTaskMemFree(address Pointer) {
|
||||
syscall.Syscall(procCoTaskMemFree.Addr(), 1, uintptr(address), 0, 0)
|
||||
return
|
||||
}
|
||||
|
||||
func SHBrowseForFolder(bi *BROWSEINFO) (ret Pointer) {
|
||||
func SHBrowseForFolder(bi *BROWSEINFO) (ret *IDLIST) {
|
||||
r0, _, _ := syscall.Syscall(procSHBrowseForFolder.Addr(), 1, uintptr(unsafe.Pointer(bi)), 0, 0)
|
||||
ret = Pointer(r0)
|
||||
ret = (*IDLIST)(unsafe.Pointer(r0))
|
||||
return
|
||||
}
|
||||
|
||||
func SHCreateItemFromParsingName(path *uint16, bc *COMObject, iid uintptr, item **IShellItem) (res error) {
|
||||
func SHCreateItemFromParsingName(path *uint16, bc *IBindCtx, iid uintptr, item **IShellItem) (res error) {
|
||||
r0, _, _ := syscall.Syscall6(procSHCreateItemFromParsingName.Addr(), 4, uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(bc)), uintptr(iid), uintptr(unsafe.Pointer(item)), 0, 0)
|
||||
if r0 != 0 {
|
||||
res = syscall.Errno(r0)
|
||||
|
@ -226,8 +220,8 @@ func SHCreateItemFromParsingName(path *uint16, bc *COMObject, iid uintptr, item
|
|||
return
|
||||
}
|
||||
|
||||
func SHGetPathFromIDListEx(ptr Pointer, path *uint16, pathLen int, opts int) (ok bool) {
|
||||
r0, _, _ := syscall.Syscall6(procSHGetPathFromIDListEx.Addr(), 4, uintptr(ptr), uintptr(unsafe.Pointer(path)), uintptr(pathLen), uintptr(opts), 0, 0)
|
||||
func SHGetPathFromIDListEx(ptr *IDLIST, path *uint16, pathLen int, opts int) (ok bool) {
|
||||
r0, _, _ := syscall.Syscall6(procSHGetPathFromIDListEx.Addr(), 4, uintptr(unsafe.Pointer(ptr)), uintptr(unsafe.Pointer(path)), uintptr(pathLen), uintptr(opts), 0, 0)
|
||||
ok = r0 != 0
|
||||
return
|
||||
}
|
||||
|
|
|
@ -187,7 +187,7 @@ func listProc(wnd win.HWND, msg uint32, wparam uintptr, lparam *unsafe.Pointer)
|
|||
dlg.out = make([]string, len)
|
||||
if len > 0 {
|
||||
indices := make([]int32, len)
|
||||
win.SendMessage(dlg.listCtl, win.LB_GETSELITEMS, len, uintptr(unsafe.Pointer(&indices[0])))
|
||||
win.SendMessagePointer(dlg.listCtl, win.LB_GETSELITEMS, len, unsafe.Pointer(&indices[0]))
|
||||
for i, idx := range indices {
|
||||
dlg.out[i] = dlg.items[idx]
|
||||
}
|
||||
|
|
|
@ -88,6 +88,7 @@ func message(kind messageKind, text string, opts options) error {
|
|||
}
|
||||
|
||||
func hookMessageDialog(opts options) (unhook context.CancelFunc, err error) {
|
||||
// TODO: use GetDlgItem, SetDlgItemText instead of EnumChildWindows.
|
||||
return hookDialog(opts.ctx, opts.windowIcon, nil, func(wnd win.HWND) {
|
||||
win.EnumChildWindows(wnd, syscall.NewCallback(hookMessageDialogCallback),
|
||||
unsafe.Pointer(&opts))
|
||||
|
@ -110,7 +111,7 @@ func hookMessageDialogCallback(wnd win.HWND, lparam *options) uintptr {
|
|||
win.SetWindowText(wnd, strptr(*text))
|
||||
}
|
||||
|
||||
if ctl == 20 /*IDC_STATIC_OK*/ {
|
||||
if ctl == win.IDC_STATIC_OK {
|
||||
icon := getIcon(lparam.icon)
|
||||
if icon.handle != 0 {
|
||||
defer icon.delete()
|
||||
|
|
|
@ -19,8 +19,8 @@ func notify(text string, opts options) error {
|
|||
var args win.NOTIFYICONDATA
|
||||
args.StructSize = uint32(unsafe.Sizeof(args))
|
||||
args.ID = rand.Uint32()
|
||||
args.Flags = 0x00000010 // NIF_INFO
|
||||
args.State = 0x00000001 // NIS_HIDDEN
|
||||
args.Flags = win.NIF_INFO
|
||||
args.State = win.NIS_HIDDEN
|
||||
|
||||
info := syscall.StringToUTF16(text)
|
||||
copy(args.Info[:len(args.Info)-1], info)
|
||||
|
@ -32,18 +32,18 @@ func notify(text string, opts options) error {
|
|||
|
||||
switch opts.icon {
|
||||
case InfoIcon, QuestionIcon:
|
||||
args.InfoFlags |= 0x1 // NIIF_INFO
|
||||
args.InfoFlags |= win.NIIF_INFO
|
||||
case WarningIcon:
|
||||
args.InfoFlags |= 0x2 // NIIF_WARNING
|
||||
args.InfoFlags |= win.NIIF_WARNING
|
||||
case ErrorIcon:
|
||||
args.InfoFlags |= 0x3 // NIIF_ERROR
|
||||
args.InfoFlags |= win.NIIF_ERROR
|
||||
default:
|
||||
icon := getIcon(opts.icon)
|
||||
if icon.handle != 0 {
|
||||
defer icon.delete()
|
||||
args.Icon = win.Handle(icon.handle)
|
||||
args.Flags |= 0x00000002 // NIF_ICON
|
||||
args.InfoFlags |= 0x4 // NIIF_USER
|
||||
args.Flags |= win.NIF_ICON
|
||||
args.InfoFlags |= win.NIIF_USER
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,8 +23,6 @@ const (
|
|||
_WS_ZEN_BUTTON = _WS_ZEN_CONTROL
|
||||
)
|
||||
|
||||
const nullptr win.Pointer = 0
|
||||
|
||||
func intptr(i int64) uintptr { return uintptr(i) }
|
||||
func strptr(s string) *uint16 { return syscall.StringToUTF16Ptr(s) }
|
||||
|
||||
|
@ -56,7 +54,7 @@ func setup() context.CancelFunc {
|
|||
|
||||
var icc win.INITCOMMONCONTROLSEX
|
||||
icc.Size = uint32(unsafe.Sizeof(icc))
|
||||
icc.ICC = 0x00004020 // ICC_STANDARD_CLASSES|ICC_PROGRESS_CLASS
|
||||
icc.ICC = win.ICC_STANDARD_CLASSES | win.ICC_DATE_CLASSES | win.ICC_PROGRESS_CLASS
|
||||
win.InitCommonControlsEx(&icc)
|
||||
|
||||
return func() {
|
||||
|
@ -264,13 +262,13 @@ func getIcon(i any) icon {
|
|||
var resource uintptr
|
||||
switch i {
|
||||
case ErrorIcon:
|
||||
resource = 32513 // IDI_ERROR
|
||||
resource = win.IDI_ERROR
|
||||
case QuestionIcon:
|
||||
resource = 32514 // IDI_QUESTION
|
||||
resource = win.IDI_QUESTION
|
||||
case WarningIcon:
|
||||
resource = 32515 // IDI_WARNING
|
||||
resource = win.IDI_WARNING
|
||||
case InfoIcon:
|
||||
resource = 32516 // IDI_INFORMATION
|
||||
resource = win.IDI_INFORMATION
|
||||
}
|
||||
if resource != 0 {
|
||||
res.handle, _ = win.LoadIcon(0, resource)
|
||||
|
@ -331,7 +329,7 @@ func registerClass(instance, icon win.Handle, proc uintptr) (*uint16, error) {
|
|||
wcx.WndProc = proc
|
||||
wcx.Icon = icon
|
||||
wcx.Instance = instance
|
||||
wcx.Background = 5 // COLOR_WINDOW
|
||||
wcx.Background = win.COLOR_WINDOW
|
||||
wcx.ClassName = strptr(name)
|
||||
|
||||
if err := win.RegisterClassEx(&wcx); err != nil {
|
||||
|
|
Loading…
Reference in a new issue