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

PowerShell调用OpenFileDialog时能否修改对话框左上角的图标

原生的System.Windows.Forms.OpenFileDialog类确实没有直接暴露设置左上角窗口图标的公开属性,我们可以通过调用Win32 API、匹配对话框窗口句柄后手动注入图标的方式实现需求,具体实现方案如下:

完整修改后代码

Function Invoke-OpenFileDialog {

  Param (
    [Parameter(Mandatory=$true, Position=0)] [string] $Title,
    [Parameter(Mandatory=$true, Position=1)] [string] $InitialDirectory,
    [Parameter(Mandatory=$true, Position=2)] [string] $Filter,
    [Parameter(Mandatory=$false)] [string] $IconPath = "" # 新增参数:自定义图标路径,支持.ico格式
    )

  Add-Type -AssemblyName System.Windows.Forms
  Add-Type -AssemblyName System.Drawing
  # 导入Win32 API声明
  Add-Type @"
  using System;
  using System.Runtime.InteropServices;
  public class Win32API {
    public const uint WM_SETICON = 0x0080;
    public const int ICON_SMALL = 0;
    public const int ICON_BIG = 1;

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

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
  }
"@

  if ($InitialDirectory -ne "") {
    if (!(Test-Path -LiteralPath $InitialDirectory -PathType Container)) {
      $InitialDirectory = ([System.IO.FileInfo]$InitialDirectory).DirectoryName
    }
  }

  $OpenFileDialog                  = New-Object System.Windows.Forms.OpenFileDialog
  $OpenFileDialog.Filter           = $Filter
  $OpenFileDialog.InitialDirectory = $InitialDirectory
  $OpenFileDialog.Title            = $Title

  # 启动异步任务等待对话框弹出后设置图标
  if (-not [string]::IsNullOrEmpty($IconPath) -and (Test-Path $IconPath -PathType Leaf)) {
    $null = Start-Job -ScriptBlock {
      param($dialogTitle, $iconPath)
      Add-Type -AssemblyName System.Drawing
      Add-Type @"
      using System;
      using System.Runtime.InteropServices;
      public class Win32API {
        public const uint WM_SETICON = 0x0080;
        public const int ICON_SMALL = 0;
        public const int ICON_BIG = 1;

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

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
      }
"@
      # 最多等待3秒防止卡死
      for ($i = 0; $i -lt 30; $i++) {
        $hwnd = [Win32API]::FindWindow("#32770", $dialogTitle) # #32770是标准文件对话框的类名,提高匹配准确率
        if ($hwnd -ne [IntPtr]::Zero) {
          $icon = [System.Drawing.Icon]::ExtractAssociatedIcon($iconPath)
          [Win32API]::SendMessage($hwnd, [Win32API]::WM_SETICON, [IntPtr][Win32API]::ICON_SMALL, $icon.Handle)
          [Win32API]::SendMessage($hwnd, [Win32API]::WM_SETICON, [IntPtr][Win32API]::ICON_BIG, $icon.Handle)
          break
        }
        Start-Sleep -Milliseconds 100
      }
    } -ArgumentList $Title, $IconPath
  }

  $result = $OpenFileDialog.ShowDialog()
  $OpenFileDialog.Dispose()

  if ($result -eq 'OK') {
    return $OpenFileDialog.FileName
  }
  else { return "" }
}

$title = 'OpenFileDialog Title'
$initialDirectory = ([System.IO.FileInfo]"C:\Users\").DirectoryName
$filter = 'All files (*.*)| *.*'
# 替换为你自己的ico文件路径,也可以填exe路径自动提取关联图标
$customIconPath = "C:\path\to\your\icon.ico"

$filePicked = Invoke-OpenFileDialog -Title $title -InitialDirectory $initialDirectory -Filter $filter -IconPath $customIconPath

# 结果校验逻辑保持不变
if ($filePicked -ne "") {
  $filePicked
  Write-Host 'File Picked...'
}
else {
  Write-Host 'File Not Picked...'
}

实现说明

  • 核心逻辑是通过FindWindow匹配文件对话框的窗口类名和标题,拿到窗口句柄后发送WM_SETICON系统消息设置自定义图标
  • 匹配时加了标准文件对话框的类名#32770,避免误匹配到其他同名窗口
  • 异步循环最多等待3秒,避免对话框弹出异常导致任务卡死
  • 支持直接传入.ico文件路径,也可以传入exe/dll路径自动提取关联的程序图标

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.13 20:39:01