From a806229364c4a668231a8b0b490ef94a63e44e0a Mon Sep 17 00:00:00 2001 From: Nuno Cruces Date: Mon, 13 Sep 2021 13:17:15 +0100 Subject: [PATCH] Avoid closures in syscall.NewCallback, #20. --- file_windows.go | 14 ++++++++------ msg_test.go | 9 +++++++++ msg_windows.go | 43 +++++++++++++++++++++++-------------------- util_windows.go | 30 ++++++++++++++++-------------- 4 files changed, 56 insertions(+), 40 deletions(-) diff --git a/file_windows.go b/file_windows.go index aac4577..d80a950 100644 --- a/file_windows.go +++ b/file_windows.go @@ -316,12 +316,7 @@ func browseForFolder(opts options) (string, []string, error) { } if opts.filename != "" { args.LParam = strptr(opts.filename) - args.CallbackFunc = syscall.NewCallback(func(wnd uintptr, msg uint32, lparam, data uintptr) uintptr { - if msg == 1 { // BFFM_INITIALIZED - sendMessage.Call(wnd, 1024+103 /* BFFM_SETSELECTIONW */, 1 /* TRUE */, data) - } - return 0 - }) + args.CallbackFunc = syscall.NewCallback(browseForFolderCallback) defer runtime.KeepAlive(opts.filename) } @@ -349,6 +344,13 @@ func browseForFolder(opts options) (string, []string, error) { return str, []string{str}, nil } +func browseForFolderCallback(wnd uintptr, msg uint32, lparam, data uintptr) uintptr { + if msg == 1 { // BFFM_INITIALIZED + sendMessage.Call(wnd, 1024+103 /* BFFM_SETSELECTIONW */, 1 /* TRUE */, data) + } + return 0 +} + func initDirNameExt(filename string, name []uint16) (dir *uint16, ext *uint16) { d, n := splitDirAndName(filename) e := filepath.Ext(n) diff --git a/msg_test.go b/msg_test.go index bd787dd..af122d8 100644 --- a/msg_test.go +++ b/msg_test.go @@ -132,3 +132,12 @@ func TestMessage_script(t *testing.T) { }) } } + +func TestMessage_callbacks(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + cancel() + + for i := 0; i < 2000; i++ { + zenity.Error("text", zenity.Context(ctx)) + } +} diff --git a/msg_windows.go b/msg_windows.go index 26a740c..6df6ad5 100644 --- a/msg_windows.go +++ b/msg_windows.go @@ -79,25 +79,28 @@ func message(kind messageKind, text string, opts options) error { func hookMessageLabels(kind messageKind, opts options) (unhook context.CancelFunc, err error) { return hookDialog(opts.ctx, func(wnd uintptr) { enumChildWindows.Call(wnd, - syscall.NewCallback(func(wnd, lparam uintptr) uintptr { - var name [8]uint16 - getClassName.Call(wnd, uintptr(unsafe.Pointer(&name)), uintptr(len(name))) - if syscall.UTF16ToString(name[:]) == "Button" { - ctl, _, _ := getDlgCtrlID.Call(wnd) - var text *string - switch ctl { - case 1, 6: // IDOK, IDYES - text = opts.okLabel - case 2: // IDCANCEL - text = opts.cancelLabel - case 7: // IDNO - text = opts.extraButton - } - if text != nil { - setWindowText.Call(wnd, strptr(*text)) - } - } - return 1 - }), 0) + syscall.NewCallback(hookMessageLabelsCallback), + uintptr(unsafe.Pointer(&opts))) }) } + +func hookMessageLabelsCallback(wnd uintptr, lparam *options) uintptr { + var name [8]uint16 + getClassName.Call(wnd, uintptr(unsafe.Pointer(&name)), uintptr(len(name))) + if syscall.UTF16ToString(name[:]) == "Button" { + ctl, _, _ := getDlgCtrlID.Call(wnd) + var text *string + switch ctl { + case 1, 6: // IDOK, IDYES + text = lparam.okLabel + case 2: // IDCANCEL + text = lparam.cancelLabel + case 7: // IDNO + text = lparam.extraButton + } + if text != nil { + setWindowText.Call(wnd, strptr(*text)) + } + } + return 1 +} diff --git a/util_windows.go b/util_windows.go index 875e044..a406ad7 100644 --- a/util_windows.go +++ b/util_windows.go @@ -90,21 +90,13 @@ func strptr(s string) uintptr { } func setup() context.CancelFunc { - var hwnd uintptr - enumWindows.Call(syscall.NewCallback(func(wnd, lparam uintptr) uintptr { - var pid uintptr - getWindowThreadProcessId.Call(wnd, uintptr(unsafe.Pointer(&pid))) - if int(pid) == os.Getpid() { - hwnd = wnd - return 0 - } - return 1 - }), 0) - if hwnd == 0 { - hwnd, _, _ = getConsoleWindow.Call() + var wnd uintptr + enumWindows.Call(syscall.NewCallback(setupEnumCallback), uintptr(unsafe.Pointer(&wnd))) + if wnd == 0 { + wnd, _, _ = getConsoleWindow.Call() } - if hwnd != 0 { - setForegroundWindow.Call(hwnd) + if wnd != 0 { + setForegroundWindow.Call(wnd) } runtime.LockOSThread() @@ -140,6 +132,16 @@ func setup() context.CancelFunc { } } +func setupEnumCallback(wnd uintptr, lparam *uintptr) uintptr { + var pid uintptr + getWindowThreadProcessId.Call(wnd, uintptr(unsafe.Pointer(&pid))) + if int(pid) == os.Getpid() { + *lparam = wnd + return 0 // stop enumeration + } + return 1 // continue enumeration +} + func commDlgError() error { s, _, _ := commDlgExtendedError.Call() if s == 0 {