From e438386e6886cc5fde3ccec897ccb4f34a7454be Mon Sep 17 00:00:00 2001
From: "Mr.Xia" <1424473282@qq.com>
Date: Thu, 21 May 2026 13:33:25 +0800
Subject: [PATCH] Reuse open Explorer window when selecting files
---
MainWindowViewModel.cs | 158 ++++++++++++++++++++++++++++++++++++++---
1 file changed, 150 insertions(+), 8 deletions(-)
diff --git a/MainWindowViewModel.cs b/MainWindowViewModel.cs
index af21545..e936723 100644
--- a/MainWindowViewModel.cs
+++ b/MainWindowViewModel.cs
@@ -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);
+
///
/// 刀具列表
///
@@ -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);
+ }
+
///
/// 生成刀具直径列表文件
///