How do I use the MsgBox "help" button Topic is solved

Get help with using AutoHotkey (v2 or newer) and its commands and hotkeys
User avatar
Jimmysan
Posts: 3
Joined: 06 May 2024, 05:18
Contact:

How do I use the MsgBox "help" button

Post by Jimmysan » 06 May 2024, 05:29

I'm trying to add a help button to my MsgBox popups so that it would direct people to my script's GitHub page whenever an error occurs.
Can someone please provide some example code showing an example of the help button directing to google.com?

I read on the docs:
When the Help button option (16384) is present in Options, pressing the Help button will have no effect unless both of the following are true:
1. The message box is owned by a GUI window by means of the OwnDialogs option.
Is it possible to not have a GUI? I want the script to be more like a hotkey and not like an app.

User avatar
Noitalommi_2
Posts: 278
Joined: 16 Aug 2023, 10:58

Re: How do I use the MsgBox "help" button  Topic is solved

Post by Noitalommi_2 » 06 May 2024, 06:05

Hi.

You don't have to show the Gui.

Code: Select all

OnMessage(WM_HELP := 0x0053, (*) => Run("www.google.com"))
g := Gui("+OwnDialogs")
MsgBox("test", "Help", 16384)
Edit:
Alternatively, you could handle it this way.

Code: Select all

if MsgBox("Do you need help?", "Help?", 262180) = "Yes"
    Run("www.google.com")

User avatar
Seven0528
Posts: 394
Joined: 23 Jan 2023, 04:52
Location: South Korea
Contact:

Re: How do I use the MsgBox "help" button

Post by Seven0528 » 06 May 2024, 06:28

 The code I'm personally using looks like this.
It actually shows what information is contained in the HELPINFO structure.

Code: Select all

#Requires AutoHotkey v2.0
#SingleInstance Force
;---------------------------------------------------------
onMessage(0x0053, WM_HELP)
WM_HELP(wParam, lParam, Msg, hWnd)    {
    prevDHW := detectHiddenWindows(true)
    hRootWnd := winExist()
    detectHiddenWindows(prevDHW)
    switch (hRootWnd)
    {
        case myGui.Hwnd:
            info := HELPINFO("winuser.h"), info.Ptr := lParam
            if !(hMsg := info.hItemHandle)
                return
            /*
            infoObj := info.getObj()
            tooltip("cbSize: " infoObj.cbSize
                . "`niContextType: " infoObj.iContextType
                . "`niCtrlId: " infoObj.iCtrlId
                . "`nhItemHandle: " infoObj.hItemHandle
                . "`ndwContextId: " infoObj.dwContextId
                . "`nMousePos.x: " infoObj.MousePos.x
                . "`nMousePos.y: " infoObj.MousePos.y)
            sleep(1000)
            tooltip()
            */
            winClose("ahk_id " hMsg)
            run("https://www.autohotkey.com/boards/viewtopic.php?f=82&t=129614")
    }
}
myGui := gui()
;---------------------------------------------------------
F7::  {
    myGui.opt("+OwnDialogs")
    msgbox("Text", "Title", 0x300|0x4000)
}
;---------------------------------------------------------
/*
 HELPINFO structure (winuser.h)
https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-helpinfo
 WM_HELP message
https://learn.microsoft.com/en-us/windows/win32/shell/wm-help
*/
HELPINFO(header)    {
    switch (header)
    {
        case "winuser.h":   return HELPINFO_winuser()
    }
}
class HELPINFO_winuser
{
    Ptr    {
        get => this._ptr
        set => this.MousePos._ptr:= this._ptr:= value
    }
    getObj()    {
        if (!this._ptr)
            return {}
        obj:={}
        ,obj.cbSize:=this.cbSize
        ,obj.iContextType:=this.iContextType
        ,obj.iCtrlId:=this.iCtrlId
        ,obj.hItemHandle:=this.hItemHandle
        ,obj.dwContextId:=this.dwContextId
        ,obj.MousePos:={}
        ,obj.MousePos.x:=this.MousePos.x
        ,obj.MousePos.y:=this.MousePos.y
        return obj
    }
    _ptr:=0
    __new()    {
        this.struct:=buffer(A_PtrSize==8?40:28,0), this._ptr:=this.struct.ptr
        this.MousePos:=HELPINFO_winuser._MousePos()
        this.MousePos._ptr:=this._ptr
        return this
    }
    __get(name, params)    {
        switch (name)
        {
            case "cbSize":          return numGet(this._ptr, 0, "UInt")
            case "iContextType":    return numGet(this._ptr, 4, "Int")
            case "iCtrlId":         return numGet(this._ptr, 8, "Int")
            case "hItemHandle":     return numGet(this._ptr, (A_PtrSize==8?16:12), "Ptr")
            case "dwContextId":     return numGet(this._ptr, (A_PtrSize==8?24:16), "UPtr")
        }
    }
    __set(name, param, value)     {
        switch (name)
        {
            case "cbSize":          numPut("UInt",value, this._ptr, 0)
            case "iContextType":    numPut("Int",value, this._ptr, 4)
            case "iCtrlId":         numPut("Int",value, this._ptr, 8)
            case "hItemHandle":     numPut("Ptr",value, this._ptr, (A_PtrSize==8?16:12))
            case "dwContextId":     numPut("UPtr",value, this._ptr, (A_PtrSize==8?24:16))
        }
        this.defineProp(name, {value:value})
    }
    class _MousePos
    {
        _ptr:=0
        __get(name, params)    {
            switch (name)
            {
                case "x":           return numGet(this._ptr, (A_PtrSize==8?32:20), "Int")
                case "y":           return numGet(this._ptr, (A_PtrSize==8?36:24), "Int")
            }
        }
        __set(name, param, value)     {
            switch (name)
            {
                case "left":        numPut("Int",value, this._ptr, (A_PtrSize==8?32:20))
                case "top":         numPut("Int",value, this._ptr, (A_PtrSize==8?36:24))
            }
            this.defineProp(name, {value:value})
        }
    }
}
/*
struct_HELPINFO_winuser(lphi)    { ;  ahk2.0
    info:={}                                                            ;  x64         x86
    info.cbSize         := numGet(0+(lphi),"UInt")                      ;   0           0
    info.iContextType   := numGet(0+(lphi+=4),"Int")                    ;   4           4
    info.iCtrlId        := numGet(0+(lphi+=4),"Int")                    ;   8           8
    info.hItemHandle    := numGet(0+(lphi+=(A_PtrSize==8?8:4)),"Ptr")   ;   16          12
    info.dwContextId    := numGet(0+(lphi+=A_PtrSize),"UPtr")           ;   24          16
    info.MousePos       := {}                                           ;
    info.MousePos.x     := numGet(0+(lphi+=A_PtrSize),"Int")            ;   32          20
    info.MousePos.y     := numGet(0+(lphi+=4),"Int")                    ;   36          24
    return info
}
*/
Last edited by Seven0528 on 06 May 2024, 07:22, edited 2 times in total.
  • English is not my native language. Please forgive any awkward expressions.
  • 영어는 제 모국어가 아닙니다. 어색한 표현이 있어도 양해해 주세요.

User avatar
Seven0528
Posts: 394
Joined: 23 Jan 2023, 04:52
Location: South Korea
Contact:

Re: How do I use the MsgBox "help" button

Post by Seven0528 » 06 May 2024, 07:03

 A more simplified version of the code is as follows.

Code: Select all

#Requires AutoHotkey v2.0
#SingleInstance Force
F2::
F3::  {
    thisKey := A_ThisHotkey
    result := MessageBoxHelp.show("Text", "Title", 0x4000)
    tooltip(thisKey ": " result)
    switch (result)
    {
        case "OK":
            ;  TO DO
        case "Help":
            ;  TO DO
            run("https://www.autohotkey.com/boards/viewtopic.php?f=82&t=129614")
    }
}
;---------------------------------------------------------
class MessageBoxHelp ;  ahk2.0
{
    static show(text?, title?, options:=0, callback:=-1, closeOnHelp:=true)    {
        static WM_HELP := 0x0053, MB_HELP := 0x00004000
        helpBtnExist := false
        for opt in strSplit(options,[A_Space,A_Tab])    {
            if (opt~="D)^(?:[[:digit:]]+|0[Xx][[:xdigit:]]+)$" && opt&MB_HELP)    {
                helpBtnExist := true
                break
            }
        }
        if (!helpBtnExist)
            return msgbox(text?, title?, options)
        tempGui := gui("+OwnDialogs"), this._results[hRootWnd:=tempGui.Hwnd] := ""
        objbm := objBindMethod(this,"_onHelp",hRootWnd,callback,closeOnHelp)    ,onMessage(WM_HELP, objbm, -1)
        result := msgbox(text?, title?, options)                                ,onMessage(WM_HELP, objbm, 0), objbm := ""
        result := (this._results[hRootWnd]?this._results[hRootWnd]:result)
        tempGui.destroy(), this._results.delete(hRootWnd)
        return result
    }
    static _results := map()
    static _onHelp(hRootWnd, callback, closeOnHelp, _, lphi, *)    {
        static WM_SYSCOMMAND := 0x0112, SC_CLOSE := 0xF060
        prevDHW := detectHiddenWindows(true)
        msgParentWindow := winExist(), detectHiddenWindows(prevDHW)
        if (msgParentWindow == hRootWnd)    {
            if (closeOnHelp)    {
                hItemHandle := numGet((lphi+(A_PtrSize==8?16:12)),"Ptr")
                hMenu := dllCall("User32.dll\GetSystemMenu", "Ptr",hItemHandle, "Int",false, "Ptr")
                lpmii := buffer(cbSize := (A_PtrSize==8?80:48), 0)
                if (dllCall("User32.dll\GetMenuItemInfoW", "Ptr",hMenu, "UInt",SC_CLOSE, "Int",false, "Ptr",lpmii.Ptr, "Int"))
                    dllCall("User32.dll\PostMessageW", "Ptr",hMenu, "UInt",WM_SYSCOMMAND, "UPtr",SC_CLOSE, "Ptr",0)
                else
                    controlSend("{Space}","Button1","ahk_id " hItemHandle)
                if (winWaitClose("ahk_id " hItemHandle,, 0.5))
                    this._results[hRootWnd] := "Help"
            }
            if (callback!==-1 && callback.hasMethod("call"))
                callback.call()
            return true
        }
    }
}
Last edited by Seven0528 on 07 May 2024, 03:54, edited 12 times in total.
  • English is not my native language. Please forgive any awkward expressions.
  • 영어는 제 모국어가 아닙니다. 어색한 표현이 있어도 양해해 주세요.

User avatar
Jimmysan
Posts: 3
Joined: 06 May 2024, 05:18
Contact:

Re: How do I use the MsgBox "help" button

Post by Jimmysan » 06 May 2024, 07:41

Thanks @Noitalommi_2, the first code block works for me. Now I'm wondering, what does this do?

Code: Select all

g := Gui("+OwnDialogs")

User avatar
Seven0528
Posts: 394
Joined: 23 Jan 2023, 04:52
Location: South Korea
Contact:

Re: How do I use the MsgBox "help" button

Post by Seven0528 » 06 May 2024, 08:52

 @Jimmysan
Please read the document before asking questions... Thank you.
 MsgBox - Remarks
The Help button: When the Help button option (16384) is present in Options, pressing the Help button will have no effect unless both of the following are true:

The message box is owned by a GUI window by means of the OwnDialogs option.
The script is monitoring the WM_HELP message (0x0053). For example: OnMessage(0x0053, WM_HELP). When the WM_HELP function is called, it may guide the user by means such as showing another window or message box.
 OwnDialogs
OwnDialogs: MyGui.Opt("+OwnDialogs") should be specified in each thread (such as a event handling function of a Button control) for which subsequently displayed MsgBox, InputBox, FileSelect, and DirSelect dialogs should be owned by the window. Such dialogs are modal, meaning that the user cannot interact with the GUI window until dismissing the dialog. By contrast, ToolTip windows do not become modal even though they become owned; they will merely stay always on top of their owner. In either case, any owned dialog or window is automatically destroyed when its GUI window is destroyed.
  • English is not my native language. Please forgive any awkward expressions.
  • 영어는 제 모국어가 아닙니다. 어색한 표현이 있어도 양해해 주세요.

User avatar
Jimmysan
Posts: 3
Joined: 06 May 2024, 05:18
Contact:

Re: How do I use the MsgBox "help" button

Post by Jimmysan » 06 May 2024, 19:14

Seven0528 wrote:
06 May 2024, 06:28
The code I'm personally using looks like this.
It actually shows what information is contained in the HELPINFO structure.

Code: Select all

#Requires AutoHotkey v2.0
#SingleInstance Force
;---------------------------------------------------------
onMessage(0x0053, WM_HELP)
WM_HELP(wParam, lParam, Msg, hWnd)    {
    prevDHW := detectHiddenWindows(true)
    hRootWnd := winExist()
    detectHiddenWindows(prevDHW)
    switch (hRootWnd)
    {
        case myGui.Hwnd:
            info := HELPINFO("winuser.h"), info.Ptr := lParam
            if !(hMsg := info.hItemHandle)
                return
            /*
            infoObj := info.getObj()
            tooltip("cbSize: " infoObj.cbSize
                . "`niContextType: " infoObj.iContextType
                . "`niCtrlId: " infoObj.iCtrlId
                . "`nhItemHandle: " infoObj.hItemHandle
                . "`ndwContextId: " infoObj.dwContextId
                . "`nMousePos.x: " infoObj.MousePos.x
                . "`nMousePos.y: " infoObj.MousePos.y)
            sleep(1000)
            tooltip()
            */
            winClose("ahk_id " hMsg)
            run("https://www.autohotkey.com/boards/viewtopic.php?f=82&t=129614")
    }
}
myGui := gui()
;---------------------------------------------------------
F7::  {
    myGui.opt("+OwnDialogs")
    msgbox("Text", "Title", 0x300|0x4000)
}
;---------------------------------------------------------
/*
 HELPINFO structure (winuser.h)
https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-helpinfo
 WM_HELP message
https://learn.microsoft.com/en-us/windows/win32/shell/wm-help
*/
HELPINFO(header)    {
    switch (header)
    {
        case "winuser.h":   return HELPINFO_winuser()
    }
}
class HELPINFO_winuser
{
    Ptr    {
        get => this._ptr
        set => this.MousePos._ptr:= this._ptr:= value
    }
    getObj()    {
        if (!this._ptr)
            return {}
        obj:={}
        ,obj.cbSize:=this.cbSize
        ,obj.iContextType:=this.iContextType
        ,obj.iCtrlId:=this.iCtrlId
        ,obj.hItemHandle:=this.hItemHandle
        ,obj.dwContextId:=this.dwContextId
        ,obj.MousePos:={}
        ,obj.MousePos.x:=this.MousePos.x
        ,obj.MousePos.y:=this.MousePos.y
        return obj
    }
    _ptr:=0
    __new()    {
        this.struct:=buffer(A_PtrSize==8?40:28,0), this._ptr:=this.struct.ptr
        this.MousePos:=HELPINFO_winuser._MousePos()
        this.MousePos._ptr:=this._ptr
        return this
    }
    __get(name, params)    {
        switch (name)
        {
            case "cbSize":          return numGet(this._ptr, 0, "UInt")
            case "iContextType":    return numGet(this._ptr, 4, "Int")
            case "iCtrlId":         return numGet(this._ptr, 8, "Int")
            case "hItemHandle":     return numGet(this._ptr, (A_PtrSize==8?16:12), "Ptr")
            case "dwContextId":     return numGet(this._ptr, (A_PtrSize==8?24:16), "UPtr")
        }
    }
    __set(name, param, value)     {
        switch (name)
        {
            case "cbSize":          numPut("UInt",value, this._ptr, 0)
            case "iContextType":    numPut("Int",value, this._ptr, 4)
            case "iCtrlId":         numPut("Int",value, this._ptr, 8)
            case "hItemHandle":     numPut("Ptr",value, this._ptr, (A_PtrSize==8?16:12))
            case "dwContextId":     numPut("UPtr",value, this._ptr, (A_PtrSize==8?24:16))
        }
        this.defineProp(name, {value:value})
    }
    class _MousePos
    {
        _ptr:=0
        __get(name, params)    {
            switch (name)
            {
                case "x":           return numGet(this._ptr, (A_PtrSize==8?32:20), "Int")
                case "y":           return numGet(this._ptr, (A_PtrSize==8?36:24), "Int")
            }
        }
        __set(name, param, value)     {
            switch (name)
            {
                case "left":        numPut("Int",value, this._ptr, (A_PtrSize==8?32:20))
                case "top":         numPut("Int",value, this._ptr, (A_PtrSize==8?36:24))
            }
            this.defineProp(name, {value:value})
        }
    }
}
/*
struct_HELPINFO_winuser(lphi)    { ;  ahk2.0
    info:={}                                                            ;  x64         x86
    info.cbSize         := numGet(0+(lphi),"UInt")                      ;   0           0
    info.iContextType   := numGet(0+(lphi+=4),"Int")                    ;   4           4
    info.iCtrlId        := numGet(0+(lphi+=4),"Int")                    ;   8           8
    info.hItemHandle    := numGet(0+(lphi+=(A_PtrSize==8?8:4)),"Ptr")   ;   16          12
    info.dwContextId    := numGet(0+(lphi+=A_PtrSize),"UPtr")           ;   24          16
    info.MousePos       := {}                                           ;
    info.MousePos.x     := numGet(0+(lphi+=A_PtrSize),"Int")            ;   32          20
    info.MousePos.y     := numGet(0+(lphi+=4),"Int")                    ;   36          24
    return info
}
*/
Hi @Seven0528, I did read the docs but due to my inexperience with programming, I could not understand it. Hence why I asked for an example.

I looked through your reply and the code seems very complicated. From what I understand from reading the Microsoft docs, I'm assuming your code can direct to different webpages when the help button is pressed in different situations (for example: different MsgBox popups).

Can you please talk me through what you code does? Thanks!

User avatar
Noitalommi_2
Posts: 278
Joined: 16 Aug 2023, 10:58

Re: How do I use the MsgBox "help" button

Post by Noitalommi_2 » 07 May 2024, 00:21

Jimmysan wrote:
06 May 2024, 07:41
Thanks @Noitalommi_2, the first code block works for me. Now I'm wondering, what does this do?

Code: Select all

g := Gui("+OwnDialogs")
This is the required GUI that receives the WM_HELP message. At least I think so. :mrgreen:

Here is an idea how you could handle multiple urls.
(I couldn't get it to work without re-registering the message. Maybe there is another way but this works for now.)

Code: Select all

#Requires AutoHotkey 2.0
#SingleInstance


ShowMsgBox("Press the Help button for further help.", "google", "https://www.google.com/")
ShowMsgBox("Press the Help button for further help.", "bing", "https://www.bing.com/")
ShowMsgBox("Press the Help button for further help.", "yahoo", "https://www.yahoo.com/")


ShowMsgBox(Text, Title, Url) {

    OnMessage(WM_HELP := 0x0053, RunUrl(*) => Run(Url))
    g := Gui("+OwnDialogs")
    MsgBox(Text, Title, 16384)
    g.Destroy(), OnMessage(WM_HELP, RunUrl, 0)
}

User avatar
Seven0528
Posts: 394
Joined: 23 Jan 2023, 04:52
Location: South Korea
Contact:

Re: How do I use the MsgBox "help" button

Post by Seven0528 » 07 May 2024, 01:16

 @Jimmysan

I apologize for not considering your situation. Sorry.
Next time, please provide more specific details about your own situation. As someone answering, there's no way to know if you're a novice or have some experience.
At least in this case, I didn't assume you were a beginner.
Before I begin, @Noitalommi_2's code is excellent on its own.
Initially, I aimed for a similarly concise response.
However, due to a slight delay, I couldn't respond earlier and since I was already crafting a response, I decided to adjust the direction towards a more specialized explanation.
After all, there's no need for identical responses, right?



The first code I provided is the most standard-like method.
Essentially, it monitors the WM_HELP message and extracts information from the lParam, which contains the address of the HELPINFO structure, whenever a message is received from the Gui window owning the MsgBox.
While the first code might seem complex at first glance, personally, I store the HELPINFO part in my personal library and #Include it, so writing that much code isn't often necessary. (The code is designed for reusability.) This approach is useful beyond just using WM_HELP for MsgBox's Help button; for instance, you might want to obtain the mouse coordinates at the time WM_HELP is received. You may also want to obtain the hWnd of the MsgBox itself.
Anyway, I've had occasions where I needed to use the HELPINFO structure frequently, and I prefer managing one message in one function, hence I tend to write it this way.

However, I admit, the first code I provided isn't particularly straightforward.
It was quite cumbersome to calculate the memory location to reference for obtaining the HELPINFO structure information each time.
Although I designed it to be easily reusable using the Class's Meta-Functions, it's not very straightforward. (This isn't a common practice, so to prevent confusion, I wrote down the traditional method of retrieving structure information from a specific memory address at the bottom as a comment.)



The second response was crafted to be more user-friendly.
It creates a temporary Gui and callback just before the MsgBox is created, enabling the MsgBox to receive WM_HELP messages, and removes the Gui and callback when the MsgBox is closed.

The complexity compared to Noitalommi_2's code arises from its actual complexity.
MsgBoxes can be invoked across multiple threads, up to a maximum of 7 simultaneously.
Providing different Help options for each MsgBox in such cases requires more complex code.
While I prefer handling this in one message callback, it requires prior information about the MsgBox and the Gui object associated with it, making dynamically assigning message callbacks challenging.
Thus, if each newly created MsgBox were to be assigned individual callbacks, the code would become even more complicated.
The order of callback creation alongside MsgBoxes for each thread, and the actual sequence of pressing the Help button, may vary, so in practice, the callback and its corresponding MsgBox should be designed to be mutually exclusive.
I didn't want to create a new Class instance every time to handle multiple threads, hence I used ObjBindMethod to tie the callback to the hRootWnd of the Gui, which has been preprocessed with +OwnDialogs.
However, even this isn't easily understandable code.
Last edited by Seven0528 on 09 May 2024, 15:29, edited 1 time in total.
  • English is not my native language. Please forgive any awkward expressions.
  • 영어는 제 모국어가 아닙니다. 어색한 표현이 있어도 양해해 주세요.

User avatar
Seven0528
Posts: 394
Joined: 23 Jan 2023, 04:52
Location: South Korea
Contact:

Re: How do I use the MsgBox "help" button

Post by Seven0528 » 07 May 2024, 01:45

Code: Select all

#Requires AutoHotkey v2.0
#SingleInstance Force


F2::ShowMsgBox("Press the Help button for further help.", "google", "https://www.google.com/")
F3::ShowMsgBox("Press the Help button for further help.", "bing", "https://www.bing.com/")
F4::ShowMsgBox("Press the Help button for further help.", "yahoo", "https://www.yahoo.com/")


ShowMsgBox(Text, Title, Url) {

    OnMessage(WM_HELP := 0x0053, RunUrl(*) => Run(Url))
    g := Gui("+OwnDialogs")
    MsgBox(Text, Title, 16384)
    g.Destroy(), OnMessage(WM_HELP, RunUrl, 0)
}
 @Noitalommi_2
If F2, F3, and F4 are pressed simultaneously, three callbacks are registered, and since it's not clear which Gui each callback is associated with,
pressing the Help button would open all three websites simultaneously.
This part caused me a lot of frustration yesterday. As for a solution...
Well, I can't think of anything other than pre-saving the hWnd of the Gui.

Code: Select all

#Requires AutoHotkey v2.0
#SingleInstance Force


F1::  {
    result := MessageBoxHelp.show("Press the Help button for further help.", "custom", 0x4000)
    setTimer tooltip, -1000 ;  Hide tooltip after 1 second.
    tooltip "result: " result
    switch (result)
    {
        case "OK":
            ;  TO DO
        case "Help":
            ;  TO DO
    }
}
F2::MessageBoxHelp.show("Press the Help button for further help.", "google" ,0x4000, runGoogleUrl, false)
F3::MessageBoxHelp.show("Press the Help button for further help.", "bing"   ,0x4000, (*)=>run("https://www.bing.com/"), false)
F4::MessageBoxHelp.show("Press the Help button for further help.", "yahoo"  ,0x4000, (*)=>run("https://www.yahoo.com/"))
runGoogleUrl()    {
    run("https://www.google.com/")
}


class MessageBoxHelp ;  ahk2.0
{
    static show(text?, title?, options:=0, callback:=-1, closeOnHelp:=true)    {
        static WM_HELP := 0x0053, MB_HELP := 0x00004000
        helpBtnExist := false
        for opt in strSplit(options,[A_Space,A_Tab])    {
            if (opt~="D)^(?:[[:digit:]]+|0[Xx][[:xdigit:]]+)$" && opt&MB_HELP)    {
                helpBtnExist := true
                break
            }
        }
        if (!helpBtnExist)
            return msgbox(text?, title?, options)
        tempGui := gui("+OwnDialogs"), this._results[hRootWnd:=tempGui.Hwnd] := ""
        objbm := objBindMethod(this,"_onHelp",hRootWnd,callback,closeOnHelp)    ,onMessage(WM_HELP, objbm, -1)
        result := msgbox(text?, title?, options)                                ,onMessage(WM_HELP, objbm, 0), objbm := ""
        result := (this._results[hRootWnd]?this._results[hRootWnd]:result)
        tempGui.destroy(), this._results.delete(hRootWnd)
        return result
    }
    static _results := map()
    static _onHelp(hRootWnd, callback, closeOnHelp, _, lphi, *)    {
        static WM_SYSCOMMAND := 0x0112, SC_CLOSE := 0xF060
        prevDHW := detectHiddenWindows(true)
        msgParentWindow := winExist(), detectHiddenWindows(prevDHW)
        if (msgParentWindow == hRootWnd)    {
            if (closeOnHelp)    {
                hItemHandle := numGet((lphi+(A_PtrSize==8?16:12)),"Ptr")
                hMenu := dllCall("User32.dll\GetSystemMenu", "Ptr",hItemHandle, "Int",false, "Ptr")
                lpmii := buffer(cbSize := (A_PtrSize==8?80:48), 0)
                if (dllCall("User32.dll\GetMenuItemInfoW", "Ptr",hMenu, "UInt",SC_CLOSE, "Int",false, "Ptr",lpmii.Ptr, "Int"))
                    dllCall("User32.dll\PostMessageW", "Ptr",hMenu, "UInt",WM_SYSCOMMAND, "UPtr",SC_CLOSE, "Ptr",0)
                else
                    controlSend("{Space}","Button1","ahk_id " hItemHandle)
                if (winWaitClose("ahk_id " hItemHandle,, 0.5))
                    this._results[hRootWnd] := "Help"
            }
            if (callback!==-1 && callback.hasMethod("call"))
                callback.call()
            return true
        }
    }
}
Please test the code I wrote above.
I think the idea of passing function objects as parameters to functions is great.
I've also adopted that idea in my code. Thank you.
Last edited by Seven0528 on 07 May 2024, 04:55, edited 10 times in total.
  • English is not my native language. Please forgive any awkward expressions.
  • 영어는 제 모국어가 아닙니다. 어색한 표현이 있어도 양해해 주세요.

User avatar
Noitalommi_2
Posts: 278
Joined: 16 Aug 2023, 10:58

Re: How do I use the MsgBox "help" button

Post by Noitalommi_2 » 07 May 2024, 02:06

@Seven0528

Thanks for the explanation and i find your script is quite useful, will put it into my code collection. :thumbup:

User avatar
Seven0528
Posts: 394
Joined: 23 Jan 2023, 04:52
Location: South Korea
Contact:

Re: How do I use the MsgBox "help" button

Post by Seven0528 » 07 May 2024, 03:11

 @Noitalommi_2
The code has been modified. Since not all cases include the SC_CLOSE menu, simply using WinClose alone cannot implement MsgBox termination.
I didn't intend to write the code so perfectly, but... I've modified the code to consider even this.
If you've added my code to the library, I recommend applying the new code. Thank you.
(I have also revised all the code used in the previously written responses.)
  • English is not my native language. Please forgive any awkward expressions.
  • 영어는 제 모국어가 아닙니다. 어색한 표현이 있어도 양해해 주세요.

Post Reply

Return to “Ask for Help (v2)”