如何从命令行使图标显示在任务栏的通知区域?

如何从命令行使图标显示在任务栏的通知区域?

我正在尝试编写 Windows 任务栏上通知区域的配置脚本。

Windows 有一个 GUI 可以执行此操作:

在此处输入图片描述

这会将图标放在通知区域,如下所示:

在此处输入图片描述

如何从命令行(cmd.exe 或 Powershell)完成此操作?

答案1

好吧,我无法再简单了。这些是命令提示符命令。我正在使用 filezilla ftp 客户端 (https://filezilla-project.org/) 作为示例。如果您没有,请下载并安装它!这样您就可以看到它的实际效果,并且它确实有效。要关闭图标:

REG ADD HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Notifications\Settings\FileZilla.Client.AppID /v 已启用 /t REG_DWORD /d 1 /f

要重新打开图标:REG DELETE HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Notifications\Settings\FileZilla.Client.AppID /v Enabled /f

您可以在注册表的通知部分中通过浏览到以下位置来编辑这些命令:HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Notifications\Settings\

并将我的命令的这一部分替换为您要编辑的通知的键名“FileZilla.Client.AppID”

答案2

按住或右键单击任务栏上的任何空白处,然后选择任务栏设置。在任务栏角落图标下:选择您想要在任务栏上看到的任何图标的“开”。

答案3

这不是一个完整的答案,而是我(OP)从其他人那里收到的有关该问题的信息 - 我发布此信息是为了让其他看到此问题的人受益:

您想要做的是以编程方式将图标添加到系统托盘。(我假设您希望图标出现在 Wifi、电池和音量图标旁边。)默认情况下,命令提示符无法访问系统托盘。因此,您必须使用 ps1 文件和 bat 文件来执行。您的命令必须关闭 explorer,然后在注册表更改后重新启动它。这是可行的,但相当复杂。

但作为一般指南,您希望 ps1 文件包含 2 个项目,即图标名称和分配给显示图标和通知的值 2。然后它必须更改 TrayNotification 注册表项中的 IconsStream 变量。这相当复杂,但这是您想要采取的总体方向。

或者,您可以使用 Shell_NotifyIcon 并将 dwMessage 指定为 NIM_ADD。但这种方法要求您了解 C++ 才能使用 Shell_NotifyIcon。

此外,另一个帖子讨论了同样的问题(也没有解决方案;抱歉,我在发布新问题之前没有发现这一点):使用命令行显示/隐藏 Windows 通知区域上的特定图标

就我个人而言,我认为这太复杂了,现在我放弃它了。

有人可能会制作一个有用的共享软件或开源命令行程序来执行此操作(但我不是)。

答案4

这里有两个选项。我已经成功测试了 #1 (reg.exe),但尚未测试 #2 (powershell):

(1)您可以从注册表中导出每个所需布局的 HKCUTrayNotify\IconStreams密钥,然后在需要切换时重新导入一个(并重新启动资源管理器)。例如:

(a)按您想要的方式设置系统托盘,然后:

reg export "HKEY_CURRENT_USER\SOFTWARE\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\TrayNotify" "TrayNotify1.reg"

然后,“TrayNotify1.reg”(UTF-16LE BOM)包含包含IconStream您设置的键。它还包含您可能不需要的其他键。

(b)按照您想要的第二种方式设置系统托盘并再次导出,但这次导出到不同的文件,如“TrayNotify2.reg”。

(c)切换回第一个布局,例如:

reg import "TrayNotify1.reg"
start /wait TASKKILL /F /IM explorer.exe && start explorer.exe

(2)或者你可以使用这些不错的PowerShell 函数indented-automation/SystemTray.ps1控制系统托盘中图标的可见性,包括 ROT13 编码。注意:我还没有测试过此代码。

# https://gist.github.com/indented-automation/8035cdbe21ff38ab8eb79bb4be84d2e6
# Functions to allow changes to the visibility of icons in the system tray.
# indented-automation/SystemTray.ps1

enum Visibility : byte {
    Default = 0
    Hide    = 1
    Show    = 2
}

function Convert-CaesarCipher {
    <#
    .SYNOPSIS
        Convert a string to and from a Caesar cipher (ROT-13) encoding.
    .DESCRIPTION
        Convert a string to and from a Caesar cipher (ROT-13) encoding.
    #>

    [CmdletBinding()]
    param (
        # The string to encode or decode.
        [Parameter(Mandatory, ValueFromPipeline)]
        [string]$String
    )

    process {
        $chars = foreach ($char in $string.ToCharArray()) {
            if ($char -notmatch '[a-z]') {
                $char
                continue
            }

            $decrement = ($char -ge 'A' -and $char -le 'Z' -and $char -gt 'M') -or
                ($char -ge 'a' -and $char -le 'z' -and $char -gt 'm')

            if ($decrement) {
                [int]$char - 13
            } else {
                [int]$char + 13
            }
        }
        [string]::new([char[]]$chars)
    }
}

function Resolve-KnownFolder {
    <#
    .SYNOPSIS
        Resolve GUID known folder values to full paths.
    .DESCRIPTION
        Resolve GUID known folder values to full paths.
    #>

    [CmdletBinding()]
    param (
        # A path containing a GUID to resolve.
        [Parameter(ValueFromPipeline)]
        [string]$Path
    )

    begin {
        if (-not ('KnownFolder' -as [Type])) {
            Add-Type -TypeDefinition '
            using System;
            using System.Runtime.InteropServices;
            
            internal class UnsafeNativeMethods
            {
                [DllImport("shell32.dll")]
                internal static extern int SHGetKnownFolderPath(
                    [MarshalAs(UnmanagedType.LPStruct)] Guid rfid,
                    uint dwFlags,
                    IntPtr hToken,
                    out IntPtr ppszPath
                );
            }
            
            public class KnownFolder {
                public static string GetPath(Guid guid)
                {
                    IntPtr ppszPath = IntPtr.Zero;
                    UnsafeNativeMethods.SHGetKnownFolderPath(
                        guid,
                        0,
                        IntPtr.Zero,
                        out ppszPath
                    );
                    string path = Marshal.PtrToStringUni(ppszPath);
                    Marshal.FreeCoTaskMem(ppszPath);
            
                    return path;
                }
            }
            '
        }
    }
    
    process {
        $pathElements = $Path -split '[\\/]'
        if ($guid = $pathElements[0] -as [Guid]) {
            $pathElements[0] = [KnownFolder]::GetPath($guid)
            $Path = [System.IO.Path]::Combine($pathElements)
        }
        $Path
    }
}

function Get-SystemTrayIcon {
    <#
    .SYNOPSIS
        Get system tray icon visibility.
    
    .DESCRIPTION
        Get system tray icon visibility using the IconStreams value in the registry.
    #>

    [CmdletBinding()]
    param (
        # The path for the system tray icon. By default app paths are displayed.
        [string]$Path = '*'
    )

    $registryPath = 'HKCU:\Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\TrayNotify'
    $iconStreams = Get-ItemPropertyValue -Path $registryPath -Name IconStreams
    # The flag for visibility appears at offset 528
    $systemTrayToggleOffset = 528

    # The iconStreams array has a 20 byte header, followed by 1640 byte records describing each icon.
    for ($i = 20; $i -lt $iconStreams.Count; $i += 1640) {
        # The path is Unicode encoded and null terminated.
        $iconPathBytes = for (($j = 0), ($isChar = $true); $isChar; $j += 2) {
            $left = $iconStreams[$i + $j]
            $right = $iconStreams[$i + $j + 1]

            $isChar = $left -ne 0 -or $right -ne 0
            if ($isChar) {
                $left, $right
            }
        }
        $iconPath = [System.Text.Encoding]::Unicode.GetString([byte[]]$iconPathBytes) | Convert-CaesarCipher

        if ($iconPath -like $Path) {
            [PSCustomObject]@{
                PSTypeName = 'IconStreamsRecord'
                Visibility = [Visibility]$iconStreams[$i + $systemTrayToggleOffset]
                Offset     = $i
                Path       = Resolve-KnownFolder $iconPath
            }
        }
    }
}

function Backup-SystemTrayIcon {
    <#
    .SYNOPSIS
        Create a backup of the System Tray Icon configuration (IconStreams).
    .DESCRIPTION
        Create a backup of the System Tray Icon configuration (IconStreams).
    #>

    [CmdletBinding()]
    param ( )

    $registryPath = 'HKCU:\Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\TrayNotify'
    $value = Get-ItemPropertyValue $registryPath -Name IconStreams
    New-ItemProperty -Path $registryPath -Name IconStreams_Backup -Value $value -Force
}

function Restore-SystemTrayIcon {
    <#
    .SYNOPSIS
        Restore an existing backup of the System Tray Icon configuration (IconStreams).
    .DESCRIPTION
        Restore an existing backup of the System Tray Icon configuration (IconStreams).
    #>

    [CmdletBinding()]
    param ( )

    $registryPath = 'HKCU:\Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\TrayNotify'
    $value = Get-ItemPropertyValue $registryPath -Name IconStreams_Backup
    if ($value) {
        Set-ItemProperty -Path $registryPath -Name IconStreams -Value $value
    } else {
        Write-Error 'IconStreams backup does not exist!'
    }
}

function Set-SystemTrayIcon {
    <#
    .SYNOPSIS
        Set system tray icon visibility.
    
    .DESCRIPTION
        Set system tray icon visibility using the IconStreams value in the registry.
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory, ParameterSetName = 'ByPath')]
        [SupportsWildcards()]
        [string]$Path,

        [Parameter(Mandatory, ValueFromPipeline, ParameterSetName = 'FromPipeline')]
        [PSTypeName('IconStreamsRecord')]
        [object]$InputObject,

        [Parameter(Mandatory)]
        [Visibility]$Visibility
    )

    begin {
        $registryPath = 'HKCU:\Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\TrayNotify'
        $systemTrayToggleOffset = 528

        if ($PSCmdlet.ParameterSetName -eq 'Path') {
            Get-SystemTrayIcon -Path $Path | Set-SystemTrayIcon -Visibility $Visibility
            return
        }

        $iconStreams = Get-ItemPropertyValue -Path $registryPath -Name IconStreams
        $shouldUpdate = $false
    }

    process {
        if ($PSCmdlet.ParameterSetName -eq 'ByPath') {
            return
        }

        if ($InputObject.Visibility -ne $Visibility) {
            $shouldUpdate = $true
            $iconStreams[$InputObject.Offset + $systemTrayToggleOffset] = $Visibility.value__
        }
    }

    end {
        if ($PSCmdlet.ParameterSetName -eq 'ByPath') {
            return
        }
        if ($shouldUpdate) {
            Set-ItemProperty -Path $registryPath -Name IconStreams -Value $iconStreams
        }
    }
}

你可以在 Github 上找到更多 PowerShell 代码,例如nodear/Awesome ManageTray.ps1stevencohn/WindowsPowerShell 设置 NotifyIcon.ps1

Tim Mintner 也在 2011 年发表了一篇旧博客文章,其中他对格式进行部分逆向工程IconStreams 的

HKCU\Software\Classes\Local Settings\Microsoft\Windows\CurrentVersion\TrayNotify
IconStreams
REG_BINARY
20 byte header followed by 
X number of 1640 byte items where X is the number of items that have notification settings. 
Each 1640 byte block is comprised of at least (one of the sections is not fully decoded so it may be made up of 2 or more sections) 5 fixed byte width sections as follows:

- 528 bytes – Path to the executable
- 4 bytes – Notification visibility setting
- 512 bytes – Last visible tooltip
- 592 bytes – Unknown (Seems to have a second tool-tip embedded in it but the starting position in the block changes)
- 4 bytes – ID?

相关内容