Browse Source

Replace direct calls to `explorer.exe` with the Shell API to prevent spawning an `explorer.exe` process that doesn't exit automatically on every call.

pull/3619/head
sonyps5201314 1 month ago
parent
commit
1f13b80a5f
  1. 2
      ILSpy/Commands/CreateDiagramContextMenuEntry.cs
  2. 2
      ILSpy/Commands/ExtractPackageEntryContextMenuEntry.cs
  3. 16
      ILSpy/Commands/GeneratePdbContextMenuEntry.cs
  4. 2
      ILSpy/SolutionWriter.cs
  5. 2
      ILSpy/TextView/DecompilerTextView.cs
  6. 2
      ILSpy/TreeNodes/AssemblyTreeNode.cs
  7. 152
      ILSpy/Util/ShellHelper.cs

2
ILSpy/Commands/CreateDiagramContextMenuEntry.cs

@ -75,7 +75,7 @@ namespace ICSharpCode.ILSpy.TextView @@ -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();

2
ILSpy/Commands/ExtractPackageEntryContextMenuEntry.cs

@ -161,7 +161,7 @@ namespace ICSharpCode.ILSpy @@ -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();

16
ILSpy/Commands/GeneratePdbContextMenuEntry.cs

@ -112,7 +112,7 @@ namespace ICSharpCode.ILSpy @@ -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 @@ -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();

2
ILSpy/SolutionWriter.cs

@ -187,7 +187,7 @@ namespace ICSharpCode.ILSpy @@ -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;

2
ILSpy/TextView/DecompilerTextView.cs

@ -1204,7 +1204,7 @@ namespace ICSharpCode.ILSpy.TextView @@ -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);
}

2
ILSpy/TreeNodes/AssemblyTreeNode.cs

@ -696,7 +696,7 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -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);
}
}
}

152
ILSpy/Util/ShellHelper.cs

@ -0,0 +1,152 @@ @@ -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<string> 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<IntPtr>();
var relativePidls = new List<IntPtr>();
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
}
}
}
}
Loading…
Cancel
Save