You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PowerShell脚本实现窗口最小化/关闭时隐藏至系统托盘

实现PowerShell窗口关闭/最小化到系统托盘的解决方案

核心思路

要实现需求,关键是通过Win32 API拦截窗口消息:

  • 拦截WM_CLOSE消息:不执行默认的关闭进程操作,改为隐藏窗口并保留托盘图标
  • 拦截WM_SYSCOMMAND中的SC_MINIMIZE命令:不将窗口缩到任务栏,直接隐藏窗口
  • 结合已有的托盘图标与菜单,保证显示/隐藏功能联动

完整实现代码

# 导入必要的Win32 API函数
Add-Type @"
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

public class WindowHook {
    // 窗口消息常量
    public const int WM_CLOSE = 0x0010;
    public const int WM_SYSCOMMAND = 0x0112;
    public const int SC_MINIMIZE = 0xF020;
    public const int GWL_WNDPROC = -4;

    // Win32 API声明
    [DllImport("user32.dll")]
    public static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, WndProc newProc);

    [DllImport("user32.dll")]
    public static extern IntPtr CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

    [DllImport("user32.dll")]
    public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

    [DllImport("kernel32.dll")]
    public static extern IntPtr GetConsoleWindow();

    // 窗口委托
    public delegate IntPtr WndProc(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

    public static WndProc prevWndProc;
    public static IntPtr consoleHandle;

    // 自定义窗口过程
    public static IntPtr CustomWndProc(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam) {
        switch (Msg) {
            // 处理关闭按钮点击
            case WM_CLOSE:
                // 隐藏窗口,不关闭进程
                ShowWindow(consoleHandle, 0); // 0 = SW_HIDE
                return IntPtr.Zero; // 阻止默认关闭行为
            // 处理最小化命令
            case WM_SYSCOMMAND:
                if ((wParam.ToInt32() & 0xFFF0) == SC_MINIMIZE) {
                    // 隐藏窗口,不缩到任务栏
                    ShowWindow(consoleHandle, 0);
                    return IntPtr.Zero; // 阻止默认最小化行为
                }
                break;
        }
        // 其他消息交给原窗口过程处理
        return CallWindowProc(prevWndProc, hWnd, Msg, wParam, IntPtr.Zero);
    }

    // 初始化窗口钩子
    public static void HookConsoleWindow() {
        consoleHandle = GetConsoleWindow();
        prevWndProc = (WndProc)Marshal.GetDelegateForFunctionPointer(
            SetWindowLongPtr(consoleHandle, GWL_WNDPROC, CustomWndProc),
            typeof(WndProc)
        );
    }
}
"@

# 初始化窗口钩子,拦截消息
[WindowHook]::HookConsoleWindow()

# 替换为你已有的系统托盘图标与菜单代码
# 示例托盘菜单框架(可直接替换为你的现有代码)
Add-Type -AssemblyName System.Windows.Forms
$notifyIcon = New-Object System.Windows.Forms.NotifyIcon
$notifyIcon.Icon = [System.Drawing.Icon]::ExtractAssociatedIcon((Get-Process -Id $PID).Path)
$notifyIcon.Visible = $true

# 创建菜单
$contextMenu = New-Object System.Windows.Forms.ContextMenuStrip
$showItem = New-Object System.Windows.Forms.ToolStripMenuItem("显示窗口")
$showItem.Add_Click({
    # 显示窗口并恢复正常状态
    [WindowHook]::ShowWindow([WindowHook]::consoleHandle, 5) # 5 = SW_SHOW
})
$exitItem = New-Object System.Windows.Forms.ToolStripMenuItem("退出")
$exitItem.Add_Click({
    # 退出时清理托盘图标并终止进程
    $notifyIcon.Visible = $false
    $notifyIcon.Dispose()
    exit
})
$contextMenu.Items.Add($showItem)
$contextMenu.Items.Add($exitItem)
$notifyIcon.ContextMenuStrip = $contextMenu

# 保持脚本运行,防止进程退出
$null = [System.Windows.Forms.Application]::Run()

关键代码说明

  • 窗口消息拦截:通过SetWindowLongPtr替换默认窗口过程,在CustomWndProc中拦截目标消息,调用ShowWindow隐藏窗口而非执行默认操作。
  • 托盘菜单联动:点击“显示窗口”时调用ShowWindow恢复窗口显示;点击“退出”时清理托盘资源并终止进程。
  • 脚本存活保障:用[System.Windows.Forms.Application]::Run()启动消息循环,避免PowerShell脚本执行完毕后进程自动终止。

注意事项

  • 若脚本以管理员权限运行,需确认窗口句柄获取逻辑正常(管理员窗口的句柄隔离可能导致差异)。
  • 任务计划程序配置时,可设置“不管用户是否登录都要运行”,并根据需求选择是否勾选“不启动命令窗口”。
  • 若已有托盘代码结构不同,只需保留WindowHook类部分,将托盘菜单的“显示”按钮逻辑替换为调用[WindowHook]::ShowWindow([WindowHook]::consoleHandle, 5)即可。

内容的提问来源于stack exchange,提问作者Gangula

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 00:22:38