将批处理脚本CMD窗口保留在新打开的CMD窗口之上

时间:2016-06-18 12:42:54

标签: windows batch-file cmd scripting

可能是一个简单的答案,但无法在线找到。

我有一个.bat脚本来打开一些程序,并且还想要用户输入(Y [N]),这一切都能正常工作。

我的问题。

如何将脚本窗口保留在新打开的窗口之上,以便用户可以看到脚本正在寻找一些输入。

@ECHO OFF
REM  2016-06-17 GMAN

REM Start Zookeeper
cd zookeeper-3.4.8 
CALL StartZookeeper.bat

REM Give Zookeeper a chance to start
sleep 4

REM Start Kafka
cd ..\kafka_2.11-0.10.0.0 
CALL StartKafka.bat

REM Give Kafka a chance to start
sleep 2

setlocal
:PROMPT
SET /p prodCons="Open a CMD for Producer and Consumer: (Y/[N]"?)
echo You entered: %prodCons%
sleep 1

IF /I "%prodCons%" NEQ "Y" GOTO END

REM Producer Terminal
start cmd.exe /k "TITLE Producer && cd .\kafka_2.11-0.10.0.0\bin\windows"

REM Consumer Terminal
start cmd.exe /k "TITLE Consumer && cd .\kafka_2.11-0.10.0.0\bin\windows"   

:END
endlocal

我的脚本窗口隐藏在新CMD后面,因此用户可以看到输入Y或N.

2 个答案:

答案 0 :(得分:0)

设置Always On Top标志的一种方法是导入SetWindowPos() function from user32.dll并使用以下参数调用它:

  • 将父窗口设置为HWND_TOPMOST(-1)
  • 使用SWP_NOMOVE(0x01)和SWP_NOSIZE(0x02)标记跳过调整窗口大小/移动窗口

在纯批次中没有办法做到这一点,但是你可以让PowerShell做繁重的工作。这是一个bat + PowerShell混合脚本模板,您可以粘贴批处理代码以使控制台始终位于顶部:

<# : 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)

还可以使用GetWindowLong()查询扩展窗口样式,以确定窗口是否已经设置在顶部 - 然后切换它。

<# : 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)

答案 1 :(得分:0)

为澄清起见,我试图使其始终位于脚本中间的顶部,而不是最底部。这会改变它的工作方式吗?即当用户在选项菜单中选择设置时,它将切换为“始终在最前面”。