Search code examples
delphiwinapiwindows-shell

How to change path of an existing Windows Explorer window?


I have the handle of an opened Windows Explorer window.

How can I send a command to it in order to change the path from
example: m:\programs to d:\programs.


example

Till now I was using ShellExecute() but it opens a new window. This is not good (user experience).


Solution

  • The following BrowseToFolder function navigates the existing instance of a Windows Explorer of the given AHandle handle (if exists) to a AFolderPath folder (if exists). If you won't specify the second parameter, the topmost window should be taken to navigate (or at least the documentation claims that; reality seems to take the oldest existing window). The function returns True, if the navigation has been successful, False otherwise:

    uses
      ActiveX, ShlObj, ShellAPI, SHDocVw;
    
    const
      IID_IServiceProvider: TGUID = '{6D5140C1-7436-11CE-8034-00AA006009FA}';
      SID_STopLevelBrowser: TGUID = '{4C96BE40-915C-11CF-99D3-00AA004AE837}';
    
    function GetItemIDListFromPath(const AFolderPath: WideString): PItemIDList;
    var
      Count: ULONG;
      Attributes: ULONG;
      ShellFolder: IShellFolder;
    begin
      Result := nil;
      if Succeeded(SHGetDesktopFolder(ShellFolder)) then
      begin
        Count := 0;
        if Failed(ShellFolder.ParseDisplayName(0, nil, PWideChar(AFolderPath),
          Count, Result, Attributes))
        then
          Result := nil;
      end;
    end;
    
    function BrowseToFolder(const AFolderPath: WideString;
      AHandle: HWND = HWND_TOPMOST): Boolean;
    var
      I: Integer;
      WndIface: IDispatch;
      ItemIDList: PItemIDList;
      ShellBrowser: IShellBrowser;
      ShellWindows: IShellWindows;
      WebBrowserApp: IWebBrowserApp;
      ServiceProvider: IServiceProvider;
    begin
      Result := False;
    
      if Succeeded(CoCreateInstance(CLASS_ShellWindows, nil, CLSCTX_LOCAL_SERVER,
        IID_IShellWindows, ShellWindows)) then
      begin
        for I := 0 to ShellWindows.Count - 1 do
        begin
          if (AHandle <> HWND_TOPMOST) then
            WndIface := ShellWindows.Item(VarAsType(I, VT_I4))
          else
            WndIface := ShellWindows.Item(VarAsType(SWC_EXPLORER, VT_UI4));
    
          if Succeeded(WndIface.QueryInterface(IID_IWebBrowserApp,
            WebBrowserApp)) then
          begin
            if (AHandle = HWND_TOPMOST) or (WebBrowserApp.HWnd = AHandle) then
            begin
              if Succeeded(WebBrowserApp.QueryInterface(IID_IServiceProvider,
                ServiceProvider)) then
              begin
                if Succeeded(ServiceProvider.QueryService(SID_STopLevelBrowser,
                  IID_IShellBrowser, ShellBrowser)) then
                begin
                  ItemIDList := GetItemIDListFromPath(AFolderPath);
                  Result := Succeeded(ShellBrowser.BrowseObject(ItemIDList,
                    SBSP_SAMEBROWSER or SBSP_ABSOLUTE));
                end;
              end;
              Break;
            end;
          end;
        end;
      end;
    end;
    

    Here is the example usage:

    procedure TForm1.Button1Click(Sender: TObject);
    var
      ExplorerHandle: HWND;
    begin
      ExplorerHandle := 123456;
    
      if not BrowseToFolder('c:\Windows\System32\', ExplorerHandle) then
        ShowMessage('Navigation to a folder failed!')
      else
        ShowMessage('Navigation to a folder succeeded!');
    end;
    

    Here is a complete testing project and the blog post from which I've taken the inspiration.