diff --git a/ILSpy/Commands/CreateDiagramContextMenuEntry.cs b/ILSpy/Commands/CreateDiagramContextMenuEntry.cs index 9f8adaa96..1e2240a0e 100644 --- a/ILSpy/Commands/CreateDiagramContextMenuEntry.cs +++ b/ILSpy/Commands/CreateDiagramContextMenuEntry.cs @@ -75,7 +75,7 @@ namespace ICSharpCode.ILSpy.TextView output.WriteLine(); var diagramHtml = Path.Combine(selectedPath, "index.html"); - output.AddButton(null, Resources.OpenExplorer, delegate { Process.Start("explorer", "/select,\"" + diagramHtml + "\""); }); + output.AddButton(null, Resources.OpenExplorer, delegate { ShellHelper.OpenFolderAndSelectItem(diagramHtml); }); output.WriteLine(); return output; }, ct), Properties.Resources.CreatingDiagram).Then(dockWorkspace.ShowText).HandleExceptions(); diff --git a/ILSpy/Commands/ExtractPackageEntryContextMenuEntry.cs b/ILSpy/Commands/ExtractPackageEntryContextMenuEntry.cs index 292b5aea9..e3870cc98 100644 --- a/ILSpy/Commands/ExtractPackageEntryContextMenuEntry.cs +++ b/ILSpy/Commands/ExtractPackageEntryContextMenuEntry.cs @@ -161,7 +161,7 @@ namespace ICSharpCode.ILSpy stopwatch.Stop(); output.WriteLine(Resources.GenerationCompleteInSeconds, stopwatch.Elapsed.TotalSeconds.ToString("F1")); output.WriteLine(); - output.AddButton(null, Resources.OpenExplorer, delegate { Process.Start("explorer", isFile ? $"/select,\"{path}\"" : $"\"{path}\""); }); + output.AddButton(null, Resources.OpenExplorer, delegate { if (isFile) ShellHelper.OpenFolderAndSelectItem(path); else ShellHelper.OpenFolder(path); }); output.WriteLine(); return output; }, ct)).Then(dockWorkspace.ShowText).HandleExceptions(); diff --git a/ILSpy/Commands/GeneratePdbContextMenuEntry.cs b/ILSpy/Commands/GeneratePdbContextMenuEntry.cs index c2e8f747f..a80f89ff9 100644 --- a/ILSpy/Commands/GeneratePdbContextMenuEntry.cs +++ b/ILSpy/Commands/GeneratePdbContextMenuEntry.cs @@ -112,7 +112,7 @@ namespace ICSharpCode.ILSpy stopwatch.Stop(); output.WriteLine(Resources.GenerationCompleteInSeconds, stopwatch.Elapsed.TotalSeconds.ToString("F1")); output.WriteLine(); - output.AddButton(null, Resources.OpenExplorer, delegate { Process.Start("explorer", "/select,\"" + fileName + "\""); }); + output.AddButton(null, Resources.OpenExplorer, delegate { ShellHelper.OpenFolderAndSelectItem(fileName); }); output.WriteLine(); return output; }, ct)).Then(dockWorkspace.ShowText).HandleExceptions(); @@ -214,7 +214,19 @@ namespace ICSharpCode.ILSpy output.WriteLine(); output.WriteLine(Resources.GenerationCompleteInSeconds, totalWatch.Elapsed.TotalSeconds.ToString("F1")); output.WriteLine(); - output.AddButton(null, Resources.OpenExplorer, delegate { Process.Start("explorer", "/select,\"" + targetFolder + "\""); }); + // Select all generated pdb files in explorer + var generatedFiles = assemblyArray + .Select(a => Path.Combine(targetFolder, WholeProjectDecompiler.CleanUpFileName(a.ShortName, ".pdb"))) + .Where(File.Exists) + .ToList(); + if (generatedFiles.Any()) + { + output.AddButton(null, Resources.OpenExplorer, delegate { ShellHelper.OpenFolderAndSelectItems(generatedFiles); }); + } + else + { + output.AddButton(null, Resources.OpenExplorer, delegate { ShellHelper.OpenFolder(targetFolder); }); + } output.WriteLine(); return output; }, ct)).Then(dockWorkspace.ShowText).HandleExceptions(); diff --git a/ILSpy/SolutionWriter.cs b/ILSpy/SolutionWriter.cs index 209cec9ef..1d2aa5d31 100644 --- a/ILSpy/SolutionWriter.cs +++ b/ILSpy/SolutionWriter.cs @@ -187,7 +187,7 @@ namespace ICSharpCode.ILSpy result.WriteLine(); result.WriteLine("Elapsed time: " + stopwatch.Elapsed.TotalSeconds.ToString("F1") + " seconds."); result.WriteLine(); - result.AddButton(null, "Open Explorer", delegate { Process.Start("explorer", "/select,\"" + solutionFilePath + "\""); }); + result.AddButton(null, "Open Explorer", delegate { ShellHelper.OpenFolderAndSelectItem(solutionFilePath); }); } return result; diff --git a/ILSpy/TextView/DecompilerTextView.cs b/ILSpy/TextView/DecompilerTextView.cs index f8da82342..703e40308 100644 --- a/ILSpy/TextView/DecompilerTextView.cs +++ b/ILSpy/TextView/DecompilerTextView.cs @@ -1204,7 +1204,7 @@ namespace ICSharpCode.ILSpy.TextView } } output.WriteLine(); - output.AddButton(null, Properties.Resources.OpenExplorer, delegate { Process.Start("explorer", "/select,\"" + fileName + "\""); }); + output.AddButton(null, Properties.Resources.OpenExplorer, delegate { ShellHelper.OpenFolderAndSelectItem(fileName); }); output.WriteLine(); tcs.SetResult(output); } diff --git a/ILSpy/TreeNodes/AssemblyTreeNode.cs b/ILSpy/TreeNodes/AssemblyTreeNode.cs index f67b86201..194c15ce1 100644 --- a/ILSpy/TreeNodes/AssemblyTreeNode.cs +++ b/ILSpy/TreeNodes/AssemblyTreeNode.cs @@ -696,7 +696,7 @@ namespace ICSharpCode.ILSpy.TreeNodes var path = node.LoadedAssembly.FileName; if (File.Exists(path)) { - GlobalUtils.ExecuteCommand("explorer.exe", $"/select,\"{path}\""); + ShellHelper.OpenFolderAndSelectItem(path); } } } diff --git a/ILSpy/Util/ShellHelper.cs b/ILSpy/Util/ShellHelper.cs new file mode 100644 index 000000000..f78909b41 --- /dev/null +++ b/ILSpy/Util/ShellHelper.cs @@ -0,0 +1,152 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Runtime.InteropServices; +using System.Linq; +using System.Collections.Generic; + +namespace ICSharpCode.ILSpy.Util +{ + static class ShellHelper + { + [DllImport("shell32.dll", CharSet = CharSet.Unicode)] + static extern int SHParseDisplayName([MarshalAs(UnmanagedType.LPWStr)] string pszName, IntPtr pbc, out IntPtr ppidl, uint sfgaoIn, out uint psfgaoOut); + + [DllImport("shell32.dll")] + static extern int SHOpenFolderAndSelectItems(IntPtr pidlFolder, uint cidl, [MarshalAs(UnmanagedType.LPArray)] IntPtr[] apidl, uint dwFlags); + + [DllImport("shell32.dll")] + static extern IntPtr ILFindLastID(IntPtr pidl); + + [DllImport("ole32.dll")] + static extern void CoTaskMemFree(IntPtr pv); + + public static void OpenFolder(string folderPath) + { + try + { + if (string.IsNullOrEmpty(folderPath)) + return; + if (!Directory.Exists(folderPath)) + return; + + IntPtr folderPidl = IntPtr.Zero; + uint attrs; + int hr = SHParseDisplayName(folderPath, IntPtr.Zero, out folderPidl, 0, out attrs); + if (hr == 0 && folderPidl != IntPtr.Zero) + { + SHOpenFolderAndSelectItems(folderPidl, 0, null, 0); + CoTaskMemFree(folderPidl); + } + else + { + // fallback + Process.Start(new ProcessStartInfo { FileName = folderPath, UseShellExecute = true }); + } + } + catch + { + // ignore + } + } + + public static void OpenFolderAndSelectItem(string path) + { + // Reuse the multi-item implementation for single item selection to avoid duplication. + try + { + if (string.IsNullOrEmpty(path)) + return; + if (Directory.Exists(path)) + { + OpenFolder(path); + return; + } + + if (!File.Exists(path)) + return; + + OpenFolderAndSelectItems(new[] { path }); + } + catch + { + // ignore + } + } + + public static void OpenFolderAndSelectItems(IEnumerable paths) + { + try + { + if (paths == null) + return; + // Group by containing folder + var files = paths.Where(p => !string.IsNullOrEmpty(p) && File.Exists(p)).ToList(); + if (files.Count == 0) + return; + + var groups = files.GroupBy(p => Path.GetDirectoryName(p)); + foreach (var group in groups) + { + string folder = group.Key; + if (string.IsNullOrEmpty(folder) || !Directory.Exists(folder)) + continue; + + IntPtr folderPidl = IntPtr.Zero; + uint attrs; + int hrFolder = SHParseDisplayName(folder, IntPtr.Zero, out folderPidl, 0, out attrs); + if (hrFolder != 0 || folderPidl == IntPtr.Zero) + { + // fallback: open folder normally + OpenFolder(folder); + continue; + } + + var itemPidlAllocs = new List(); + var relativePidls = new List(); + try + { + foreach (var file in group) + { + IntPtr itemPidl = IntPtr.Zero; + int hrItem = SHParseDisplayName(file, IntPtr.Zero, out itemPidl, 0, out attrs); + if (hrItem == 0 && itemPidl != IntPtr.Zero) + { + IntPtr relative = ILFindLastID(itemPidl); + if (relative != IntPtr.Zero) + { + relativePidls.Add(relative); + itemPidlAllocs.Add(itemPidl); + continue; + } + } + if (itemPidl != IntPtr.Zero) + CoTaskMemFree(itemPidl); + } + + if (relativePidls.Count > 0) + { + SHOpenFolderAndSelectItems(folderPidl, (uint)relativePidls.Count, relativePidls.ToArray(), 0); + } + else + { + // nothing to select - open folder + OpenFolder(folder); + } + } + finally + { + foreach (var p in itemPidlAllocs) + CoTaskMemFree(p); + if (folderPidl != IntPtr.Zero) + CoTaskMemFree(folderPidl); + } + } + } + catch + { + // ignore + } + } + } +}