Skip to content

Commit aa44ab2

Browse files
authored
[Default explorer] Open control panel in existing window (#7456)
1 parent 05a9894 commit aa44ab2

File tree

2 files changed

+269
-6
lines changed

2 files changed

+269
-6
lines changed

src/Files.Launcher/Program.cs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -245,16 +245,12 @@ private static bool HandleCommandLineArgs()
245245
{
246246
TerminateProcess((int)localSettings.Values["pid"]);
247247

248-
using Process process = new Process();
249-
process.StartInfo.UseShellExecute = true;
250-
process.StartInfo.FileName = "explorer.exe";
251-
process.StartInfo.CreateNoWindow = false;
252-
process.StartInfo.Arguments = (string)localSettings.Values["ShellCommand"];
253-
process.Start();
248+
Win32API.OpenFolderInExistingShellWindow((string)localSettings.Values["ShellCommand"]);
254249

255250
return true;
256251
}
257252
}
253+
258254
return false;
259255
}
260256

src/Files.Launcher/Win32API.cs

Lines changed: 267 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,9 +567,276 @@ public static Win32Window FromLong(long hwnd)
567567
}
568568
}
569569

570+
public static void OpenFolderInExistingShellWindow(string folderPath)
571+
{
572+
var opened = false;
573+
574+
if (Ole32.CoCreateInstance(typeof(Shell32.ShellWindows).GUID, null, Ole32.CLSCTX.CLSCTX_LOCAL_SERVER, typeof(Shell32.IShellWindows).GUID, out var shellWindowsUnk).Succeeded)
575+
{
576+
var shellWindows = (Shell32.IShellWindows)shellWindowsUnk;
577+
578+
using var controlPanelCategoryView = new Vanara.Windows.Shell.ShellItem("::{26EE0668-A00A-44D7-9371-BEB064C98683}");
579+
580+
for (int i = 0; i < shellWindows.Count; i++)
581+
{
582+
var item = shellWindows.Item(i);
583+
var webBrowser = (Win32API.IWebBrowserApp)item;
584+
if (webBrowser != null)
585+
{
586+
var serv = (Shell32.IServiceProvider)webBrowser;
587+
if (serv != null)
588+
{
589+
if (serv.QueryService(Shell32.SID_STopLevelBrowser, typeof(Shell32.IShellBrowser).GUID, out var ppv).Succeeded)
590+
{
591+
var pUnk = Marshal.GetObjectForIUnknown(ppv);
592+
var shellBrowser = (Shell32.IShellBrowser)pUnk;
593+
using var targetFolder = Extensions.IgnoreExceptions(() => new Vanara.Windows.Shell.ShellItem(folderPath));
594+
if (targetFolder != null)
595+
{
596+
if (shellBrowser.QueryActiveShellView(out var shellView).Succeeded)
597+
{
598+
var folderView = (Shell32.IFolderView)shellView;
599+
var folder = folderView.GetFolder<Win32API.IPersistFolder2>();
600+
if (folder.GetCurFolder(out var folderPidl).Succeeded)
601+
{
602+
if (Shell32.ILIsParent(folderPidl.DangerousGetHandle(), targetFolder.PIDL.DangerousGetHandle(), true) ||
603+
Shell32.ILIsEqual(folderPidl.DangerousGetHandle(), controlPanelCategoryView.PIDL.DangerousGetHandle()))
604+
{
605+
if (shellBrowser.BrowseObject(targetFolder.PIDL.DangerousGetHandle(), Shell32.SBSP.SBSP_SAMEBROWSER | Shell32.SBSP.SBSP_ABSOLUTE).Succeeded)
606+
{
607+
opened = true;
608+
break;
609+
}
610+
}
611+
folderPidl.Dispose();
612+
}
613+
Marshal.ReleaseComObject(folder);
614+
Marshal.ReleaseComObject(folderView);
615+
Marshal.ReleaseComObject(shellView);
616+
}
617+
}
618+
Marshal.ReleaseComObject(shellBrowser);
619+
Marshal.ReleaseComObject(pUnk);
620+
}
621+
Marshal.ReleaseComObject(serv);
622+
}
623+
Marshal.ReleaseComObject(webBrowser);
624+
}
625+
Marshal.ReleaseComObject(item);
626+
}
627+
628+
Marshal.ReleaseComObject(shellWindows);
629+
Marshal.ReleaseComObject(shellWindowsUnk);
630+
}
631+
632+
if (!opened)
633+
{
634+
Shell32.ShellExecute(HWND.NULL,
635+
"open",
636+
Environment.ExpandEnvironmentVariables("%windir%\\explorer.exe"),
637+
folderPath,
638+
null,
639+
ShowWindowCommand.SW_SHOWNORMAL);
640+
}
641+
}
642+
570643
// Get information from recycle bin.
571644
[DllImport(Lib.Shell32, SetLastError = false, CharSet = CharSet.Auto)]
572645
public static extern int SHQueryRecycleBin(string pszRootPath,
573646
ref SHQUERYRBINFO pSHQueryRBInfo);
647+
648+
[ComImport, Guid("1AC3D9F0-175C-11d1-95BE-00609797EA4F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
649+
public interface IPersistFolder2 : Shell32.IPersistFolder
650+
{
651+
new Guid GetClassID();
652+
653+
new void Initialize([In] Shell32.PIDL pidl);
654+
655+
[PreserveSig]
656+
HRESULT GetCurFolder(out Shell32.PIDL ppidl);
657+
}
658+
659+
[ComImport, Guid("EAB22AC1-30C1-11CF-A7EB-0000C05BAE0B"), CoClass(typeof(WebBrowser_V1))]
660+
public interface IWebBrowser
661+
{
662+
[DispId(100)]
663+
void GoBack();
664+
665+
[DispId(0x65)]
666+
void GoForward();
667+
668+
[DispId(0x66)]
669+
void GoHome();
670+
671+
[DispId(0x67)]
672+
void GoSearch();
673+
674+
[DispId(0x68)]
675+
void Navigate([In, MarshalAs(UnmanagedType.BStr)] string URL, [In, Optional, MarshalAs(UnmanagedType.Struct)] ref object Flags, [In, Optional, MarshalAs(UnmanagedType.Struct)] ref object TargetFrameName, [In, Optional, MarshalAs(UnmanagedType.Struct)] ref object PostData, [In, Optional, MarshalAs(UnmanagedType.Struct)] ref object Headers);
676+
677+
[DispId(-550)]
678+
void Refresh();
679+
680+
[DispId(0x69)]
681+
void Refresh2([In, Optional, MarshalAs(UnmanagedType.Struct)] ref object Level);
682+
683+
[DispId(0x6a)]
684+
void Stop();
685+
686+
[DispId(200)]
687+
object Application { [return: MarshalAs(UnmanagedType.IDispatch)] [DispId(200)] get; }
688+
689+
[DispId(0xc9)]
690+
object Parent { [return: MarshalAs(UnmanagedType.IDispatch)] [DispId(0xc9)] get; }
691+
692+
[DispId(0xca)]
693+
object Container { [return: MarshalAs(UnmanagedType.IDispatch)] [DispId(0xca)] get; }
694+
695+
[DispId(0xcb)]
696+
object Document { [return: MarshalAs(UnmanagedType.IDispatch)] [DispId(0xcb)] get; }
697+
698+
[DispId(0xcc)]
699+
bool TopLevelContainer { [DispId(0xcc)] get; }
700+
701+
[DispId(0xcd)]
702+
string Type { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0xcd)] get; }
703+
704+
[DispId(0xce)]
705+
int Left { [DispId(0xce)] get; [param: In] [DispId(0xce)] set; }
706+
707+
[DispId(0xcf)]
708+
int Top { [DispId(0xcf)] get; [param: In] [DispId(0xcf)] set; }
709+
710+
[DispId(0xd0)]
711+
int Width { [DispId(0xd0)] get; [param: In] [DispId(0xd0)] set; }
712+
713+
[DispId(0xd1)]
714+
int Height { [DispId(0xd1)] get; [param: In] [DispId(0xd1)] set; }
715+
716+
[DispId(210)]
717+
string LocationName { [return: MarshalAs(UnmanagedType.BStr)] [DispId(210)] get; }
718+
719+
[DispId(0xd3)]
720+
string LocationURL { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0xd3)] get; }
721+
722+
[DispId(0xd4)]
723+
bool Busy { [DispId(0xd4)] get; }
724+
}
725+
726+
[ComImport, Guid("0002DF05-0000-0000-C000-000000000046")]
727+
public interface IWebBrowserApp : IWebBrowser
728+
{
729+
[DispId(100)]
730+
void GoBack();
731+
732+
[DispId(0x65)]
733+
void GoForward();
734+
735+
[DispId(0x66)]
736+
void GoHome();
737+
738+
[DispId(0x67)]
739+
void GoSearch();
740+
741+
[DispId(0x68)]
742+
void Navigate([In, MarshalAs(UnmanagedType.BStr)] string URL, [In, Optional, MarshalAs(UnmanagedType.Struct)] ref object Flags, [In, Optional, MarshalAs(UnmanagedType.Struct)] ref object TargetFrameName, [In, Optional, MarshalAs(UnmanagedType.Struct)] ref object PostData, [In, Optional, MarshalAs(UnmanagedType.Struct)] ref object Headers);
743+
744+
[DispId(-550)]
745+
void Refresh();
746+
747+
[DispId(0x69)]
748+
void Refresh2([In, Optional, MarshalAs(UnmanagedType.Struct)] ref object Level);
749+
750+
[DispId(0x6a)]
751+
void Stop();
752+
753+
[DispId(200)]
754+
object Application { [return: MarshalAs(UnmanagedType.IDispatch)] [DispId(200)] get; }
755+
756+
[DispId(0xc9)]
757+
object Parent { [return: MarshalAs(UnmanagedType.IDispatch)] [DispId(0xc9)] get; }
758+
759+
[DispId(0xca)]
760+
object Container { [return: MarshalAs(UnmanagedType.IDispatch)] [DispId(0xca)] get; }
761+
762+
[DispId(0xcb)]
763+
object Document { [return: MarshalAs(UnmanagedType.IDispatch)] [DispId(0xcb)] get; }
764+
765+
[DispId(0xcc)]
766+
bool TopLevelContainer { [DispId(0xcc)] get; }
767+
768+
[DispId(0xcd)]
769+
string Type { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0xcd)] get; }
770+
771+
[DispId(0xce)]
772+
int Left { [DispId(0xce)] get; [param: In] [DispId(0xce)] set; }
773+
774+
[DispId(0xcf)]
775+
int Top { [DispId(0xcf)] get; [param: In] [DispId(0xcf)] set; }
776+
777+
[DispId(0xd0)]
778+
int Width { [DispId(0xd0)] get; [param: In] [DispId(0xd0)] set; }
779+
780+
[DispId(0xd1)]
781+
int Height { [DispId(0xd1)] get; [param: In] [DispId(0xd1)] set; }
782+
783+
[DispId(210)]
784+
string LocationName { [return: MarshalAs(UnmanagedType.BStr)] [DispId(210)] get; }
785+
786+
[DispId(0xd3)]
787+
string LocationURL { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0xd3)] get; }
788+
789+
[DispId(0xd4)]
790+
bool Busy { [DispId(0xd4)] get; }
791+
792+
[DispId(300)]
793+
void Quit();
794+
795+
[DispId(0x12d)]
796+
void ClientToWindow([In, Out] ref int pcx, [In, Out] ref int pcy);
797+
798+
[DispId(0x12e)]
799+
void PutProperty([In, MarshalAs(UnmanagedType.BStr)] string Property, [In, MarshalAs(UnmanagedType.Struct)] object vtValue);
800+
801+
[return: MarshalAs(UnmanagedType.Struct)]
802+
[DispId(0x12f)]
803+
object GetProperty([In, MarshalAs(UnmanagedType.BStr)] string Property);
804+
805+
[DispId(0)]
806+
string Name { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0)] get; }
807+
808+
[DispId(-515)]
809+
int HWND { [DispId(-515)] get; }
810+
811+
[DispId(400)]
812+
string FullName { [return: MarshalAs(UnmanagedType.BStr)] [DispId(400)] get; }
813+
814+
[DispId(0x191)]
815+
string Path { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0x191)] get; }
816+
817+
[DispId(0x192)]
818+
bool Visible { [DispId(0x192)] get; [param: In] [DispId(0x192)] set; }
819+
820+
[DispId(0x193)]
821+
bool StatusBar { [DispId(0x193)] get; [param: In] [DispId(0x193)] set; }
822+
823+
[DispId(0x194)]
824+
string StatusText { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0x194)] get; [param: In, MarshalAs(UnmanagedType.BStr)] [DispId(0x194)] set; }
825+
826+
[DispId(0x195)]
827+
int ToolBar { [DispId(0x195)] get; [param: In] [DispId(0x195)] set; }
828+
829+
[DispId(0x196)]
830+
bool MenuBar { [DispId(0x196)] get; [param: In] [DispId(0x196)] set; }
831+
832+
[DispId(0x197)]
833+
bool FullScreen { [DispId(0x197)] get; [param: In] [DispId(0x197)] set; }
834+
}
835+
836+
[ComImport, ComSourceInterfaces("Vanara.PInvoke.Shell32.DWebBrowserEvents2\0Vanara.PInvoke.Shell32.DWebBrowserEvents\0"), Guid("8856F961-340A-11D0-A96B-00C04FD705A2"), ClassInterface(ClassInterfaceType.None)]
837+
public class WebBrowser { }
838+
839+
[ComImport, ClassInterface(ClassInterfaceType.None), Guid("EAB22AC3-30C1-11CF-A7EB-0000C05BAE0B"), ComSourceInterfaces("Vanara.PInvoke.Shell32.DWebBrowserEvents\0Vanara.PInvoke.Shell32.DWebBrowserEvents2\0")]
840+
public class WebBrowser_V1 { }
574841
}
575842
}

0 commit comments

Comments
 (0)