Sometimes a MsgBox Window Just Pops Up in the Wrong Place—Here’s How to Relocate It
I’ve experienced this problem a couple of times. I use the MsgBox command to display script information at specific spots in a script. If in the modal mode (always-on-top), the pop-up window obscures my view of the window underneath it. I want the MsgBox to open elsewhere on the screen but AutoHotkey MsgBox command does not provide options for placing the window at an alternative location.
The WinMove command can relocate the MsgBox window, but only after the window exists. Since the MsgBox command stops the processing of the current thread, inserting the WinMove command after the MsgBox command doesn’t work. AutoHotkey won’t run the command until after closing the MsgBox window. I need a way to initiate a separate processing thread which relocates the MsgBox window after it comes to life—without closing the MsgBox window.
AutoHotkey can run multiple processes (threads) simultaneously in the same script. While scripts run commands serially (one at a time) in order from beginning to end, a few commands can initiate new threads which run independently from other processes. From the AutoHotkey online documentation:
The current thread is defined as the flow of execution invoked by the most recent event; examples include Hotkeys, SetTimer subroutines, custom menu items, and GUI events. The current thread can be executing commands within its own subroutine or within other subroutines called by that subroutine.
The events listed above allow you to write scripts which can do more than one thing at a time.
Note from the AutoHotkey online documentation:
Although AutoHotkey doesn’t actually use multiple threads, it simulates some of that behavior: If a second thread is started — such as by pressing another hotkey while the previous is still running — the current thread will be interrupted (temporarily halted) to allow the new thread to become current. If a third thread is started while the second is still running, both the second and first will be in a dormant state, and so on.
You could relocate the active window by creating a Hotkey which executes the WinMove command, but, by inserting the SetTimer command, you can automate the movement of the MsgBox window after it opens.
By scheduling a new thread using the SetTimer command prior to opening the script-pausing MsgBox command, you can move the windows after it appears. I discuss this technique when modifying buttons inside a MsgBox in the section “Changing Message Box Button Names” in the chapter “13.1.5 Tips for Optimizing the Standard AutoHotkey Message Box (MsgBox) Command” of the book Jack’s Motley Assortment of AutoHotkey Tips.
Using the SetTimer Command to Move a MsgBox
You can find this MsgBox moving tip at a couple of places in the AutoHotkey forums.
SetTimer, WinMoveMsgBox, 50 MsgBox, 4096, Title, Text ExitApp Return WinMoveMsgBox: SetTimer, WinMoveMsgBox, OFF WinMove, Title, , 50, 50 Return
Prior to AutoHotkey opening the MsgBox, the SetTimer command initiates a new thread which calls the WinMoveMsgBox subroutine. Hopefully, after the MsgBox window activates, the WinMoveMsgBox subroutine turns off the Timer and moves the MsgBox window using the WinMove command to the coordinates 50,50 on the screen.
I say, “hopefully,” because this technique works great as long as the MsgBox window opens before the WinMoveMsgBox subroutine executes. Otherwise, the MsgBox does not move. (You can test this concept by placing the Sleep command for 100 milliseconds—Sleep 100—after the SetTimer command. The MsgBox window will not move.)
Increasing WinMoveMsgBox Subroutine Reliability
We could increase the wait time in the SetTimer command to allow for any possible slow-loading MsgBox commands, but that doesn’t seal the deal for unexpected CPU delays. We need a method which guarantees the execution of the WinMoveMsgBox subroutine only after the MsgBox window comes into existence. To prevent the script from missing its opportunity to move the MsgBox window, we add a check to the WinMoveMsgBox subroutine.
Fortunately, by default, the SetTimer command repeatedly runs the WinMoveMsgBox subroutine every 50 milliseconds until the script turns the Timer off. By checking for the existence of the window, the AutoHotkey waits until the window pops open to turn off the Timer:
SetTimer, WinMoveMsgBox, 50 Sleep 100 MsgBox, 4096, Title, Text ExitApp Return WinMoveMsgBox: If WinExist("Title") SetTimer, WinMoveMsgBox, OFF WinMove, Title, , 50, 50 Return
This one conditional using the WinExist() function forces the WinMoveMsgBox subroutine to rerun every 50 milliseconds until the MsgBox window activates.
Changing MsgBox Window Names
If you want to change the title of the MsgBox window, you can add a variable containing the new window title:
WinName := "Title" SetTimer, WinMoveMsgBox, 50 Sleep 100 MsgBox, 4096, %WinName%, Text ExitApp Return WinMoveMsgBox: If WinExist(WinName) SetTimer, WinMoveMsgBox, OFF WinMove, %WinName%, , 50, 50 Return
Add this SetTimer command technique to you AutoHotkey toolkit. It can help you fill in the gaps when you need to make changes after-the-fact.
Click the Follow button at the top of the sidebar on the right of this page for e-mail notification of new blogs. (If you’re reading this on a tablet or your phone, then you must scroll all the way to the end of the blog—pass any comments—to find the Follow button.)
This post was proofread by Grammarly
(Any other mistakes are all mine.)
(Full disclosure: If you sign up for a free Grammarly account, I get 20¢. I use the spelling/grammar checking service all the time, but, then again, I write a lot more than most people. I recommend Grammarly because it works and it’s free.)