Код: Выделить всё
[ComImport, Guid("9BA05972-F6A8-11CF-A442-00A0C90A8F39"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IShellWindows : IEnumerable
{
int Count { get; }
object Item(object index);
new IEnumerator GetEnumerator();
}
public void CloseExplorerWindowsForPath(string path)
{
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return;
_logger.LogInformation("Closing Explorer windows for path: {}", path);
// ShellWindows is an STA COM object. Calling it from the MTA thread pool
// (used by gRPC) causes Quit() to be silently ignored by Explorer because
// the cross-apartment message is never pumped. A dedicated STA thread is required.
Exception? threadException = null;
var staThread = new Thread(() =>
{
var shellType = Type.GetTypeFromCLSID(new Guid("9BA05972-F6A8-11CF-A442-00A0C90A8F39"));
if (shellType == null) return;
dynamic shellWindows = Activator.CreateInstance(shellType)!;
try
{
var toClose = new List();
foreach (dynamic window in shellWindows)
{
try
{
string location = window.LocationURL;
// Convertir l'URL file:/// en chemin normal
string windowPath = Uri.UnescapeDataString(
new Uri(location).LocalPath);
_logger.LogDebug("{} against {}", windowPath, path);
// Fermer si le chemin correspond ou est un sous-dossier
if (windowPath.StartsWith(path, StringComparison.OrdinalIgnoreCase))
{
_logger.LogDebug("Adding window with path {} to close list.", windowPath);
toClose.Add(window);
}
}
catch { /* Ignorer les fenêtres inaccessibles */ }
}
foreach (dynamic window in toClose)
{
try { window.Quit(); }
catch (Exception e) { _logger.LogDebug(e.Message); }
}
}
catch (Exception ex)
{
threadException = ex;
}
});
staThread.SetApartmentState(ApartmentState.STA);
staThread.Start();
staThread.Join();
if (threadException is not null)
throw threadException;
}