【问题标题】:Run Windows Explorer beside my application with a specified Bounds在我的应用程序旁边以指定的边界运行 Windows 资源管理器
【发布时间】:2018-08-25 19:24:42
【问题描述】:

我有这个:

ShellExecute(Application.Handle, nil, PWideChar('explorer.exe'), PWideChar(ImagesDir), nil, SW_SHOWNORMAL);

变量ImagesDir 是我想通过 Windows 资源管理器显示的图像目录...

如何在我的应用程序旁边以指定的边界运行 Windows 资源管理器,例如这样的?

【问题讨论】:

  • 打开窗口后,使用FindWindow()或更好的IShellWindows.FindWindowSW()定位窗口的HWND,然后根据需要重新定位。
  • 一个非常好的和明确的答案......但是先生:Remy Lebeau 如果你不介意当然我需要如何使用这个功能(ishellwindows.findwindowsw())来重新定位打开的Windows 资源管理器...我希望您在答案框中回答我,而不是评论框,让我可以选择对您的答案投赞成票...
  • 将视图嵌入到您的应用程序中,随意放置。搜索 iExplorerBrowser。

标签: api delphi vcl shellexecute


【解决方案1】:

当您打开任何文件资源管理器窗口(例如转到 C:\ )时,文件资源管理器具有特定的已保存窗口大小,它会随其打开。因此,当您水平和/或垂直调整它的大小时,关闭它并再次重新打开它,它会保存窗口的大小,
并且在注册表中保存此信息的位置是:
在我的系统上,HKCU\Software\Classes\Local Settings\Software\Microsoft\Windows\Shell\Bags\AllFolders\Shell\WinPos1366x768x96(1)..position,其中位置是左、右、上或下,给出了位置以像素为单位的窗口边框。

我假设键的名称取决于屏幕分辨率。here 代码将是这样的:

.....
const
   AMainKey = '\Software\Classes\Local 
   Settings\Software\Microsoft\Windows\Shell\Bags\AllFolders\Shell\';

var
  FrmMain: TFrmMain;
  ImagesDir: string;
  AWinPos_left, AWinPos_Top,
  AWinPos_Right, AWinPos_Bottom: string;

implementation
  Uses
    ShellApi, Registry;
  {$R *.dfm}

procedure ExploreDir_With_Bounds(AFile_Dir: string;ALeft, ATop, AWidth, AHieght: DWORD);
  FUNCTION ExploreDirectory(CONST Dir : STRING) : BOOLEAN;
  BEGIN
    Result :=(ShellExecute(GetDesktopWindow,'open',PWideChar(Dir),'','',SW_SHOW)>32)
  END;
var
  ListNames, ListPosition: TStringList;
  I, AScreen_Width, AScreen_Hieght, APixelPI: Integer;
  AWinPos_Uses: string;
begin
  ListNames    := TStringList.Create;
  ListPosition := TStringList.Create;
  With TRegistry.Create Do
  Try
    RootKey := HKEY_CURRENT_USER;
    OpenKey(AMainKey,FALSE);
    GetValueNames(ListNames);

    AScreen_Width  := Screen.Width;
    AScreen_Hieght := Screen.Height;
    APixelPI := Screen.PixelsPerInch;
    AWinPos_Uses := 'WinPos'+AScreen_Width.ToString+'x'+AScreen_Hieght.ToString+'x'+APixelPI.ToString;

    for I := 0 to ListNames.Count - 1 do
    begin
      if Pos(AWinPos_Uses, ListNames[I]) <> 0 then
      begin
        ListPosition.Add(ListNames[I]);
      end;
    end;

    for I := 0 to ListPosition.Count - 1 do
    begin
      if (Pos('left', ListPosition[I]) <> 0) then
      begin
        AWinPos_left := ListPosition[I];
        Lbl_Left.Caption := AWinPos_left;
        Continue;
      end else
      if (Pos('top', ListPosition[I]) <> 0) then
      begin
        AWinPos_Top := ListPosition[I];
        Lbl_Top.Caption := AWinPos_Top;
        Continue;
      end else
      if (Pos('right', ListPosition[I]) <> 0) then
      begin
        AWinPos_Right := ListPosition[I];
        Lbl_Right.Caption := AWinPos_Right;
        Continue;
      end else
      if (Pos('bottom', ListPosition[I]) <> 0) then
      begin
        AWinPos_Bottom := ListPosition[I];
        Lbl_Bottom.Caption := AWinPos_Bottom;
      end;
    end;

    if (AWinPos_left <> '')and(AWinPos_Top <> '')and
      (AWinPos_Right <> '')and(AWinPos_Bottom <> '') then
    begin
      WriteInteger(AWinPos_left, ALeft);
      WriteInteger(AWinPos_Top, ATop);
      WriteInteger(AWinPos_Right, ALeft + AWidth);
      WriteInteger(AWinPos_Bottom, ATop + AHieght);
    end;

    CloseKey;
  Finally
    Free;
    ListNames.Free;
    ListPosition.Free;
  End;

  ExploreDirectory(AFile_Dir);
end;  

procedure TFrmMain.FormCreate(Sender: TObject);
begin
  ImagesDir := TDirectory.GetParent(TDirectory.GetParent(ExtractFileDir(ParamStr(0))))+ '\My Images To Test';

  ExploreDir_With_Bounds(ImagesDir, (50 + Width)+10{Left}, 50{TOP},
                         Screen.Width - (Left + Width +20){width},
                         Screen.Height - 150{hieght});
end;

procedure TFrmMain.FormShow(Sender: TObject);
begin
  Left := 0;
  Top  := (Screen.WorkAreaHeight div 2)-(Height div 2);
end;  

end.

the Result here

【讨论】:

    【解决方案2】:

    您可以使用以下函数打开资源管理器窗口并使其指向特定目录。

    USES Windows,ShellAPI;
    
    FUNCTION ExploreDirectory(CONST Dir : STRING) : BOOLEAN;
      BEGIN
        Result:=(ShellExecute(GetDesktopWindow,'open',PChar(Dir),'','',SW_SHOW)>32)
      END;
    

    但是请注意,您不能(使用此代码)使资源管理器窗口“跟随”您的程序,即。打开的窗口是一个完全自主的窗口,没有指向您的程序的链接,就好像用户自己浏览了该目录一样。如果您再次使用新目录调用此函数,资源管理器将使用该目录打开一个新窗口(并保持旧窗口打开)。

    更新: 如果您希望能够在资源管理器窗口打开后对其进行操作,则需要使用资源管理器公开的各种接口。我制作了一个 UNIT,它允许你做你想做的事情,并返回之后能够操作窗口所需的界面。它很大程度上基于此答案中的代码:

    Check if windows explorer already opened on given path

    Victoria

    UNIT WindowsExplorer;
    
    INTERFACE
    
    USES Types,ShDocVw;
    
    FUNCTION ExploreDirectory(CONST Dir : STRING) : BOOLEAN;
    FUNCTION OpenFolder(CONST Dir : STRING) : IWebBrowserApp; OVERLOAD;
    FUNCTION OpenFolderAt(CONST Dir : STRING ; Left,Top,Width,Height : INTEGER) : IWebBrowserApp; OVERLOAD;
    FUNCTION OpenFolderAt(CONST Dir : STRING ; CONST Rect : TRect) : IWebBrowserApp; OVERLOAD; INLINE;
    
    IMPLEMENTATION
    
    USES Windows,Variants,ShlObj,Ole2,OleAuto,ShellAPI,ActiveX,SysUtils;
    
    FUNCTION ExploreDirectory(CONST Dir : STRING) : BOOLEAN;
      BEGIN
        Result:=(ShellExecute(GetDesktopWindow,'open',PChar(Dir),'','',SW_SHOW)>32)
      END;
    
    FUNCTION GetFolderIDList(CONST Dir : STRING) : PItemIDList;
      VAR
        ShellFolder : IShellFolder;
        Attributes  : ULONG;
        Count       : ULONG;
    
      BEGIN
        OleCheck(SHGetDesktopFolder(ShellFolder));
        Attributes:=SFGAO_FOLDER or SFGAO_STREAM;
        OleCheck(ShellFolder.ParseDisplayName(0,NIL,PWideChar(WideString(Dir)),Count,Result,Attributes));
        IF NOT ((Attributes AND SFGAO_FOLDER=SFGAO_FOLDER) AND (Attributes AND SFGAO_STREAM<>SFGAO_STREAM)) THEN BEGIN
          CoTaskMemFree(Result);
          Result:=NIL
        END
      END;
    
    FUNCTION OpenFolder(CONST Dir : STRING ; OpenIfNotFound : BOOLEAN) : IWebBrowserApp; OVERLOAD;
      CONST
        IID_IServiceProvider: System.TGUID = '{6D5140C1-7436-11CE-8034-00AA006009FA}';
    
      VAR
        FolderID        : PItemIDList;
        ShellWindows    : IShellWindows;
        I               : INTEGER;
        WndIFace        : System.IDispatch;
        WebBrowserApp   : IWebBrowserApp;
        ServiceProvider : IServiceProvider;
        ShellBrowser    : IShellBrowser;
        ShellView       : IShellView;
        FolderView      : IFolderView;
        PersistFolder   : IPersistFolder2;
        CurFolderID     : PItemIDList;
    
      BEGIN
        FolderID:=GetFolderIDList(Dir);
        IF Assigned(FolderID) THEN TRY
          OleCheck(CoCreateInstance(CLASS_ShellWindows,NIL,CLSCTX_LOCAL_SERVER,IID_IShellWindows,ShellWindows));
          FOR I:=0 TO PRED(ShellWindows.Count) DO BEGIN
            WndIface:=ShellWindows.Item(VarAsType(I,VT_I4));
            IF Assigned(WndIface) AND
               Succeeded(WndIface.QueryInterface(IID_IWebBrowserApp,WebBrowserApp)) AND
               Succeeded(WebBrowserApp.QueryInterface(IID_IServiceProvider,ServiceProvider)) AND
               Succeeded(ServiceProvider.QueryService(SID_STopLevelBrowser,IID_IShellBrowser,ShellBrowser)) AND
               Succeeded(ShellBrowser.QueryActiveShellView(ShellView)) AND
               Succeeded(ShellView.QueryInterface(IID_IFolderView,FolderView)) AND
               Succeeded(FolderView.GetFolder(IID_IPersistFolder2,PersistFolder)) AND
               Succeeded(PersistFolder.GetCurFolder(CurFolderID)) AND
               ILIsEqual(FolderID,CurFolderID) THEN BEGIN
              IF IsIconic(WebBrowserApp.HWnd) THEN Win32Check(ShowWindow(WebBrowserApp.HWnd,SW_RESTORE));
              Win32Check(SetForegroundWindow(WebBrowserApp.HWnd));
              Exit(WebBrowserApp)
            END
          END
        FINALLY
          CoTaskMemFree(FolderID)
        END;
        Result:=NIL;
        IF OpenIfNotFound THEN BEGIN
          IF NOT ExploreDirectory(Dir) THEN EXIT;
          FOR I:=1 TO 20 DO BEGIN
            Result:=OpenFolder(Dir,FALSE);
            IF Assigned(Result) THEN EXIT;
            Sleep(100)
          END
        END
      END;
    
    FUNCTION OpenFolder(CONST Dir : STRING) : IWebBrowserApp;
      BEGIN
        Result:=OpenFolder(Dir,TRUE)
      END;
    
    FUNCTION OpenFolderAt(CONST Dir : STRING ; Left,Top,Width,Height : INTEGER) : IWebBrowserApp;
      BEGIN
        Result:=OpenFolder(Dir);
        IF Assigned(Result) THEN BEGIN
          Result.Left:=Left; Result.Top:=Top; Result.Width:=Width; Result.Height:=Height
        END
      END;
    
    FUNCTION OpenFolderAt(CONST Dir : STRING ; CONST Rect : TRect) : IWebBrowserApp;
      BEGIN
        Result:=OpenFolderAt(Dir,Rect.Left,Rect.Top,Rect.Width,Rect.Height)
      END;
    
    END.
    

    它是为 Delphi Tokyo 10.2.3 使用而设计的,因此如果您使用较早的版本(您没有在问题中指定 Delphi 版本),您可能需要调整使用列表以匹配。

    【讨论】:

      猜你喜欢
      • 2013-12-04
      • 1970-01-01
      • 2011-09-11
      • 1970-01-01
      • 1970-01-01
      • 2019-08-03
      • 1970-01-01
      • 1970-01-01
      • 2021-01-23
      相关资源
      最近更新 更多