Getting a GUI to move with another window?

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
AtleastItried
Posts: 51
Joined: 03 Mar 2017, 04:51

Getting a GUI to move with another window?

30 Apr 2018, 15:18

I want to put my GUI ontop of another window and rest it there. I have found this code:

Code: Select all

#NoEnv
#NoTrayIcon
#Persistent
#SingleInstance, Off
SetWinDelay, 0
SendMode Input
SetBatchLines, -1
SetTitleMatchMode, 2


;; Get ID of Notepad
WinGet, WinID, ID, ahk_class Notepad,,,
SetTimer, ShowGui, 500

	ShowGui:	
WinWait, ahk_class Notepad
WinGetPos, X, Y,,, ahk_class Notepad
WinGet, WinID, ID, ahk_class Notepad,,,
IfWinNotExist, ahk_class AutohotkeyGUI
{
Gui, +Owner%WinID% +Border +ToolWindow 
Gui, Show, NoActivate x%X% y%Y% w51 h431, %GuiTitle%
}
else
{
WinGetPos, Xgui, , , ,  ahk_class AutohotkeyGUI
	If Xgui<>X - 56
	WinMove, ahk_class AutohotkeyGUI,  X - 56
}
return
But It's really choppy and I would honestly prefer something that works A LOT better. Ideally it should look like it exists natively in the window.
A_AhkUser
Posts: 1147
Joined: 06 Mar 2017, 16:18
Location: France
Contact:

Re: Getting a GUI to move with another window?

30 Apr 2018, 17:45

Hi AtleastItried,

Here's a commented example. It registers an event hook function for an event which is sent when, in particular, the window has changed location, shape, or size:

Code: Select all

#NoEnv
#SingleInstance force
SetWorkingDir % A_ScriptDir
SendMode, Input

SetWinDelay, -1


WinWaitActive, ahk_class Notepad
WinGet, PID, PID, % "ahk_id " . owner:=WinExist() ; if all parameters are omitted, WinExist returns the ID the Last Found Window if it still exist; WInWait set the Last Found Window
GUI, +ToolWindow +Owner%owner% +Hwndowned
/*
+ToolWindow > no taskbar button
+Owner%owner% > make the GUI owned by the window whose ID is the one stored in the variable 'owner'
+Hwndowned > stores the ID of the GUI in 'owned'
*/
global ownerAhkId := "ahk_id " . owner, ownedAhkId := "ahk_id " . owned
GUI, Show, w100 h300
hWinEventHook := SetWinEventHook("0x800B", "0x800B", 0, RegisterCallback("OnLocationChangeMonitor"), PID, 0, 0) ; register a event hook function for EVENT_OBJECT_LOCATIONCHANGE := "0x800B"
OnLocationChangeMonitor(0, 0, 1)
OnExit, handleExit ; specifies a subroutine or callback function to run automatically when the script exits...
WinWaitClose % ownerAhkId ; ... or until the owner window does not exist
handleExit:
UnhookWinEvent(hWinEventHook) ; removes the event hook function created by SetWinEventHook before exiting the script
ExitApp



OnLocationChangeMonitor(_hWinEventHook, _event, _hwnd) { ; https://msdn.microsoft.com/en-us/library/windows/desktop/dd373885(v=vs.85).aspx
	_listLines := A_ListLines
	ListLines, Off
		if not (_hwnd) ; if the system sent the EVENT_OBJECT_LOCATIONCHANGE event for the caret: https://msdn.microsoft.com/en-us/library/windows/desktop/dd318066(v=vs.85).aspx
			return
		WinGetPos, _x, _y,,, % ownerAhkId
		WinMove, % ownedAhkId,, % _x, % _y ; set the position of the window owned by owner
	ListLines % _listLines ? "On" : "Off"
}



SetWinEventHook(_eventMin, _eventMax, _hmodWinEventProc, _lpfnWinEventProc, _idProcess, _idThread, _dwFlags) {
   DllCall("CoInitialize", "Uint", 0)
   return DllCall("SetWinEventHook"
			, "Uint", _eventMin
			, "Uint", _eventMax
			, "Ptr", _hmodWinEventProc
			, "Ptr", _lpfnWinEventProc
			, "Uint", _idProcess
			, "Uint", _idThread
			, "Uint", _dwFlags)
} ; cf. https://autohotkey.com/boards/viewtopic.php?t=830
UnhookWinEvent(_hWinEventHook) {
    _v := DllCall("UnhookWinEvent", "Ptr", _hWinEventHook)
    DllCall("CoUninitialize")
return _v
} ;  cf. https://autohotkey.com/boards/viewtopic.php?t=830
my scripts
art
Posts: 22
Joined: 01 Jan 2014, 05:56

Re: Getting a GUI to move with another window?

02 May 2018, 02:54

Thank you very much A_AhkUser for your example!

If you don't mind, i change it a little for my needs:
- more compact
- less global vars
- if you manually re-position the owned window over the owner, it remembers and new relationship.

Code: Select all


#NoEnv
#SingleInstance force
SetWinDelay, -1

run notepad.exe
WinWaitActive, ahk_class Notepad
WinGet, PID, PID, % "ahk_id " . owner:=WinExist() ; if all parameters are omitted, WinExist returns the ID the Last Found Window if it still exist; WInWait set the Last Found Window

GUI, +ToolWindow +Owner%owner% +Hwndowned
GUI, Show, w100 h300

OnLocationChangeMonitor(owner, owned, PID) ; INIT

WinWaitClose % "ahk_id " . owner ; ... or until the owner window does not exist
ExitApp


OnLocationChangeMonitor(_hWinEventHook, _event, _hwnd) { ; https://msdn.microsoft.com/en-us/library/windows/desktop/dd373885(v=vs.85).aspx
	STATIC ox, oy, nx, ny, ownerAhkId, ownedAhkId, hWinEventHook
	IF !_hwnd	; if the system sent the EVENT_OBJECT_LOCATIONCHANGE event for the caret:
		Return	; https://msdn.microsoft.com/en-us/library/windows/desktop/dd318066(v=vs.85).aspx
	IF !hWinEventHook			; register a event hook function for EVENT_OBJECT_LOCATIONCHANGE := "0x800B"
		hWinEventHook := SetWinEventHook("0x800B", "0x800B",0, RegisterCallback("OnLocationChangeMonitor"),_hwnd,0,0)
		 , ownerAhkId := _hWinEventHook,   ownedAhkId := _event,   OnExit(Func("UnhookWinEvent").Bind(hWinEventHook))
	WinGetPos,  _x,  _y,,, ahk_id %ownerAhkId%
	WinGetPos, _x1, _y1,,, ahk_id %ownedAhkId%
	IF (_x1!=ox || _y1!=oy)
		nx:=_x-_x1, ny:=_y-_y1
	WinMove, ahk_id %ownedAhkId%,, % ox:=_x-nx, % oy:=_y-ny ; set the position of the window owned by owner
}

SetWinEventHook(_eventMin, _eventMax, _hmodWinEventProc, _lpfnWinEventProc, _idProcess, _idThread, _dwFlags) {
   DllCall("CoInitialize", "Uint", 0)
   return DllCall("SetWinEventHook","Uint",_eventMin,"Uint",_eventMax,"Ptr",_hmodWinEventProc,"Ptr",_lpfnWinEventProc,"Uint",_idProcess,"Uint",_idThread,"Uint",_dwFlags)
}  ; cf. https://autohotkey.com/boards/viewtopic.php?t=830
UnhookWinEvent(_hWinEventHook) {
   DllCall("UnhookWinEvent", "Ptr", _hWinEventHook)
   DllCall("CoUninitialize")
}  ; cf. https://autohotkey.com/boards/viewtopic.php?t=830

User avatar
FanaticGuru
Posts: 1908
Joined: 30 Sep 2013, 22:25

Re: Getting a GUI to move with another window?

02 May 2018, 18:13

AtleastItried wrote:I want to put my GUI ontop of another window and rest it there. ...
Ideally it should look like it exists natively in the window.
You might want to make the GUI a child window of a parent window.

Here is an example using Excel.

Code: Select all

Win_Hwnd := WinExist("ahk_exe excel.exe ahk_class XLMAIN")

; Gui Create
Gui, Color, Green
Gui, Font, s12 cRed, Bold Verdana
Gui, Add, Text,, This is Text
Gui, +LastFound +ToolWindow +AlwaysOnTop -Caption -Border HWNDGui_Hwnd
DllCall("SetParent", "uint", Gui_Hwnd, "uint", Win_Hwnd)
Gui, Show, x200 y200 ; Position on Gui Parent
return

Esc::ExitApp
I use this technique to add buttons to other programs. I have one program that I monitor for with a hook and any time it is opened a button is automatically added to the top of the window's titlebar where there is some blank space that allows me to run a AHK script. It is like adding a custom toolbar that goes beyond the capabilities of the program.

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
User avatar
Hellbent
Posts: 2114
Joined: 23 Sep 2017, 13:34

Re: Getting a GUI to move with another window?

02 May 2018, 23:50

FanaticGuru wrote:I have one program that I monitor for with a hook and any time it is opened
I haven't bothered looking at anything to do with "hooks", thought they had to do with keyboard keys or some other thing i'm not interested in.
The way you said the line I quoted suggests something other than something to do with a keyboard. Can you give some details on this?
truekefir
Posts: 17
Joined: 29 Jul 2017, 13:57

Re: Getting a GUI to move with another window?

03 May 2018, 11:30

FanaticGuru wrote:
AtleastItried wrote: Win_Hwnd := WinExist("ahk_exe excel.exe ahk_class XLMAIN")
DllCall("SetParent", "uint", Gui_Hwnd, "uint", Win_Hwnd)
is there difference between
DllCall("SetParent", "uint", Gui_Hwnd, "uint", Win_Hwnd)
and
Gui, +LastFound +ToolWindow +AlwaysOnTop -Caption -Border +parent%Win_Hwnd% HWNDGui_Hwnd
?
User avatar
FanaticGuru
Posts: 1908
Joined: 30 Sep 2013, 22:25

Re: Getting a GUI to move with another window?

03 May 2018, 12:34

truekefir wrote:
FanaticGuru wrote:
AtleastItried wrote: Win_Hwnd := WinExist("ahk_exe excel.exe ahk_class XLMAIN")
DllCall("SetParent", "uint", Gui_Hwnd, "uint", Win_Hwnd)
is there difference between
DllCall("SetParent", "uint", Gui_Hwnd, "uint", Win_Hwnd)
and
Gui, +LastFound +ToolWindow +AlwaysOnTop -Caption -Border +parent%Win_Hwnd% HWNDGui_Hwnd
?
I don't believe there is any difference. The DllCall is just an artifact from my library of examples from the time before +Parent was impliminted.

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
User avatar
FanaticGuru
Posts: 1908
Joined: 30 Sep 2013, 22:25

Re: Getting a GUI to move with another window?

03 May 2018, 13:06

Hellbent wrote:
FanaticGuru wrote:I have one program that I monitor for with a hook and any time it is opened
I haven't bothered looking at anything to do with "hooks", thought they had to do with keyboard keys or some other thing i'm not interested in.
The way you said the line I quoted suggests something other than something to do with a keyboard. Can you give some details on this?
Here is an example of a ShellHook to detect when Notepad is opened.

Code: Select all

; Sets up the hook to tell Windows to run ShellMessage function in this script when a Shell Hook event occurs
DllCall( "RegisterShellHookWindow", UInt, A_ScriptHwnd )
MsgNum := DllCall( "RegisterWindowMessage", Str,"SHELLHOOK" )
OnMessage( MsgNum, "ShellMessage" )
Return

ShellMessage( wParam,lParam )	; Gets all Shell Hook Messages
{
	If ( wParam = 1 ) ;  HSHELL_WINDOWCREATED := 1 ; Only act on Window Created Messages
	{
		wId:= lParam							; wID is Window Handle
		WinGetTitle, wTitle, ahk_id %wId%		; wTitle is Window Title
		WinGetClass, wClass, ahk_id %wId%		; wClass is Window Class
		WinGet, wExe, ProcessName, ahk_id %wId%	; wExe is Window Execute
		if (wClass = "Notepad")					; Only act on the specific Window
			DisableCloseButton(wId)
	}
}

; Skan (https://autohotkey.com/board/topic/80593-how-to-disable-grey-out-the-close-button/)
DisableCloseButton(hWnd) 
{
	hSysMenu:=DllCall("GetSystemMenu","Int",hWnd,"Int",FALSE)
	nCnt:=DllCall("GetMenuItemCount","Int",hSysMenu)
	DllCall("RemoveMenu","Int",hSysMenu,"UInt",nCnt-1,"Uint","0x400")
	DllCall("RemoveMenu","Int",hSysMenu,"UInt",nCnt-2,"Uint","0x400")
	DllCall("DrawMenuBar","Int",hWnd)
}
While this script is running, any time a shell message event occurs (lots of things having to do with windows cause this) the ShellMessage function is run. It checks to see if the message is that a window has just been created, then it checks if it was Notepad, if so it runs the DisableCloseButton function which disables the X close button in the top right corner of the window.

This is only using the wClass to filter but the example includes how to get lots of info about the window that triggered the event even though all that info is not used in this example.

You could monitor for lots of different events and filter just to act on certain events or windows.

SetWinEventHook is another hook that can be used to detect lots of useful events. It is setup a little differently but behaves similar. Should be able to google examples of how to do in AHK.

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
User avatar
Hellbent
Posts: 2114
Joined: 23 Sep 2017, 13:34

Re: Getting a GUI to move with another window?

04 May 2018, 21:23

FanaticGuru wrote:Stuff
Thanks, i'll have a look over this sometime this weekend.
truekefir
Posts: 17
Joined: 29 Jul 2017, 13:57

Re: Getting a GUI to move with another window?

06 May 2018, 12:26

FanaticGuru wrote: Here is an example of a ShellHook to detect when Notepad is opened.

I tried to use this but it appears that sometimes it misses if window was opened. I think it happens when I open different windows close to each other.
I'm using all of your script except DisableCloseButton() function, I have Gosub, Label. Then I have wId set as global, subroutine starts with reassignment of wID to another var to keep it and does various manipulations with specific windows like change size, remove titlebar, move, set region, add overlay with close button etc, but while the subroutine is in process another ShellMessage() function wouldn't start on new window. I guess I can make 2 AHK one for solely making a list of started apps to make a queue, and 2nd for processing that list, or there is a better solution?
User avatar
FanaticGuru
Posts: 1908
Joined: 30 Sep 2013, 22:25

Re: Getting a GUI to move with another window?

07 May 2018, 12:36

truekefir wrote: I tried to use this but it appears that sometimes it misses if window was opened. I think it happens when I open different windows close to each other.
I'm using all of your script except DisableCloseButton() function, I have Gosub, Label. Then I have wId set as global, subroutine starts with reassignment of wID to another var to keep it and does various manipulations with specific windows like change size, remove titlebar, move, set region, add overlay with close button etc, but while the subroutine is in process another ShellMessage() function wouldn't start on new window. I guess I can make 2 AHK one for solely making a list of started apps to make a queue, and 2nd for processing that list, or there is a better solution?
Yes, you will have problems if the script triggers a new message before whatever processing has finished on the previous message.

OnMessage by default can only create one thread at a time, meaning that while one is processing all others are ignored.

OnMessage has an option to increase the number of threads so that one OnMessage can interrupt another, then they will be done backwards off the stack. Each interrupt able to jump to the first in line. Meaning the second one will finish then jump control back to the first one. This might be desirable, might not.

Another option is to put Critical at top of script. This makes the thread uninterruptable in most cases but the interrupts are buffered and done in order as each finishes.

Between these two options you should be able to get the result you want. You need to be aware of what is going on with your global variables and such. Critical is probably the easier to follow and understand the processing order.

There are other commands and options having to do with the interruptibility of threads that you could tinker with. The basis of your problem is the interruptibility of threads.

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
aaart777
Posts: 11
Joined: 05 Nov 2020, 03:12

Re: Getting a GUI to move with another window?

05 Nov 2020, 07:06

FanaticGuru wrote:
02 May 2018, 18:13
AtleastItried wrote:I want to put my GUI ontop of another window and rest it there. ...
Ideally it should look like it exists natively in the window.
You might want to make the GUI a child window of a parent window.

Here is an example using Excel.

Code: Select all

Win_Hwnd := WinExist("ahk_exe excel.exe ahk_class XLMAIN")

; Gui Create
Gui, Color, Green
Gui, Font, s12 cRed, Bold Verdana
Gui, Add, Text,, This is Text
Gui, +LastFound +ToolWindow +AlwaysOnTop -Caption -Border HWNDGui_Hwnd
DllCall("SetParent", "uint", Gui_Hwnd, "uint", Win_Hwnd)
Gui, Show, x200 y200 ; Position on Gui Parent
return

Esc::ExitApp
I use this technique to add buttons to other programs. I have one program that I monitor for with a hook and any time it is opened a button is automatically added to the top of the window's titlebar where there is some blank space that allows me to run a AHK script. It is like adding a custom toolbar that goes beyond the capabilities of the program.

FG
Hey!

This code works super well for excel/word but it doesn't seem to work with other softwares. What's the reason for that? I'm trying to recreate exactly what was asked in this thread, but all my attempts at making this work for other softwares (I tried chrome, discord) didn't work ... would appreciate help!

My suspicion is that this script doesn't work with some classes? The class I'm trying to address is called "GLFW30". Is there something specific about that one which prevents the script from working correctly?

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Bing [Bot], Google [Bot], JKJadan, peter_ahk and 286 guests