MsgBox and WinMove

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
AmDeG 11
Posts: 388
Joined: 28 Nov 2013, 11:42

MsgBox and WinMove

22 Sep 2017, 09:45

how can I open a MsgBox at a specific area of my screen?

The following is NOT working

Code: Select all

#z::
MsgBox,,MEMO,Pray everyday
    Sleep 6000
    WinActivate MEMO
    WinMove MEMO,,1155,220,255,580
return
User avatar
FanaticGuru
Posts: 1906
Joined: 30 Sep 2013, 22:25

Re: MsgBox and WinMove

22 Sep 2017, 10:51

AmDeG 11 wrote:

Code: Select all

#z::
MsgBox,,MEMO,Pray everyday
    Sleep 6000
    WinActivate MEMO
    WinMove MEMO,,1155,220,255,580
return
The problem is that as soon as the code encounters the MsgBox the thread pauses while the message is open. Once you hit OK the thread continues and tries to move the box after it is closed.

The clunky way to fix this is to create a SetTimer to move the box before the thread is paused. The SetTimer then interrupts after a predetermined time and moves the message while it is displayed.

Code: Select all

SetTimer, Move_MsgBox, -50
MsgBox,,MEMO,Pray everyday

ExitApp

Move_MsgBox:
	WinActivate MEMO
	WinMove MEMO,,1155,220
return
You see the message box in the wrong place for a moment though before it is moved.

A cooler and more complicated way to handle this is to have AHK monitor events and detect when a message box is about to be displayed and move it before Windows displays it.

Code: Select all

MsgBox_XY(30,50, "Hello")
MsgBoxOpt_XY(100,100,,"MEMO","Pray everyday")

MsgBox_XY(X, Y, Text:="")
{
	global MsgBox_X := X, MsgBox_Y := Y	; Make global for other function
	OnMessage(0x44, "Move_MsgBox")	; When a dialog appears run Move_MsgBox
	MsgBox, % Text
	OnMessage(0x44, "")				; When a dialog appears do nothing special
}

MsgBoxOpt_XY(X, Y, Options:="", Title:="", Text:="", Timeout:="")
{
	global MsgBox_X := X, MsgBox_Y := Y	; Make global for other function
	OnMessage(0x44, "Move_MsgBox")	; When a dialog appears run Move_MsgBox
	MsgBox, % Options, % Title, % Text, % Timeout
	OnMessage(0x44, "")				; When a dialog appears do nothing special
}

Move_MsgBox(P)
{
	global MsgBox_X, MsgBox_Y 		; Have to be global to get value set in other function
	if (P = 1027) 					; Make sure it is a AHK dialog
	{
		Process, Exist	; Get the Process PID into ErrorLevel
		DetectHiddenWindows, % (Setting_A_DetectHiddenWindows := A_DetectHiddenWindows) ? "On" :	; Round about way of changing DetectHiddenWindows settting and saving the setting all in one line
		if WinExist("ahk_class #32770 ahk_pid " ErrorLevel)	; Make sure dialog still exist
			WinMove, MsgBox_X, MsgBox_Y	; Move the default window from above WinExist
		DetectHiddenWindows, %Setting_A_DetectHiddenWindows%	; Set the DetectHiddenWindows setting back to what it was before function changed it
	}
}
There are separate functions for when you just want a default message box and another for when you want a message box with all the options.

FG
Hotkey Help - Help Dialog for Currently Running AHK Scripts
AHK Startup - Consolidate Multiply AHK Scripts with one Tray Icon
Hotstring Manager - Create and Manage Hotstrings
[Class] WinHook - Create Window Shell Hooks and Window Event Hooks
AmDeG 11
Posts: 388
Joined: 28 Nov 2013, 11:42

Re: MsgBox and WinMove

22 Sep 2017, 12:10

wow! never thought it was going to be so complicated!
Is that going to affect others MsgBoxes? I don't want that.

Also at your script where should I add my position desired which is 1155,220,255,580 ?
User avatar
boiler
Posts: 16768
Joined: 21 Dec 2014, 02:44

Re: MsgBox and WinMove

22 Sep 2017, 12:46

In his first approach, he put a negative number on the SetTimer period, which means it only occurs once and will not affect subsequent MsgBoxes.
AmDeG 11
Posts: 388
Joined: 28 Nov 2013, 11:42

Re: MsgBox and WinMove

22 Sep 2017, 13:34

ok, I was able to make it open at the area of my screen desired

however is it possible to avoid the first dialog ("Hello") and go directly there?

so far I see first the "Hello" dialog and then after pressing Return I get to my desired Message
GEV
Posts: 1002
Joined: 25 Feb 2014, 00:50

Re: MsgBox and WinMove

22 Sep 2017, 14:06

Just remove the first line.
AmDeG 11
Posts: 388
Joined: 28 Nov 2013, 11:42

Re: MsgBox and WinMove

22 Sep 2017, 15:14

perfect!
a related question: can I use the simple "structure" for an InputBox ?
teadrinker
Posts: 4309
Joined: 29 Mar 2015, 09:41
Contact:

Re: MsgBox and WinMove

22 Sep 2017, 18:20

One more example. Just add the function CBTProc() to your script, and then set coordinates of MsgBox like in the code below, if you need.

Code: Select all

MsgBox, This MessageBox will appear in the centre of screen, as usual
MsgBox,, |x50 y70, This MessageBox will appear in coords x = 50 y = 70 without a title.
MsgBox,, Hello!|x500 y0, This MessageBox will appear in coords x = 500 y = 0 with the title "Hello!"
Return

CBTProc(nCode, wp, lp)  {
   static HCBT_CREATEWND := 3, WH_CBT := 5
        , hHook := DllCall("SetWindowsHookEx", Int, WH_CBT
                                             , Ptr, RegisterCallback("CBTProc", "Fast")
                                             , Ptr, 0
                                             , UInt, DllCall("GetCurrentThreadId") , Ptr)
   if (nCode = HCBT_CREATEWND)  {
      VarSetCapacity(WinClass, 256)
      DllCall("GetClassName", Ptr, hwnd := wp, Str, WinClass, Int, 256)
      if (WinClass != "#32770")
         Return
      
      pCREATESTRUCT := NumGet(lp+0)
      sTitle := StrGet( pTitle := NumGet(pCREATESTRUCT + A_PtrSize * 5 + 4 * 4), "UTF-16" )
      RegExMatch(sTitle, "^(.*)\|(?:x(\d+)\s?)?(?:y(\d+))?$", match)
      ( !(match2 = "" && match3 = "") && StrPut(match1, pTitle, "UTF-16") )
      ( match2 != "" && NumPut(match2, pCREATESTRUCT + A_PtrSize * 4 + 4 * 3, "Int") )
      ( match3 != "" && NumPut(match3, pCREATESTRUCT + A_PtrSize * 4 + 4 * 2, "Int") )
   }
}
User avatar
FanaticGuru
Posts: 1906
Joined: 30 Sep 2013, 22:25

Re: MsgBox and WinMove

25 Sep 2017, 13:18

teadrinker wrote:One more example. Just add the function CBTProc() to your script, and then set coordinates of MsgBox like in the code below, if you need.

Code: Select all

MsgBox, This MessageBox will appear in the centre of screen, as usual
MsgBox,, |x50 y70, This MessageBox will appear in coords x = 50 y = 70 without a title.
MsgBox,, Hello!|x500 y0, This MessageBox will appear in coords x = 500 y = 0 with the title "Hello!"
Return

CBTProc(nCode, wp, lp)  {
   static HCBT_CREATEWND := 3, WH_CBT := 5
        , hHook := DllCall("SetWindowsHookEx", Int, WH_CBT
                                             , Ptr, RegisterCallback("CBTProc", "Fast")
                                             , Ptr, 0
                                             , UInt, DllCall("GetCurrentThreadId") , Ptr)
   if (nCode = HCBT_CREATEWND)  {
      VarSetCapacity(WinClass, 256)
      DllCall("GetClassName", Ptr, hwnd := wp, Str, WinClass, Int, 256)
      if (WinClass != "#32770")
         Return
      
      pCREATESTRUCT := NumGet(lp+0)
      sTitle := StrGet( pTitle := NumGet(pCREATESTRUCT + A_PtrSize * 5 + 4 * 4), "UTF-16" )
      RegExMatch(sTitle, "^(.*)\|(?:x(\d+)\s?)?(?:y(\d+))?$", match)
      ( !(match2 = "" && match3 = "") && StrPut(match1, pTitle, "UTF-16") )
      ( match2 != "" && NumPut(match2, pCREATESTRUCT + A_PtrSize * 4 + 4 * 3, "Int") )
      ( match3 != "" && NumPut(match3, pCREATESTRUCT + A_PtrSize * 4 + 4 * 2, "Int") )
   }
}
Yea, you could do it this way if you don't mind limiting perfectly valid message box titles.

I am totally kidding. This is REALLY cool code. It has initializing a hook through a static variable at load time, registering a call back through a DLLCall, a cryptic RegEx needle, and best of all a bunch of magic numbers to manipulate a message box's structure in memory. Nice!

Makes my OnMessage trick look like crayon code suitable for putting on the refrigerator door with a smiley face sticker.

FG
Hotkey Help - Help Dialog for Currently Running AHK Scripts
AHK Startup - Consolidate Multiply AHK Scripts with one Tray Icon
Hotstring Manager - Create and Manage Hotstrings
[Class] WinHook - Create Window Shell Hooks and Window Event Hooks
AmDeG 11
Posts: 388
Joined: 28 Nov 2013, 11:42

Re: MsgBox and WinMove

25 Sep 2017, 13:26

sorry, you are the experts I'm a layperson. Is it better to follow teadrinker code instead of FanatiGuru or teadrinker code could affect other MsgBoxes at other scripts?

Also any clue if I could apply this to InputBoxes?
User avatar
boiler
Posts: 16768
Joined: 21 Dec 2014, 02:44

Re: MsgBox and WinMove

25 Sep 2017, 13:39

InputBox lets you specify the size and position, unlike MsgBox, so you don't really need to apply this to them.
User avatar
FanaticGuru
Posts: 1906
Joined: 30 Sep 2013, 22:25

Re: MsgBox and WinMove

25 Sep 2017, 14:01

AmDeG 11 wrote:sorry, you are the experts I'm a layperson. Is it better to follow teadrinker code instead of FanatiGuru or teadrinker code could affect other MsgBoxes at other scripts?
teadrinker's code is probably better. It is simpler to use. You put their function in your script and all MsgBox commands in that script will behave as normal unless you put coordinates in the format of |x10 y20 at the end of the title for the message box.

They are using some fancy code to allow you to slip another parameter into the MsgBox command that will be looked for any time a message box is being created. If the extra information is found in the title it is used to set the position of the message box.

FG
Hotkey Help - Help Dialog for Currently Running AHK Scripts
AHK Startup - Consolidate Multiply AHK Scripts with one Tray Icon
Hotstring Manager - Create and Manage Hotstrings
[Class] WinHook - Create Window Shell Hooks and Window Event Hooks
teadrinker
Posts: 4309
Joined: 29 Mar 2015, 09:41
Contact:

Re: MsgBox and WinMove

25 Sep 2017, 18:45

FanaticGuru, thanks for your feedback! :)
AmDeG 11
Posts: 388
Joined: 28 Nov 2013, 11:42

Re: MsgBox and WinMove

25 Sep 2017, 23:14

both of you are great!! an example of charity and I commend FanaticGuru humility. things we need more in this world... more than scripts... :)
teadrinker
Posts: 4309
Joined: 29 Mar 2015, 09:41
Contact:

Re: MsgBox and WinMove

25 Sep 2017, 23:22

Made some changes to the code:

Code: Select all

MsgBox, This MessageBox will appear in the centre of screen, as usual
MsgBox,, |x50 y70, This MessageBox will appear in coords x = 50 y = 70 without a title.
MsgBox,, Hello!|x500 y0, This MessageBox will appear in coords x = 500 y = 0 with the title "Hello!"
Return

CBTProc(nCode, wp, lp)  {
   static WH_CBT := 5, HCBT_CREATEWND := 3
        , dummy := OnExit( Func("CBTProc").Bind("OnExit") )
        , hHook := DllCall("SetWindowsHookEx", Int, WH_CBT
                                             , Ptr, RegisterCallback("CBTProc", "Fast")
                                             , Ptr, 0
                                             , UInt, DllCall("GetCurrentThreadId") , Ptr)
   if (nCode = "OnExit")  {
      DllCall("UnhookWindowsHookEx", Ptr, hHook)
      return
   }
   if (nCode = HCBT_CREATEWND)  {
      VarSetCapacity(WinClass, 256)
      DllCall("GetClassName", Ptr, hwnd := wp, Str, WinClass, Int, 256)
      if (WinClass = "#32770")  {
         pCREATESTRUCT := NumGet(lp+0)
         sTitle := StrGet( pTitle := NumGet(pCREATESTRUCT + A_PtrSize * 5 + 4 * 4), "UTF-16" )
         RegExMatch(sTitle, "^(.*)\|(?:x(\d+)\s?)?(?:y(\d+))?$", match)
         ( !(match2 = "" && match3 = "") && StrPut(match1, pTitle, "UTF-16") )
         ( match2 != "" && NumPut(match2, pCREATESTRUCT + A_PtrSize * 4 + 4 * 3, "Int") )
         ( match3 != "" && NumPut(match3, pCREATESTRUCT + A_PtrSize * 4 + 4 * 2, "Int") )
      }
   }
   Return DllCall("CallNextHookEx", Ptr, 0, Int, nCode, Ptr, wp, Ptr, lp)
}
User avatar
Delta Pythagorean
Posts: 627
Joined: 13 Feb 2017, 13:44
Location: Somewhere in the US
Contact:

Re: MsgBox and WinMove

26 Sep 2017, 08:47

Just use a SetTimer to move it.

Code: Select all

SetTimer, Label, -1
MsgBox, Stuffs
Return

Label:
WinWaitActive, MsgTitle
WinMove, A position you want
Return

[AHK]......: v2.0.12 | 64-bit
[OS].......: Windows 11 | 23H2 (OS Build: 22621.3296)
[GITHUB]...: github.com/DelPyth
[PAYPAL]...: paypal.me/DelPyth
[DISCORD]..: tophatcat

AmDeG 11
Posts: 388
Joined: 28 Nov 2013, 11:42

Re: MsgBox and WinMove

22 Jan 2018, 10:36

@teadrinker
sorry for my very late comment. But I cannot move the MsgBox
it is not working this: |x500 y0

according to your comment

;MsgBox,, Hello!|x500 y0, This MessageBox will appear in coords x = 500 y = 0 with the title "Hello!"
teadrinker
Posts: 4309
Joined: 29 Mar 2015, 09:41
Contact:

Re: MsgBox and WinMove

22 Jan 2018, 10:58

AmDeG 11 wrote:it is not working this: |x500 y0
Can you show your full code?
AmDeG 11
Posts: 388
Joined: 28 Nov 2013, 11:42

Re: MsgBox and WinMove

22 Jan 2018, 11:10

Code: Select all

NumpadUp::
     ;MsgBox, This MessageBox will appear in the centre of  screen, as usual
     ;MsgBox,, |x50 y70, This MessageBox will appear in coords x = 50 y = 70 without a title.
     ;MsgBox,, Hello!|x500 y0, This MessageBox will appear in coords x = 500 y = 0 with the title  "Hello!"
MsgBox,, |x50 y70, RAlt-LWin Taskbar hide/unhide`n`n  +^ESC  TaskManager`n    +^F1   Programs&Features
Return
CBTProc(nCode, wp, lp)  {
   static WH_CBT := 5, HCBT_CREATEWND := 3
        , dummy := OnExit( Func("CBTProc").Bind("OnExit") )
        , hHook := DllCall("SetWindowsHookEx", Int, WH_CBT
                                             , Ptr, RegisterCallback("CBTProc", "Fast")
                                             , Ptr, 0
                                             , UInt, DllCall("GetCurrentThreadId") , Ptr)
   if (nCode = "OnExit")  {
      DllCall("UnhookWindowsHookEx", Ptr, hHook)
      return
   }
   if (nCode = HCBT_CREATEWND)  {                                                                                                                                                                                                                                               
      VarSetCapacity(WinClass, 256)
      DllCall("GetClassName", Ptr, hwnd := wp, Str, WinClas vs, Int, 256)
      if (WinClass = "#32770")  {
         pCREATESTRUCT := NumGet(lp+0)
         sTitle := StrGet( pTitle := NumGet(pCREATESTRUCT + A_PtrSize * 5 + 4 * 4), "UTF-16" )
         RegExMatch(sTitle, "^(.*)\|(?:x(\d+)\s?)?(?:y(\d+))?$", match)
         ( !(match2 = "" && match3 = "") && StrPut(match1, pTitle, "UTF-16") )
         ( match2 != "" && NumPut(match2, pCREATESTRUCT + A_PtrSize * 4 + 4 * 3, "Int") )
         ( match3 != "" && NumPut(match3, pCREATESTRUCT + A_PtrSize * 4 + 4 * 2, "Int") )
      }
   }
   Return DllCall("CallNextHookEx", Ptr, 0, Int, nCode, Ptr, wp, Ptr, lp)
}
teadrinker
Posts: 4309
Joined: 29 Mar 2015, 09:41
Contact:

Re: MsgBox and WinMove

22 Jan 2018, 12:06

You copied my function incorrectly:
DllCall("GetClassName", Ptr, hwnd := wp, Str, WinClas vs, Int, 256)

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: catquas, Google [Bot], mikeyww, mmflume, Ralf_Reddings200244, sofista, thelegend and 150 guests