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
相关产品推荐
相关产品推荐

