【问题标题】:How to close window with .bat script?如何使用 .bat 脚本关闭窗口?
【发布时间】:2016-04-21 16:53:43
【问题描述】:

我在用鼠标配置一些键绑定时遇到了一个小问题。

我想要实现的事情是从后台打开程序(打开或关闭窗口)并再次关闭它,但不杀死任务(相当于x按钮,所以它一直在后台运行)

我已经设置了我的鼠标来启动一个名为everything的应用程序(它能够非常快速地搜索文件系统)

我已经用这段代码弄清楚了:

TASKKILL /F /IM Everything.exe

我可以用宏键运行我可以杀死应用程序。但是我不想仅仅杀死应用程序本身的窗口,因为一旦我必须重新启动它,它需要一段时间来索引所有重要文件。

所以这里的问题是有什么方法可以在屏幕前面显示一个窗口/任务或触发 x 按钮事件,而不必终止整个进程?

Mouse(g600) 也支持 lua 脚本,但这可能是更难的方式。

【问题讨论】:

  • Taskkill 没有强制工作。如果没有Force,它会发布一条 wm_exit 消息,请求程序关闭,通常类似于 Alt + F4 向窗口发送 wm_close。(这些规则通常是在最后一个窗口关闭时退出)。 /f 终止应用程序 - 不询问或通知应用程序。
  • 可能,this 命令行实用程序有助于最小化/最大化您的“everything.exe”

标签: windows batch-file cmd lua


【解决方案1】:

最小化窗口通常可以通过激活窗口(将其置于前台)然后使用SendKeys() 发送 Alt+Space 来完成,然后发送任何字母区域设置为“最小化”(英文 Windows 中的 N)加了下划线。 Here's one 可能有几十个使用 VBScript 的示例。

在我看来,这个序列被过度使用、不优雅和无聊——而且它不适用于某些窗口(例如 cmd 控制台)。可以在不将其置于前台且不模拟按键的情况下最小化窗口。只需从 user32.dll 导入一个函数。只要我们遇到了这个麻烦,我们还不如导入第二个函数来检测当前窗口状态,这样我们就可以切换最小化/恢复。

我们可以像这样使用 PowerShell 导入函数。保存这个带有 .bat 扩展名的 Batch / PowerShell 混合脚本并运行它。

<# : minimize.bat
:: toggles minimized state of a window by its filename
:: minimize.bat /? for usage
:: https://stackoverflow.com/a/34834953/1683264

@echo off & setlocal

if "%~1"=="" goto usage
set "prog=%~n1"
tasklist | findstr /i "\<%prog%\>" >NUL || goto usage

set /P "=Toggling the minimized state of %prog%... " <NUL
powershell -noprofile -noninteractive "iex ((gc \"%~f0\") -join \"`n\")"

goto :EOF

:usage
echo syntax: %~nx0 progname[.exe]
echo;
echo If the program is visible, minimize it.  If minimized, restore it.
goto :EOF

:: end Batch / begin PowerShell hybrid chimera #>

Add-Type user32_dll @'
    [DllImport("user32.dll")]
    public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);

    [DllImport("user32.dll")]
    public static extern int GetWindowLong(IntPtr hWnd, int nIndex);
'@ -namespace System

$hwnd = @(Get-Process $env:prog)[0].MainWindowHandle
$state = [user32_dll]::GetWindowLong($hwnd, -16)

# mask of 0x20000000 = minimized; 2 = minimize; 4 = restore
if ($state -band 0x20000000) { $action = 4 } else { $action = 2 }

if ([user32_dll]::ShowWindowAsync($hwnd, $action)) {
    write-host "Success" -f green
} else {
    write-host "Fail" -f red
}

现在,如果您的程序最小化到系统托盘,之前的脚本可以很好地最小化,但在最小化时将无法找到窗口句柄。尝试恢复时会失败。在这种情况下找到 HWND 是很棘手的。如果知道窗口标题,可以使用 user32.dll FindWindow()FindWindowEx() 函数找到 HWND。

我在使用 WMI 或内置 PowerShell 命令来查找最小化到托盘的窗口标题时运气不佳。 get-processgwmi win32_process[diagnostics.process]::getProcessByName() 都没有成功。然而,我确实发现tasklist /v /fo list 的最后一行将显示窗口标题。这足以调用 FindWindow() 并获取 HWND。

这可能比它需要的更复杂,但也可能不会。我只知道我找到了 1000 种失败的方法,但只有一种方法可以成功。 Thanks to JPBlanc 帮助我弄清楚如何将空参数传递给 FindWindow()FindWindowEx()

<# : minimize.bat
:: toggles minimized state of a window by its filename
:: minimize.bat /? for usage

@echo off & setlocal

if "%~1"=="" goto usage
set "prog=%~n1"
tasklist | findstr /i "\<%prog%\>" >NUL || goto usage

set /P "=Toggling the minimized state of %prog%... " <NUL
powershell -noprofile -noninteractive "iex ((gc \"%~f0\") -join \"`n\")"

goto :EOF

:usage
echo syntax: %~nx0 progname[.exe]
echo;
echo If the program is visible, minimize it.  If minimized, restore it.
goto :EOF

End batch / begin PowerShell hybrid chimera #>

Add-Type user32_dll @'
    [DllImport("user32.dll")]
    public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);

    [DllImport("user32.dll")]
    public static extern int GetWindowLong(IntPtr hWnd, int nIndex);

    [DllImport("user32.dll")]
    public static extern IntPtr FindWindow(IntPtr lpClassName, string lpWindowName);

    [DllImport("user32.dll")]
    public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter,
        IntPtr lclassName, string windowTitle);
'@ -namespace System

$hwnd = (ps $env:prog)[0].MainWindowHandle

if ($hwnd -eq 0) {
    tasklist /v /fi "imagename eq $env:prog*" /fo list | %{
        $title = $_ -replace '^[^:]+:\s+'
    }
    $zero = [IntPtr]::Zero
    $hwnd = [user32_dll]::FindWindow($zero, $title)
    if ($hwnd -eq 0) {
        $hwnd = [user32_dll]::FindWindowEx($zero, $zero, $zero, $title)
    }
}

$state = [user32_dll]::GetWindowLong($hwnd, -16)

# mask of 0x20000000 = minimized; 2 = minimize; 4 = restore
if ($state -band 0x20000000) { $action = 4 } else { $action = 2 }

if ([user32_dll]::ShowWindowAsync($hwnd, $action)) {
    write-host "Success" -f green
} else {
    write-host "Fail" -f red
}

【讨论】:

  • 向该程序发送一个简单的 esc 按键就可以了。我应该如何在 vbscript 中解决这个问题?
  • 把它放到一个 .vbs 文件中:CreateObject("WScript.Shell").SendKeys "{ESC}" 然后调用它,wscript vbsfile.vbs。它将 Esc 发送到恰好被聚焦的任何窗口。如果您只需要发送 Esc 按键,您确定您的鼠标软件没有按键作为可分配的操作吗?
  • 是否也可以向特定窗口发送sendkey命令?
  • 您可以使用AppActivate 聚焦窗口。然后SendKeys 将击键发送到焦点窗口。
【解决方案2】:

无法评论,所以我会尝试回答。 'x' 按钮可能会杀死你的应用程序,除非应用程序被配置,否则我猜。 我想我理解您宁愿将其最小化为图标托盘或其他东西。据我所知,如果您的应用程序不是自然地这样做,这是不可能的。 您可以尝试按 alt + space + n,这是最小化应用程序的快捷方式。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-10
    • 2014-04-12
    • 1970-01-01
    相关资源
    最近更新 更多