The last version seems to work OK, and fast enough. (Checking Dock_event = 3 was clever!) I made a few changes. Keep the ones you see fit.
- There is no need any more for API_ShowWindow(Dock_ClientId, 8) in the Dock_Update subroutine.
- It is a little cleaner to list explicitly the global variables a function needs, albeit longer.
- We don't need to load the hook dll repeatedly.
- It is enough to determine the script's process ID only once.
- The return value of the function Dock was better the logic AND of the handles, which is 0 if any one of them is 0. (Bitwise AND can be 0 otherwise, too.)
- Undock does not need GoSub Dock_Update
- I made the calling syntax of the dock function faster and more flexible, but also more complex (beginners choose one of a few listed options). There are 10 parameters: (xhw,xw,xd, yhh,yh,yd, whw,wd, hhh,hd)
--- The x coordinate of the top, left corner of the client window is computed as
HostX + xhw*HostWidth + xw*ClientWidth + xd, with the parameters xhw, xw and xd
--- The y coordinate of the top, left corner of the client window is computed as
HostY + yhh*HostHeight + yh*ClientHeight + yd, with the parameters yhh, yh and yd
--- The width ClientWidth of the client window is computed as whw*HostWidth + wd, with the parameters whw and wd.
--- The height ClientHeight of the client window is computed as hhh*HostHeight + hd, with the parameters hhh and hd.
Code:
#SingleInstance Force
#NoEnv
SetBatchLines -1
SetWinDelay -1
OnExit Close
HookDll = wineventhook.dll
Run notepad,,,nPID
WinWait ahk_pid %nPID%
Dock_HostID := Dock_HookHwnd := WinExist("ahk_pid " . nPID)
Gui +LastFound -Caption +ToolWindow +Border
Dock_ClientID := WinExist()
Gui Add, Text,,Docked Window
Gui Show
; dx = (HostWidth*, ClientWidth*, Offset)
; dy = (HostHeight*,ClientHeight*,Offset)
; w = (HostWidth*, Constant)
; h = (HostHeight*,Constant)
;Dock(0,0,0, 1,0,-2, 1,0, 0,30) ; below, full width
;Dock(.5,-.5,0, 1,0,10, .5,0, 0,30) ; below, centered, half width
;Dock(0,-1,-10, 0,0,0, 0,63, 1,0) ; left, top
;Dock(1,0,10, 0,0,50, 0,63, 1,-50) ; right, bottom
Dock(0,0,0, 0,-1,-5, 0,120, 0,30) ; above, left, fixed width
Dock_Update:
If (Dock_HookHwnd != Dock_HostID)
Return
WinGetPos hX, hY, hW, hH, ahk_id %Dock_HookHwnd%
W := whw*hW + wd, H := hhh*hH + hd
WinMove ahk_id %Dock_ClientId%,,hX + xhw*hW + xw*W + xd, hY + yhh*hH + yh*H + yd, W, H
If (Dock_event = 3) {
WinSet AlwaysOnTop, On, ahk_id %Dock_ClientId%
WinSet AlwaysOnTop, Off, ahk_id %Dock_ClientId%
}
Return
Close:
Undock()
WinClose ahk_id %Dock_HostID%
ExitApp
Dock(_xhw,_xw,_xd, _yhh,_yh,_yd, _whw,_wd, _hhh,_hd) {
Global HookDll, xhw,xw,xd, yhh,yh,yd, whw,wd, hhh,hd
Static hwnd, Dock_hHookDll, Dock_msg := 0x550
If Dock_hHookDll=
Dock_hHookDll := API_LoadLibrary(HookDll)
If hwnd=
hwnd := WinExist("ahk_pid " . DllCall("GetCurrentProcessId"))
xhw:=_xhw, xw:=_xw, xd:=_xd, yhh:=_yhh, yh:=_yh, yd:=_yd, whw:=_whw, wd:=_wd, hhh:=_hhh, hd:=_hd
Dock_hHook0 := Hook(hwnd, Dock_msg, 3) ; EVENT_SYSTEM_FOREGROUND
Dock_hHook2 := Hook(hwnd, Dock_msg, 10, 11) ; EVENT_SYSTEM_MOVESIZESTART 10 EVENT_SYSTEM_MOVESIZEEND 11
Dock_hHook3 := Hook(hwnd, Dock_msg, 0x800A, 0x800B, "Dock_HookHandler") ;EVENT_OBJECT_STATECHANGE 0x0000800a, EVENT_OBJECT_LOCATIONCHANGE 0x0000800b
Return Dock_hHook3 && Dock_hHook2 && Dock_hHook0 && Dock_hHookDll
}
Dock_HookHandler(wParam, lParam, msg, hwnd) {
Global Dock_event, Dock_HookHwnd
GetHookParams(lparam, Dock_event, Dock_HookHwnd)
GoSub Dock_Update
}
GetHookParams(lparam, ByRef event, ByRef hwnd="", ByRef idObject="", ByRef idChild="", ByRef dwEventThread="", ByRef dwmsEventTime="") {
DllCall("RtlMoveMemory", UIntP,event , UInt,lParam+ 4, UInt, 4)
DllCall("RtlMoveMemory", UIntP,hwnd , UInt,lParam+ 8, UInt, 4)
DllCall("RtlMoveMemory", UIntP,idObject , UInt,lParam+12, UInt, 4)
DllCall("RtlMoveMemory", UIntP,idChild , UInt,lParam+16, UInt, 4)
DllCall("RtlMoveMemory", UIntP,dwEventThread, UInt,lParam+20, UInt, 4)
DllCall("RtlMoveMemory", UIntP,dwmsEventTime, UInt,lParam+24, UInt, 4)
}
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 (function)
OnMessage(COMM_MSG, function)
Return r
}
Undock() {
Unhook(Dock_hHook, Dock_msg)
API_FreeLibrary(HookDll)
}
Unhook(handle, com_msg) {
OnMessage(com_msg)
Return DllCall("UnhookWinEvent", "UInt", handle)
}
API_ShowWindow(hwnd, flag){
return DllCall("ShowWindow", "UInt", hwnd, "int", flag)
}
API_LoadLibrary( dll ) {
Return DllCall("LoadLibrary", "str", dll)
}
API_FreeLibrary( h ) {
Return DllCall("FreeLibrary", "uint", h)
}