Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

TitleButton 0.31


  • Please log in to reply
42 replies to this topic
majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
Special variant of docking deserved its own space. In latest version this script doesn't hook any specific window, but all windows (except alerts, menus, shelltray etc..). U can acieve single window titlebutton by using Dock function.

Posted Image


Posted Image

Download

Now you can have customizable buttons on titles, as many as you want, so you can create nice looking addons for Windows. Only your imagination is the limit.

What was previously very hard to get working without lot of
programming, you have here to abuse as much as you like.

Posted Image

Latest work here
Posted Image

Rajat
  • Members
  • 1904 posts
  • Last active: Jul 17 2015 07:45 AM
  • Joined: 28 Mar 2004
pretty neat! thanks for sharing.

MIA

CleanNews.in : Bite sized latest news headlines from India with zero bloat


mosaic
  • Members
  • 29 posts
  • Last active: Nov 04 2009 04:57 AM
  • Joined: 25 Apr 2007
It's very nice. However, when one double clicks on the title bar, which usually means Restore/Maximize, the titlebutton does not follow. It seems like Dock_event does not correctly generate an event for Restore/Maxmize. Even if one minimizes the window, then Maximizes the window, there is no Maxmize event (23) generated, only event 3 is generated.

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
I discovered that yesterday.

WinEvent doesn't recognise this event (Restore/Maximize).

Maximize/Minimize works nice here.


I was so dissapointed yesterday when I saw that Restore/Maximize doesn't fall into 16,17 or 22,23 category, nor in any other category.

By examining what is happening when I monitor events from 0 to 0xFFFFFF (should be all supported events IMO) I see that lot of strange 3227 or something, events are genererated. Perhpase Restore/Maximize falls into some general category.

Unless somebody can't help, this basicly means that WinEvent isn't good enough for docking as to fix Restore/Maximize, currently I have to set another timer running constatly, which was not the point.
Posted Image

JGR
  • Members
  • 59 posts
  • Last active: Feb 07 2012 08:49 PM
  • Joined: 15 Jun 2006
Actually event 32778, 0x800A EVENT_OBJECT_STATECHANGE, is sent when the window is restored or maximised.

Interestingly event 32779, 0x800B EVENT_OBJECT_LOCATIONCHANGE, is sent DURING a window move, if "Show window contents while dragging" windows option is turned on (I have it off usually).
I am not sure of the frequency/usefulness of this, but I will investigate...


JGR

majkinetor!
  • Guests
  • Last active:
  • Joined: --
Can you fix this TItleButton to work with Restore/Maximize as you did with Dock (yeah, dock works fine now)

The problem is little different here as in TitleButton DockHostClass basicly doesn't exist as all windows are hooked. 327789 is isued 10-15 times on Restore/Maximize so other messages are problematic.

The solution is probably to determine what is top level window out of event hwnd and to filter all hwnd's not representing top level windows.

Thalon
  • Members
  • 641 posts
  • Last active: Jan 02 2017 12:17 PM
  • Joined: 12 Jul 2005
The button does also disappear if window loses focus.

But this is a very usefull feature (if maximize-code is added).

Thx!
Thalon

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006

The button does also disappear if window loses focus.

I know about this but this is not something very important.
I have another version where button stays , but this introduced new problems so it was much easier just to let it be like that. The problem is if you have 2 notepad windows both should have its own 4th button. Now only active one has it. To make both has it is much more complicated and benefits are close to 0.

But this is a very usefull feature (if maximize-code is added).

Yes, its very useful and practical. If JGR can fix maximize I will create more handy wrapper that asks you how many buttons to add, icons for each, offset, handlers for left & right click etc...

Anyway, it would be helpful if someone point me to the ahk code that can say if hwnd is top level window or not. I have not much time to create it on my own, have some exames these days...
Posted Image

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
AH, I forgot one lil' detail. The script I was talking about is not the same as the one at the first post.


This is the script, that should be fixed. It doesn't use Dock_HostClass at all to filter but will add button on every title except msgbox windows (EVENT_ALERT is filtered).

#SingleInstance, force
CoordMode, mouse, screen
SetWinDelay, -1
SetBatchLines, -1
CoordMode, tooltip, screen
DetectHiddenWindows, On


	Gui, +LastFound -Caption +ToolWindow +AlwaysOnTop 
	hGui := WinExist()
	Gui, Font,s8 , Webdings	
	Gui, Add, Picture, x0 y0 +0x8000 gOnClick, enable.ico
	WinSet ExStyle, 0x08000008, ahk_id %hGui%  



	Gui, Color, 0
	WinSet, TransColor, 0

;	Dock_HostClass := "#32770"
	Dock_ClientId := hGui

	Dock("R","T",0,0,-90,5)
	Gui, Show, -1500 AutoSize
	Gui, Hide
	
return



GuiContextMenu:
	hwnd := WinExist("A")
	WinGetClass class, ahk_id %hwnd%
	msgbox Exclude %class% ?
return

OnClick:
	FMA_SHOW    = 3
	WM_FAVMENU	= 0x399
	PostMessage, WM_FAVMENU, FMA_SHOW,,,ahk_id 0xFFFF	
return


Dock(H="R",V="T", sizeX="", sizeY="", dx=0, dy=0 ) {
	local hwnd, msg


	hwnd := WinExist("ahk_pid " . DllCall("GetCurrentProcessId","Uint"))
	Dock_msg := 0x550

	HookDll = wineventhook.dll
	
	Dock_pH := H 
	Dock_pV := V
	Dock_dx := dx 
	Dock_dy := dy
	Dock_sizeX := sizeX 
	Dock_sizeY := sizeY

	Dock_hHookDll := API_LoadLibrary(HookDll)

	Dock_hHook0 := Hook(hwnd, Dock_msg, 3)								;   EVENT_SYSTEM_FOREGROUND
	Dock_hHook1 := Hook(hwnd, Dock_msg, 22, 23)							;   EVENT_SYSTEM_MINIMIZEEND
	Dock_hHook2 := Hook(hwnd, Dock_msg, 2)		
	Dock_hHook4 := Hook(hwnd, Dock_msg, 10, 11, "Dock_HookHandler")		;	EVENT_SYSTEM_MOVESIZESTART :=  10	EVENT_SYSTEM_MOVESIZEEND :=  11

	return Dock_hHook & Dock_hHookDll
}

Dock_Timer:
	WinGetPos, Dock_hX, Dock_hY, Dock_hW, Dock_hH,  ahk_id %Dock_HookHwnd%
	WinGetPos, Dock_cX, Dock_cY, Dock_cW, Dock_cH,  ahk_id %Dock_ClientId%
	Dock_H := Dock_cH
	Dock_W := Dock_cW

	
	if (Dock_sizeX)
		StringReplace, Dock_W, Dock_sizeX, A_DockHostWidth, %Dock_hW%

	if (Dock_sizeY)	
		StringReplace, Dock_H, Dock_sizeY, A_DockHostHeight, %Dock_hH%

	
	Dock_x := Dock_hX 
	if (Dock_pH = "R")
			Dock_x := Dock_hX + Dock_hW
	else if (Dock_pH = "M") 
		Dock_x := Dock_hX + (Dock_hW//2) - (Dock_cW//2)

	Dock_y := Dock_hY
	if (Dock_pV = "B")
		Dock_y := Dock_hY + Dock_hH
	else if (Dock_pV = "M") 
		Dock_y := Dock_hY + (Dock_hH//2) - (Dock_cH//2)


	Dock_x += Dock_dx, Dock_y += Dock_dy
	WinMove, ahk_id %Dock_ClientId%, ,%Dock_X%, %Dock_Y%, %Dock_W%, %Dock_H%
	WinSet, Top,, ahk_id %Dock_ClientId%
	API_ShowWindow(Dock_ClientId, 4)
return


Undock(){
	goSub Dock_Timer
	Unhook(Dock_hHook, Dock_msg)
	API_FreeLibrary(HookDll)
}
	
Dock_HookHandler(wParam, lParam, msg, hwnd) {
	local e, cls, title
	static alert 
	
	GetHookParams(lparam, Dock_event, Dock_HookHwnd)	   
	WinGetClass Dock_cls, ahk_id %Dock_HookHwnd% 

	if Dock_event = 2
	{
		alert := Dock_HookHwnd
		return
	}

	if (alert = Dock_HookHwnd)	;skip alert windows
		return

    WinGetTitle, title, ahk_id %Dock_HookHwnd% 
    if (title = "")
		return
	

	if StrLen(s)>200
		s =
	s .= Dock_event "`n"



	
	if (Dock_HookHwnd = Dock_ClientId) {
;		if !WinExist("ahk_class " Dock_HostClass)
;			WinHide, ahk_id %Dock_ClientId%
		return
	}
;	if (Dock_cls != Dock_HostClass){
;		if (Dock_event = 3)
;			WinHide, ahk_id %Dock_ClientId%
;		return
;	}
	Tooltip %s%, 0, 0
	if (Dock_event = 10)  {		;movesize start
		SetTimer, Dock_Timer, 0
		return
	}

	if (Dock_event = 11) {		;movesize end
		SetTimer, Dock_Timer, off
		gosub Dock_Timer
		return
	}

	if (Dock_event = 3)	{		;foreground
		Sleep 100
		gosub Dock_Timer
	}
	
	if (Dock_event = 23) or (Dock_event=0x800B)	;maximized
		gosub Dock_Timer
	

	if Dock_event = 22			;minimized
		WinHide, ahk_id %Dock_ClientId%
}


GetHookParams(lparam, ByRef event, ByRef hwnd="", ByRef idObject="", ByRef idChild="", ByRef dwEventThread="", ByRef dwmsEventTime="") {
	event			:=GetDeRefInteger(lParam+4)
	hwnd			:=GetDeRefInteger(lParam+8)
	idObject		:=GetDeRefInteger(lParam+12)
	idChild			:=GetDeRefInteger(lParam+16)
	dwEventThread	:=GetDeRefInteger(lParam+20)
	dwmsEventTime	:=GetDeRefInteger(lParam+24)
}

Hook(comm_hwnd, comm_msg, s_event, e_event="", function="", wparam=0) { 
	global HookDll 
    
	r := DllCall(HookDll "\reghook", "UInt", comm_hwnd, "UInt", COMM_MSG, "UInt", s_event, "UInt", e_event ? e_event : s_event, "UInt", wparam) 
	if !r 
		return 0 

	if (function)
		OnMessage(COMM_MSG, function) 

	return r 
}

Unhook(handle, com_msg) { 
   OnMessage(com_msg) 
   return DllCall("UnhookWinEvent", "UInt", handle) 
} 

API_LoadLibrary( dll ) { 
   return DllCall("LoadLibrary", "str", dll) 
}

API_FreeLibrary( h ) {
    return DllCall("FreeLibrary", "uint", h) 
}

API_ShowWindow(hwnd, flag){
   return DllCall("ShowWindow", "UInt", hwnd, "int", flag) 	
}



GetDeRefInteger(pSource, pIsSigned = false, pSize = 4)
; pSource is an integer pointer to a raw/binary integer
; The caller should pass true for pSigned to interpret the result as signed vs. unsigned.
; pSize is the size of PSource's integer in bytes (e.g. 4 bytes for a DWORD or Int).
{
   Loop %pSize%  ; Build the integer by adding up its bytes.
      result += *(pSource + A_Index-1) << 8*(A_Index-1)
   if (!pIsSigned OR pSize > 4 OR result < 0x80000000)
      return result  ; Signed vs. unsigned doesn't matter in these cases.
   ; Otherwise, convert the value (now known to be 32-bit) to its signed counterpart:
   return -(0xFFFFFFFF - result + 1)
}

SetDeRefInteger(pInteger, pDest, pSize = 4)
; The caller must ensure that *pDest has sufficient capacity and that pDest is a valid dereferencable integer pointer.
; To preserve any existing contents at *pDest, only pSize number of bytes are altered.
{
   Loop %pSize%  ; Copy each byte in the integer into the structure as raw binary data.
      DllCall("RtlFillMemory", UInt, pDest + A_Index-1, UInt, 1, UChar, pInteger >> 8*(A_Index-1) & 0xFF)
}

Posted Image

JGR
  • Members
  • 59 posts
  • Last active: Feb 07 2012 08:49 PM
  • Joined: 15 Jun 2006
Maximise is fixed already:
See here, changes are added into the dock script.

Event 0x800A EVENT_OBJECT_STATECHANGE, for maximise/restore and event 0x800B EVENT_OBJECT_LOCATIONCHANGE, for window movement (no timer necessary).

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
I know, I said to you that dock is fixed.

BUt this is not like dock. There is no Dock_HostClass as every window should be afected except alerts. So there is no thing like

WinGetClass cls, ahk_id %EventHWND%
  if (Dock_HostClass != cls)
     return

to filter 10-20 32779 events that you get when you maximize single window.

So, EVENT_OBJECT_LOCATIONCHANGE will be risied bunch of times for single maximize event for any window and handle of that window will be among other handles in the bunch of events. So, dock client will get wrong coordinates as it will check some funny window (maybe child hwnd that rised EVENT_OBJECT_LOCATIONCHANGE after main window is reported). I didn't further investigate this, didn't have time today, the easiest solution would probably be to check the type of handle you recieve and discard everything having WS_CHILD style.
Posted Image

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
Well, check it out yourself here:

#SingleInstance, force
CoordMode, mouse, screen
SetWinDelay, -1
SetBatchLines, -1
CoordMode, tooltip, screen
DetectHiddenWindows, On


	Gui, +LastFound -Caption +ToolWindow +AlwaysOnTop 
	hGui := WinExist()
	Gui, Font,s8 , Webdings	
	Gui, Add, Picture, x0 y0 +0x8000 gOnClick, enable.ico
	WinSet ExStyle, 0x08000008, ahk_id %hGui%  



	Gui, Color, 0
	WinSet, TransColor, 0

	Dock_HostClass := "#32770"
	Dock_ClientId := hGui

	Dock("R","T",0,0,-90,5)
	Gui, Show, -1500 AutoSize
	Gui, Hide
	
return



GuiContextMenu:
	hwnd := WinExist("A")
	WinGetClass class, ahk_id %hwnd%
	msgbox Exclude %class% ?
return

OnClick:
	FMA_SHOW    = 3
	WM_FAVMENU	= 0x399
	PostMessage, WM_FAVMENU, FMA_SHOW,,,ahk_id 0xFFFF	
return


Dock(H="R",V="T", sizeX="", sizeY="", dx=0, dy=0 ) {
	local hwnd, msg


	hwnd := WinExist("ahk_pid " . DllCall("GetCurrentProcessId","Uint"))
	Dock_msg := 0x550

	HookDll = wineventhook.dll
	
	Dock_pH := H 
	Dock_pV := V
	Dock_dx := dx 
	Dock_dy := dy
	Dock_sizeX := sizeX 
	Dock_sizeY := sizeY

	Dock_hHookDll := API_LoadLibrary(HookDll)

	Dock_hHook0 := Hook(hwnd, Dock_msg, 3)								;   EVENT_SYSTEM_FOREGROUND
	Dock_hHook1 := Hook(hwnd, Dock_msg, 22, 23)							;   EVENT_SYSTEM_MINIMIZEEND
	Dock_hHook2 := Hook(hwnd, Dock_msg, 2)		
    Dock_hHook3 := Hook(hwnd, Dock_msg, 0x800A, 0x800B, "Dock_HookHandler")      ;EVENT_OBJECT_STATECHANGE        0x0000800a, EVENT_OBJECT_LOCATIONCHANGE     0x0000800b,


	return Dock_hHook & Dock_hHookDll
}

Dock_Timer:
	WinGetPos, Dock_hX, Dock_hY, Dock_hW, Dock_hH,  ahk_id %Dock_HookHwnd%
	WinGetPos, Dock_cX, Dock_cY, Dock_cW, Dock_cH,  ahk_id %Dock_ClientId%
	Dock_H := Dock_cH
	Dock_W := Dock_cW

	
	if (Dock_sizeX)
		StringReplace, Dock_W, Dock_sizeX, A_DockHostWidth, %Dock_hW%

	if (Dock_sizeY)	
		StringReplace, Dock_H, Dock_sizeY, A_DockHostHeight, %Dock_hH%

	
	Dock_x := Dock_hX 
	if (Dock_pH = "R")
			Dock_x := Dock_hX + Dock_hW
	else if (Dock_pH = "M") 
		Dock_x := Dock_hX + (Dock_hW//2) - (Dock_cW//2)

	Dock_y := Dock_hY
	if (Dock_pV = "B")
		Dock_y := Dock_hY + Dock_hH
	else if (Dock_pV = "M") 
		Dock_y := Dock_hY + (Dock_hH//2) - (Dock_cH//2)


	Dock_x += Dock_dx, Dock_y += Dock_dy
	WinMove, ahk_id %Dock_ClientId%, ,%Dock_X%, %Dock_Y%, %Dock_W%, %Dock_H%
	WinSet, Top,, ahk_id %Dock_ClientId%
	API_ShowWindow(Dock_ClientId, 4)
return


Undock(){
	goSub Dock_Timer
	Unhook(Dock_hHook, Dock_msg)
	API_FreeLibrary(HookDll)
}
	
Dock_HookHandler(wParam, lParam, msg, hwnd) {
	local e, cls, title
	static alert 
	
	GetHookParams(lparam, Dock_event, Dock_HookHwnd)	   
	WinGetClass Dock_cls, ahk_id %Dock_HookHwnd% 

	if Dock_event = 2
	{
		alert := Dock_HookHwnd
		return
	}

	if (alert = Dock_HookHwnd)	;skip alert windows
		return

    WinGetTitle, title, ahk_id %Dock_HookHwnd% 
    if (title = "")
		return
	

	if StrLen(s)>200
		s =
	s .= Dock_event "`n"



	
	if (Dock_HookHwnd = Dock_ClientId) {
;		if !WinExist("ahk_class " Dock_HostClass)
;			WinHide, ahk_id %Dock_ClientId%
		return
	}
;	if (Dock_cls != Dock_HostClass){
;		if (Dock_event = 3)
;			WinHide, ahk_id %Dock_ClientId%
;		return
;	}
;	Tooltip %s%, 0, 0

	if (Dock_event = 3)	{		;foreground
		gosub Dock_Timer
	}
	
	if (Dock_event = 23) or (Dock_event=0x800B)	;maximized
		gosub Dock_Timer
	

	if Dock_event = 22			;minimized
		WinHide, ahk_id %Dock_ClientId%
}


GetHookParams(lparam, ByRef event, ByRef hwnd="", ByRef idObject="", ByRef idChild="", ByRef dwEventThread="", ByRef dwmsEventTime="") {
	event			:=GetDeRefInteger(lParam+4)
	hwnd			:=GetDeRefInteger(lParam+8)
	idObject		:=GetDeRefInteger(lParam+12)
	idChild			:=GetDeRefInteger(lParam+16)
	dwEventThread	:=GetDeRefInteger(lParam+20)
	dwmsEventTime	:=GetDeRefInteger(lParam+24)
}

Hook(comm_hwnd, comm_msg, s_event, e_event="", function="", wparam=0) { 
	global HookDll 
    
	r := DllCall(HookDll "\reghook", "UInt", comm_hwnd, "UInt", COMM_MSG, "UInt", s_event, "UInt", e_event ? e_event : s_event, "UInt", wparam) 
	if !r 
		return 0 

	if (function)
		OnMessage(COMM_MSG, function) 

	return r 
}

Unhook(handle, com_msg) { 
   OnMessage(com_msg) 
   return DllCall("UnhookWinEvent", "UInt", handle) 
} 

API_LoadLibrary( dll ) { 
   return DllCall("LoadLibrary", "str", dll) 
}

API_FreeLibrary( h ) {
    return DllCall("FreeLibrary", "uint", h) 
}

API_ShowWindow(hwnd, flag){
   return DllCall("ShowWindow", "UInt", hwnd, "int", flag) 	
}



GetDeRefInteger(pSource, pIsSigned = false, pSize = 4)
; pSource is an integer pointer to a raw/binary integer
; The caller should pass true for pSigned to interpret the result as signed vs. unsigned.
; pSize is the size of PSource's integer in bytes (e.g. 4 bytes for a DWORD or Int).
{
   Loop %pSize%  ; Build the integer by adding up its bytes.
      result += *(pSource + A_Index-1) << 8*(A_Index-1)
   if (!pIsSigned OR pSize > 4 OR result < 0x80000000)
      return result  ; Signed vs. unsigned doesn't matter in these cases.
   ; Otherwise, convert the value (now known to be 32-bit) to its signed counterpart:
   return -(0xFFFFFFFF - result + 1)
}

SetDeRefInteger(pInteger, pDest, pSize = 4)
; The caller must ensure that *pDest has sufficient capacity and that pDest is a valid dereferencable integer pointer.
; To preserve any existing contents at *pDest, only pSize number of bytes are altered.
{
   Loop %pSize%  ; Copy each byte in the integer into the structure as raw binary data.
      DllCall("RtlFillMemory", UInt, pDest + A_Index-1, UInt, 1, UChar, pInteger >> 8*(A_Index-1) & 0xFF)
}

It almost work correctly. No timer.
The star (button) flickers sometimes (I guess because of great number of messages received). Also, most important is this: star is sometimes on weird positions, like in the middle of something, this happens only on event=3 (foreground). Its strange... somehow putting sleep before processing this event produce different frequencies of this bug. The star is returned to right place as soon as I move the window arround. Fast alttabing sometimes makes the star stay on the same place as before.

Notice that you can right click on star. I planned this so you can exclude certain window (for instance ICQ, Miranda, DesktopX etc..) that are not excluded automaticaly. Now it just reports class of window under it. I done it by making gui holding the star having WS_NOACTIVATE flag.

BTW, enable the tooltip to see event. I desabled it as star flickers cuz tooltip is updated fast as of bunch of events.

Interestingly enough timer worked better. Now, when you move window around CPU goes very high. Timer didn't touch CPU more then 1-2% while moving.
Posted Image

JGR
  • Members
  • 59 posts
  • Last active: Feb 07 2012 08:49 PM
  • Joined: 15 Jun 2006
Solved by adding some lines, as after foreground change, some messages are still received from old foreground window...

Note that you cannot seem to left click on the icon, but right click works... I have not checked to find out why yet.

#SingleInstance, force
CoordMode, mouse, screen
SetWinDelay, -1
SetBatchLines, -1
CoordMode, tooltip, screen
DetectHiddenWindows, On


   Gui, +LastFound -Caption +ToolWindow +AlwaysOnTop
   hGui := WinExist()
   Gui, Font,s8 , Webdings   
   Gui, Add, Picture, x0 y0 +0x8000 gOnClick, enable.ico
   WinSet ExStyle, 0x08000008, ahk_id %hGui% 



   Gui, Color, 0
   WinSet, TransColor, 0

   Dock_HostClass := "#32270"
   Dock_ClientId := hGui

   Dock("R","T",0,0,-90,5)
   Gui, Show, -1500 AutoSize
   Gui, Hide
   
return



GuiContextMenu:
   hwnd := WinExist("A")
   WinGetClass class, ahk_id %hwnd%
   msgbox Exclude %class% ?
return

OnClick:
   FMA_SHOW    = 3
   WM_FAVMENU   = 0x399
   PostMessage, WM_FAVMENU, FMA_SHOW,,,ahk_id 0xFFFF   
return


Dock(H="R",V="T", sizeX="", sizeY="", dx=0, dy=0 ) {
   local hwnd, msg


   hwnd := WinExist("ahk_pid " . DllCall("GetCurrentProcessId","Uint"))
   Dock_msg := 0x550

   HookDll = wineventhook.dll
   
   Dock_pH := H
   Dock_pV := V
   Dock_dx := dx
   Dock_dy := dy
   Dock_sizeX := sizeX
   Dock_sizeY := sizeY

   Dock_hHookDll := API_LoadLibrary(HookDll)

   Dock_hHook0 := Hook(hwnd, Dock_msg, 3)                        ;   EVENT_SYSTEM_FOREGROUND
   Dock_hHook1 := Hook(hwnd, Dock_msg, 22, 23)                     ;   EVENT_SYSTEM_MINIMIZEEND
   Dock_hHook2 := Hook(hwnd, Dock_msg, 2)      
    Dock_hHook3 := Hook(hwnd, Dock_msg, 0x800A, 0x800B, "Dock_HookHandler")      ;EVENT_OBJECT_STATECHANGE        0x0000800a, EVENT_OBJECT_LOCATIONCHANGE     0x0000800b,


   return Dock_hHook & Dock_hHookDll
}

Dock_Timer:
   Dock_hW:=0
   Dock_hH:=0
   WinGetPos, Dock_hX, Dock_hY, Dock_hW, Dock_hH,  ahk_id %Dock_HookHwnd%
   WinGetPos, Dock_cX, Dock_cY, Dock_cW, Dock_cH,  ahk_id %Dock_ClientId%
   Dock_H := Dock_cH
   Dock_W := Dock_cW

OutputDebug %Dock_HookHwnd%, %Dock_hX%, %Dock_hY%, %Dock_hW%, %Dock_hH%, %Dock_ClientId%, %Dock_cX%, %Dock_cY%, %Dock_cW%, %Dock_cH%, %Dock_sizeX%, %Dock_sizeY%, %count%
   
   if (Dock_sizeX)
      StringReplace, Dock_W, Dock_sizeX, A_DockHostWidth, %Dock_hW%

   if (Dock_sizeY)   
      StringReplace, Dock_H, Dock_sizeY, A_DockHostHeight, %Dock_hH%

   
   Dock_x := Dock_hX
   if (Dock_pH = "R")
         Dock_x := Dock_hX + Dock_hW
   else if (Dock_pH = "M")
      Dock_x := Dock_hX + (Dock_hW//2) - (Dock_cW//2)

   Dock_y := Dock_hY
   if (Dock_pV = "B")
      Dock_y := Dock_hY + Dock_hH
   else if (Dock_pV = "M")
      Dock_y := Dock_hY + (Dock_hH//2) - (Dock_cH//2)

   Dock_x += Dock_dx, Dock_y += Dock_dy
   OutputDebug %Dock_Event%, %Dock_ClientId%, %Dock_X%, %Dock_Y%
   WinMove, ahk_id %Dock_ClientId%, ,%Dock_X%, %Dock_Y%, %Dock_W%, %Dock_H%
   WinSet, Top,, ahk_id %Dock_ClientId%
   API_ShowWindow(Dock_ClientId, 4)
return


Undock(){
   goSub Dock_Timer
   Unhook(Dock_hHook, Dock_msg)
   API_FreeLibrary(HookDll)
}
   
Dock_HookHandler(wParam, lParam, msg, hwnd) {
   local e, cls, title
   static alert
   
   GetHookParams(lparam, Dock_event, Dock_HookHwnd)      
   WinGetClass Dock_cls, ahk_id %Dock_HookHwnd%

   if Dock_event = 2
   {
      alert := Dock_HookHwnd
      return
   }

   if (alert = Dock_HookHwnd)   ;skip alert windows
      return

    WinGetTitle, title, ahk_id %Dock_HookHwnd%
    if (title = "")
      return


   if StrLen(s)>200
      s =
   s .= Dock_event "`n"


   if (Dock_HookHwnd = Dock_ClientId) {
;      if !WinExist("ahk_class " Dock_HostClass)
;         WinHide, ahk_id %Dock_ClientId%
      return
   }

;   if (Dock_cls != Dock_HostClass){
;      if (Dock_event = 3)
;         WinHide, ahk_id %Dock_ClientId%
;      return
;   }
;   Tooltip %s%, 0, 0

   if (Dock_event = 3)   {      ;foreground
      [color=red]currentforeground:=Dock_HookHwnd[/color]
      gosub Dock_Timer
   }
[color=red]   if(currentforeground<>Dock_HookHwnd)
   	return[/color]
   if (Dock_event = 23) or (Dock_event=0x800B) [color=red]or (Dock_event=0x800A)[/color]   ;maximized
      gosub Dock_Timer
   

   if Dock_event = 22         ;minimized
      WinHide, ahk_id %Dock_ClientId%
}


GetHookParams(lparam, ByRef event, ByRef hwnd="", ByRef idObject="", ByRef idChild="", ByRef dwEventThread="", ByRef dwmsEventTime="") {
   event         :=GetDeRefInteger(lParam+4)
   hwnd         :=GetDeRefInteger(lParam+8)
   idObject      :=GetDeRefInteger(lParam+12)
   idChild         :=GetDeRefInteger(lParam+16)
   dwEventThread   :=GetDeRefInteger(lParam+20)
   dwmsEventTime   :=GetDeRefInteger(lParam+24)
}

Hook(comm_hwnd, comm_msg, s_event, e_event="", function="", wparam=0) {
   global HookDll
   
   r := DllCall(HookDll "\reghook", "UInt", comm_hwnd, "UInt", COMM_MSG, "UInt", s_event, "UInt", e_event ? e_event : s_event, "UInt", wparam)
   if !r
      return 0

   if (function)
      OnMessage(COMM_MSG, function)

   return r
}

Unhook(handle, com_msg) {
   OnMessage(com_msg)
   return DllCall("UnhookWinEvent", "UInt", handle)
}

API_LoadLibrary( dll ) {
   return DllCall("LoadLibrary", "str", dll)
}

API_FreeLibrary( h ) {
    return DllCall("FreeLibrary", "uint", h)
}

API_ShowWindow(hwnd, flag){
   return DllCall("ShowWindow", "UInt", hwnd, "int", flag)
}



GetDeRefInteger(pSource, pIsSigned = false, pSize = 4)
; pSource is an integer pointer to a raw/binary integer
; The caller should pass true for pSigned to interpret the result as signed vs. unsigned.
; pSize is the size of PSource's integer in bytes (e.g. 4 bytes for a DWORD or Int).
{
   Loop %pSize%  ; Build the integer by adding up its bytes.
      result += *(pSource + A_Index-1) << 8*(A_Index-1)
   if (!pIsSigned OR pSize > 4 OR result < 0x80000000)
      return result  ; Signed vs. unsigned doesn't matter in these cases.
   ; Otherwise, convert the value (now known to be 32-bit) to its signed counterpart:
   return -(0xFFFFFFFF - result + 1)
}

SetDeRefInteger(pInteger, pDest, pSize = 4)
; The caller must ensure that *pDest has sufficient capacity and that pDest is a valid dereferencable integer pointer.
; To preserve any existing contents at *pDest, only pSize number of bytes are altered.
{
   Loop %pSize%  ; Copy each byte in the integer into the structure as raw binary data.
      DllCall("RtlFillMemory", UInt, pDest + A_Index-1, UInt, 1, UChar, pInteger >> 8*(A_Index-1) & 0xFF)
}


majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
Great.

Works almost like a charm.

Almost is really a small problem. Sometimes, the star doesn't jump to next window. In my situation this: #R (open run) . Repeat: ALT B then ESC fast. In my scenario, once Browse dialog will not get the icon but it will stay at Run.

Other then that, seems to work fine. Thx.

O yeah, button click opens favmenu if it is active among processes
PostMessage, WM_FAVMENU, FMA_SHOW,,,ahk_id 0xFFFF

Posted Image

JGR
  • Members
  • 59 posts
  • Last active: Feb 07 2012 08:49 PM
  • Joined: 15 Jun 2006
Poking through autohotkey's code, line 1785 of MsgMonitor in application.cpp suggests that if the message handler is already running, the message is simply discarded rather than being queued, or waiting for the message handler function to finish.

I have verified that messages are dropped at this point when executing the script (with OllyDbg).

It might be easier to simply use a synchronisation object within the hook dll, to prevent multiple messages being sent concurrently...
I will try this next.

JGR

Edit:
Occasionally I get this (after adding some debugging to AHK)
[916] AHK -- Message Dropped -- 0x550 -- event: 0x3 -- window 918460
This is with using critical on the message handler, and using a critical section object around sendmessage in the dll.
I suspect that somehow, the message handler is triggering these early, so that they are subsequently lost, and the OS thinks that they are sent, and does not send them again...

I may try buffering in the dll, instead.