Reuse open Explorer window when selecting files

This commit is contained in:
2026-05-21 13:33:25 +08:00
parent 25a7458db3
commit e438386e68

View File

@@ -4,6 +4,7 @@ using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.RegularExpressions;
@@ -33,6 +34,19 @@ namespace DrillTools
private bool _isStartupDrillTapeFile;
private bool _canGeneratePpDrillTape;
private const int SwRestore = 9;
private const int SvsiSelect = 0x1;
private const int SvsiDeselectOthers = 0x4;
private const int SvsiEnsureVisible = 0x8;
private const int SvsiFocused = 0x10;
private const int SelectFileFlags = SvsiSelect | SvsiDeselectOthers | SvsiEnsureVisible | SvsiFocused;
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
/// <summary>
/// 刀具列表
/// </summary>
@@ -1223,15 +1237,11 @@ M30";
return;
}
// 使用 explorer.exe 的 /select 参数来打开文件资源管理器并选中文件
ProcessStartInfo startInfo = new ProcessStartInfo
{
FileName = "explorer.exe",
Arguments = $"/select,\"{filePath}\"",
UseShellExecute = true
};
string fullFilePath = Path.GetFullPath(filePath);
if (TrySelectFileInOpenExplorerWindow(fullFilePath))
return;
Process.Start(startInfo);
OpenNewExplorerWindowAndSelectFile(fullFilePath);
}
catch (Exception ex)
{
@@ -1239,6 +1249,138 @@ M30";
}
}
private static bool TrySelectFileInOpenExplorerWindow(string filePath)
{
string? directory = Path.GetDirectoryName(filePath);
if (string.IsNullOrWhiteSpace(directory))
return false;
string normalizedDirectory = NormalizeDirectoryPath(directory);
Type? shellType = Type.GetTypeFromProgID("Shell.Application");
if (shellType == null)
return false;
object? shell = null;
try
{
shell = Activator.CreateInstance(shellType);
if (shell == null)
return false;
dynamic shellApplication = shell;
foreach (dynamic window in shellApplication.Windows())
{
if (!IsExplorerWindow(window))
continue;
string? windowDirectory = GetExplorerWindowDirectory(window);
if (string.IsNullOrWhiteSpace(windowDirectory)
|| !string.Equals(NormalizeDirectoryPath(windowDirectory), normalizedDirectory, StringComparison.OrdinalIgnoreCase))
{
continue;
}
if (SelectFileInExplorerWindow(window, filePath))
return true;
}
}
catch
{
return false;
}
finally
{
if (shell != null && Marshal.IsComObject(shell))
Marshal.FinalReleaseComObject(shell);
}
return false;
}
private static bool IsExplorerWindow(dynamic window)
{
try
{
string fullName = Convert.ToString(window.FullName) ?? string.Empty;
return string.Equals(Path.GetFileName(fullName), "explorer.exe", StringComparison.OrdinalIgnoreCase);
}
catch
{
return false;
}
}
private static string? GetExplorerWindowDirectory(dynamic window)
{
try
{
string path = Convert.ToString(window.Document.Folder.Self.Path) ?? string.Empty;
if (!string.IsNullOrWhiteSpace(path))
return path;
}
catch
{
// 回退到 LocationURL兼容部分 Explorer 窗口取不到 Folder.Self.Path 的情况。
}
try
{
string locationUrl = Convert.ToString(window.LocationURL) ?? string.Empty;
if (Uri.TryCreate(locationUrl, UriKind.Absolute, out Uri? uri) && uri.IsFile)
return uri.LocalPath;
}
catch
{
return null;
}
return null;
}
private static bool SelectFileInExplorerWindow(dynamic window, string filePath)
{
try
{
dynamic document = window.Document;
dynamic fileItem = document.Folder.ParseName(Path.GetFileName(filePath));
if (fileItem == null)
{
document.Refresh();
fileItem = document.Folder.ParseName(Path.GetFileName(filePath));
}
if (fileItem == null)
return false;
document.SelectItem(fileItem, SelectFileFlags);
IntPtr handle = new IntPtr(Convert.ToInt64(window.HWND));
ShowWindow(handle, SwRestore);
SetForegroundWindow(handle);
return true;
}
catch
{
return false;
}
}
private static string NormalizeDirectoryPath(string path)
{
return Path.GetFullPath(path).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
}
private static void OpenNewExplorerWindowAndSelectFile(string filePath)
{
ProcessStartInfo startInfo = new ProcessStartInfo
{
FileName = "explorer.exe",
Arguments = $"/select,\"{filePath}\"",
UseShellExecute = true
};
Process.Start(startInfo);
}
/// <summary>
/// 生成刀具直径列表文件
/// </summary>