无法恢复使用ShowWindow隐藏的窗口

时间:2018-03-06 03:49:01

标签: c# powershell pinvoke user32

我在脚本中有以下类型定义:

Add-Type -TypeDefinition @'
namespace Win32
{
    //https://msdn.microsoft.com/en-us/library/windows/desktop/ms633548(v=vs.85).aspx
    public static class Functions
    {
        [System.Runtime.InteropServices.DllImport("User32.dll", EntryPoint="ShowWindow")]
        public static extern bool SW(System.IntPtr hWnd, Win32.SW nCmdShow);
    }
    public enum SW
    {
        HIDE               = 0,
        SHOW_NORMAL        = 1,
        SHOW_MINIMIZED     = 2,
        MAXIMIZE           = 3,
        SHOW_MAXIMIZED     = 3,
        SHOW_NO_ACTIVE     = 4,
        SHOW               = 5,
        MINIMIZE           = 6,
        SHOW_MIN_NO_ACTIVE = 7,
        SHOW_NA            = 8,
        RESTORE            = 9,
        SHOW_DEFAULT       = 10,
        FORCE_MINIMIZE     = 11
    }
}
'@

其中的所有内容都有效,例如:

[Win32.Functions]::SW((Get-Process -Name powershell).MainWindowHandle, [Win32.SW]::SHOW_DEFAULT)

但是,当我使用[Win32.SW]::HIDE时,我完全无法恢复该窗口。每个选项都失败,我得到false返回。文档中是否缺少某些内容或SW_HIDE的一项功能,使其无法恢复?

我的最终目标是在自我扩展.cmd - > .ps1脚本中创建一些WPF GUI,创建一个伪可执行文件并隐藏一个留下的PowerShell窗口(可能是根据脚本操作进行恢复。)

2 个答案:

答案 0 :(得分:1)

问题是 .MainWindowHandle在隐藏窗口时不再有效 [1] ,所以试图"取消隐藏"窗户失败了。

只需缓存 HWND并使用"取消隐藏"中的缓存值拨打:

# Also consider Get-Process -ID $PID, as in Stanislav's answer, to avoid ambiguity 
# if multiple PowerShell processes exist.
$hWnd = (Get-Process -Name PowerShell).MainWindowHandle

# ... hide window and do stuff

# Unhide, using the *cached* HWND:
[Win32.Functions]::SW($hWnd, [Win32.SW]::SHOW_DEFAULT)

暂且不说:ShowWindow() Windows API function(别名为SW)  返回一个不反映成功的布尔值,但该窗口是否先前已隐藏($False)($True)。

[1]属性类型为[System.IntPtr],隐藏窗口时其值为0

答案 1 :(得分:0)

我能看到的是你通过检查它的名字来指代过程。这可能有点棘手,因为可以运行具有相同名称的多个进程。因此,如果您要隐藏当前的PowerShell窗口并希望稍后恢复它,请使用其PID而不是名称来引用它。可以在下面找到可能用作示例的代码。

Add-Type -TypeDefinition @'
namespace Win32
{
    //https://msdn.microsoft.com/en-us/library/windows/desktop/ms633548(v=vs.85).aspx
    public static class Functions
    {
        [System.Runtime.InteropServices.DllImport("User32.dll", EntryPoint="ShowWindow")]
        public static extern bool SW(System.IntPtr hWnd, Win32.SW nCmdShow);
    }
    public enum SW
    {
        HIDE               = 0,
        SHOW_NORMAL        = 1,
        SHOW_MINIMIZED     = 2,
        MAXIMIZE           = 3,
        SHOW_MAXIMIZED     = 3,
        SHOW_NO_ACTIVE     = 4,
        SHOW               = 5,
        MINIMIZE           = 6,
        SHOW_MIN_NO_ACTIVE = 7,
        SHOW_NA            = 8,
        RESTORE            = 9,
        SHOW_DEFAULT       = 10,
        FORCE_MINIMIZE     = 11
    }
}
'@

. ([ScriptBlock]::Create('using namespace Win32'))

$mainWindowHandle = (Get-Process -ID $PID).MainWindowHandle
[Functions]::SW($mainWindowHandle, [SW]::HIDE)

# Sleep for 5 seconds to prove it working
Start-Sleep -Seconds 5

[Functions]::SW($mainWindowHandle, [SW]::SHOW_DEFAULT)

在运行之前请确保在最后一个命令后至少有一个空行换行,否则它将无法执行,并且您的窗口永远不会弹回;)

希望它有所帮助!