One way to set the Always On Top flag is to import the SetWindowPos()
function from user32.dll and invoke it with arguments which:
- set the window parent to HWND_TOPMOST (-1)
- skip resizing / moving the window with SWP_NOMOVE (0x01) and SWP_NOSIZE (0x02) flags
There's no way to do this in pure batch, but you can have PowerShell do the heavy lifting. Here's a bat + PowerShell hybrid script template into which you can paste your batch code to make the console always on top:
<# : AlwaysOnTop.bat -- http://stackoverflow.com/a/37912693/1683264
@echo off & setlocal
rem // Relaunch self in PowerShell to run this window Always On Top
powershell -noprofile "iex (${%~f0} | out-string)"
rem /* ###############################
rem Your main batch code goes here.
rem ############################### */
goto :EOF
rem // end batch / begin PowerShell hybrid code #>
# // Solution based on http://stackoverflow.com/a/34703664/1683264
add-type user32_dll @'
[DllImport("user32.dll")]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter,
int x, int y, int cx, int cy, uint uFlags);
'@ -namespace System
# // Walk up the process tree until we find a window handle
$id = $PID
do {
$id = (gwmi win32_process -filter "ProcessID='$id'").ParentProcessID
$hwnd = (ps -id $id).MainWindowHandle
} while (-not $hwnd)
$rootWin = [IntPtr](-1)
$topmostFlags = 0x0003
[void][user32_dll]::SetWindowPos($hwnd, $rootWin, 0, 0, 0, 0, $topmostFlags)
One can also use GetWindowLong()
to query extended window styles to determine whether the window is already set always on top -- then toggle it.
<# : AlwaysOnTop2.bat -- http://stackoverflow.com/a/37912693/1683264
@echo off & setlocal
call :toggleAlwaysOnTop
rem /* ###############################
rem Your main batch code goes here.
rem ############################### */
goto :EOF
:toggleAlwaysOnTop
powershell -noprofile "iex (${%~f0} | out-string)"
goto :EOF
rem // end batch / begin PowerShell hybrid code #>
add-type user32_dll @'
[DllImport("user32.dll")]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter,
int x, int y, int cx, int cy, uint uFlags);
[DllImport("user32.dll")]
public static extern int GetWindowLong(IntPtr hWnd, int nIndex);
'@ -namespace System
$id = $PID
do {
$id = (gwmi win32_process -filter "ProcessID='$id'").ParentProcessID
$hwnd = (ps -id $id).MainWindowHandle
} while (-not $hwnd)
$style = [user32_dll]::GetWindowLong($hwnd, -20)
# // If flag 0x08 is set, make parent HWND -2 to unset it. Otherwise, HWND -1 to set it.
[IntPtr]$rootWin = ($style -band 0x08) / -8 - 1
[void][user32_dll]::SetWindowPos($hwnd, $rootWin, 0, 0, 0, 0, 0x03)