【问题标题】:Unable to restore windows hidden with ShowWindow无法恢复使用 ShowWindow 隐藏的窗口
【发布时间】:2018-08-13 20:27:04
【问题描述】:

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

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 窗口(可能会根据脚本进行恢复行动)。

【问题讨论】:

  • 你用什么代码来恢复你的窗口?
  • @rs232 主块下面的代码sn-p

标签: c# powershell pinvoke user32


【解决方案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

【讨论】:

    【解决方案2】:

    我可以看到您通过检查其名称来指代进程。这可能有点棘手,因为可以运行多个具有相同名称的进程。因此,如果您要隐藏当前的 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)
    

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

    希望对你有帮助!

    【讨论】:

    • 事实并非如此。只有一个进程在运行。
    • 使用$PID 的好主意,并且您的代码确实有效,但这是因为它使用 已保存 HWND 值,这与 OP 的代码不同(尝试访问 .MainWindowHandle而窗口被隐藏是问题)。据我所知,没有必要 . ([ScriptBlock]::Create('using namespace Win32')) - 也许令人惊讶的是,像往常一样简单地将 using namespace Win32 放在顶部就可以正常工作,即使类型是添加到 below 它。
    • @mklement0 奇怪的是它可以包含尚未定义的类型。很高兴知道
    • @TheIncorrigible1:我怀疑using namespace实际上并没有加载任何东西——它只是用于缩短类型引用的语法糖,所以它不必关心那个点是否存在引用的命名空间 - 不是编译语言,PowerShell可以摆脱这一点。然而,. ([ScriptBlock]::Create('using namespace Win32')) 技术是一项有趣的技术,因为它可以用于动态 更改隐式使用的命名空间,例如,可以在模拟场景中使用。请注意,它不适用于脚本块 literal.
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-28
    • 2019-06-23
    • 1970-01-01
    • 2020-12-03
    • 2020-07-10
    • 1970-01-01
    相关资源
    最近更新 更多