浏览代码

ADD: View recycle bin content (Windows)

Alexander Koblov 4 年之前
父节点
当前提交
e947eeb9a8

+ 16 - 0
components/doublecmd/dcdatetimeutils.pas

@@ -81,6 +81,7 @@ function DosFileTimeToDateTime(const DosTime: TDosFileTime): TDateTime;
 function DateTimeToDosFileTime(const DateTime: TDateTime): TDosFileTime;
 function DateTimeToDosFileTime(const DateTime: TDateTime): TDosFileTime;
 
 
 {$IFDEF MSWINDOWS}
 {$IFDEF MSWINDOWS}
+function VariantTimeToDateTime(VarTime: Double): TDateTime;
 function WinFileTimeToDateTime(ft : Windows.FILETIME) : TDateTime; inline; overload;
 function WinFileTimeToDateTime(ft : Windows.FILETIME) : TDateTime; inline; overload;
 function WinToDosTime(const WinTime: Windows.FILETIME; var DosTime: TDosFileTime): LongBool; overload;
 function WinToDosTime(const WinTime: Windows.FILETIME; var DosTime: TDosFileTime): LongBool; overload;
 function DosToWinTime(const DosTime: TDosFileTime; var WinTime: Windows.FILETIME): LongBool; overload;
 function DosToWinTime(const DosTime: TDosFileTime; var WinTime: Windows.FILETIME): LongBool; overload;
@@ -377,6 +378,21 @@ begin
 end;
 end;
 
 
 {$IFDEF MSWINDOWS}
 {$IFDEF MSWINDOWS}
+function VariantTimeToDateTime(VarTime: Double): TDateTime;
+var
+  lpUniversalTime, lpLocalTime: TSystemTime;
+begin
+  if (Win32MajorVersion > 5) then
+  begin
+    DateTimeToSystemTime(VarTime, lpUniversalTime);
+    SystemTimeToTzSpecificLocalTime(nil, @lpUniversalTime, @lpLocalTime);
+    Result := SystemTimeToDateTime(lpLocalTime);
+  end
+  else begin
+    Result := IncMinute(VarTime, -WinTimeZoneBias);
+  end;
+end;
+
 function WinFileTimeToDateTime(ft : Windows.FILETIME) : TDateTime;
 function WinFileTimeToDateTime(ft : Windows.FILETIME) : TDateTime;
 begin
 begin
   Result := WinFileTimeToDateTime(TWinFileTime(ft));
   Result := WinFileTimeToDateTime(TWinFileTime(ft));

+ 21 - 20
src/doublecmd.lpi

@@ -1,15 +1,15 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <?xml version="1.0" encoding="UTF-8"?>
 <CONFIG>
 <CONFIG>
   <ProjectOptions>
   <ProjectOptions>
-    <Version Value="11"/>
+    <Version Value="12"/>
     <PathDelim Value="\"/>
     <PathDelim Value="\"/>
     <General>
     <General>
       <Flags>
       <Flags>
         <SaveClosedFiles Value="False"/>
         <SaveClosedFiles Value="False"/>
         <MainUnitHasUsesSectionForAllUnits Value="False"/>
         <MainUnitHasUsesSectionForAllUnits Value="False"/>
+        <CompatibilityMode Value="True"/>
       </Flags>
       </Flags>
       <SessionStorage Value="InProjectDir"/>
       <SessionStorage Value="InProjectDir"/>
-      <MainUnit Value="0"/>
       <AutoCreateForms Value="False"/>
       <AutoCreateForms Value="False"/>
       <Title Value="Double Commander"/>
       <Title Value="Double Commander"/>
       <ResourceType Value="res"/>
       <ResourceType Value="res"/>
@@ -38,7 +38,7 @@
           </Target>
           </Target>
           <SearchPaths>
           <SearchPaths>
             <IncludeFiles Value="$(LazarusDir)\ide;$(ProjOutDir);..\sdk;..\units"/>
             <IncludeFiles Value="$(LazarusDir)\ide;$(ProjOutDir);..\sdk;..\units"/>
-            <OtherUnitFiles Value="platform;platform\$(SrcOS);platform\$(SrcOS)\$(TargetOS);..\sdk;frames;fileviews;filesources;filesources\filesystem;filesources\multiarchive;filesources\multilist;filesources\searchresult;filesources\tempfilesystem;filesources\vfs;filesources\wcxarchive;filesources\wfxplugin;filesources\winnet;platform\unix\glib;platform\unix\mime;filesources\gio;rpc;rpc\sys\$(SrcOS);rpc\sys"/>
+            <OtherUnitFiles Value="platform;platform\$(SrcOS);platform\$(SrcOS)\$(TargetOS);..\sdk;frames;fileviews;filesources;filesources\filesystem;filesources\multiarchive;filesources\multilist;filesources\searchresult;filesources\tempfilesystem;filesources\vfs;filesources\wcxarchive;filesources\wfxplugin;filesources\winnet;platform\unix\glib;platform\unix\mime;filesources\gio;rpc;rpc\sys\$(SrcOS);rpc\sys;filesources\recyclebin"/>
             <UnitOutputDirectory Value="..\units\$(TargetCPU)-$(TargetOS)-$(LCLWidgetType)"/>
             <UnitOutputDirectory Value="..\units\$(TargetCPU)-$(TargetOS)-$(LCLWidgetType)"/>
             <SrcPath Value="$(LazarusDir)\lcl;$(LazarusDir)\lcl\interfaces\$(LCLWidgetType);$(fpcsrcdir)\packages\fcl-base\src"/>
             <SrcPath Value="$(LazarusDir)\lcl;$(LazarusDir)\lcl\interfaces\$(LCLWidgetType);$(fpcsrcdir)\packages\fcl-base\src"/>
           </SearchPaths>
           </SearchPaths>
@@ -81,7 +81,7 @@
           </Target>
           </Target>
           <SearchPaths>
           <SearchPaths>
             <IncludeFiles Value="$(LazarusDir)\ide;$(ProjOutDir);..\sdk;..\units"/>
             <IncludeFiles Value="$(LazarusDir)\ide;$(ProjOutDir);..\sdk;..\units"/>
-            <OtherUnitFiles Value="platform;platform\$(SrcOS);platform\$(SrcOS)\$(TargetOS);..\sdk;frames;fileviews;filesources;filesources\filesystem;filesources\multiarchive;filesources\multilist;filesources\searchresult;filesources\tempfilesystem;filesources\vfs;filesources\wcxarchive;filesources\wfxplugin;filesources\winnet;platform\unix\glib;platform\unix\mime;filesources\gio;rpc;rpc\sys\$(SrcOS);rpc\sys"/>
+            <OtherUnitFiles Value="platform;platform\$(SrcOS);platform\$(SrcOS)\$(TargetOS);..\sdk;frames;fileviews;filesources;filesources\filesystem;filesources\multiarchive;filesources\multilist;filesources\searchresult;filesources\tempfilesystem;filesources\vfs;filesources\wcxarchive;filesources\wfxplugin;filesources\winnet;platform\unix\glib;platform\unix\mime;filesources\gio;rpc;rpc\sys\$(SrcOS);rpc\sys;filesources\recyclebin"/>
             <UnitOutputDirectory Value="..\units\$(TargetCPU)-$(TargetOS)-$(LCLWidgetType)"/>
             <UnitOutputDirectory Value="..\units\$(TargetCPU)-$(TargetOS)-$(LCLWidgetType)"/>
             <SrcPath Value="$(LazarusDir)\lcl;$(LazarusDir)\lcl\interfaces\$(LCLWidgetType);$(fpcsrcdir)\packages\fcl-base\src"/>
             <SrcPath Value="$(LazarusDir)\lcl;$(LazarusDir)\lcl\interfaces\$(LCLWidgetType);$(fpcsrcdir)\packages\fcl-base\src"/>
           </SearchPaths>
           </SearchPaths>
@@ -120,29 +120,29 @@
           </Target>
           </Target>
           <SearchPaths>
           <SearchPaths>
             <IncludeFiles Value="$(LazarusDir)\ide;$(ProjOutDir);..\sdk;..\units"/>
             <IncludeFiles Value="$(LazarusDir)\ide;$(ProjOutDir);..\sdk;..\units"/>
-            <OtherUnitFiles Value="platform;platform\$(SrcOS);platform\$(SrcOS)\$(TargetOS);..\sdk;frames;fileviews;filesources;filesources\filesystem;filesources\multiarchive;filesources\multilist;filesources\searchresult;filesources\tempfilesystem;filesources\vfs;filesources\wcxarchive;filesources\wfxplugin;filesources\winnet;platform\unix\glib;platform\unix\mime;filesources\gio;rpc;rpc\sys\$(SrcOS);rpc\sys"/>
+            <OtherUnitFiles Value="platform;platform\$(SrcOS);platform\$(SrcOS)\$(TargetOS);..\sdk;frames;fileviews;filesources;filesources\filesystem;filesources\multiarchive;filesources\multilist;filesources\searchresult;filesources\tempfilesystem;filesources\vfs;filesources\wcxarchive;filesources\wfxplugin;filesources\winnet;platform\unix\glib;platform\unix\mime;filesources\gio;rpc;rpc\sys\$(SrcOS);rpc\sys;filesources\recyclebin"/>
             <UnitOutputDirectory Value="..\units\$(TargetCPU)-$(TargetOS)-$(LCLWidgetType)"/>
             <UnitOutputDirectory Value="..\units\$(TargetCPU)-$(TargetOS)-$(LCLWidgetType)"/>
             <SrcPath Value="$(LazarusDir)\lcl;$(LazarusDir)\lcl\interfaces\$(LCLWidgetType);$(fpcsrcdir)\packages\fcl-base\src"/>
             <SrcPath Value="$(LazarusDir)\lcl;$(LazarusDir)\lcl\interfaces\$(LCLWidgetType);$(fpcsrcdir)\packages\fcl-base\src"/>
           </SearchPaths>
           </SearchPaths>
-          <Conditionals Value="if (TargetOS = 'linux') then
+          <Conditionals Value="if (TargetOS = &apos;linux&apos;) then
 begin
 begin
-  LinkerOptions += ' -z relro --as-needed';
+  LinkerOptions += &apos; -z relro --as-needed&apos;;
 end;
 end;
 
 
-if LCLWidgetType &lt;> GetIDEValue('LCLWidgetType') then
+if LCLWidgetType &lt;> GetIDEValue(&apos;LCLWidgetType&apos;) then
 begin
 begin
-  UnitPath += '$(FallbackOutputRoot)/LazControls/lib/$(TargetCPU)-$(TargetOS)/$(LCLWidgetType);';
-  UnitPath += '$(FallbackOutputRoot)/SynEdit/units/$(TargetCPU)-$(TargetOS)/$(LCLWidgetType);';
+  UnitPath += &apos;$(FallbackOutputRoot)/LazControls/lib/$(TargetCPU)-$(TargetOS)/$(LCLWidgetType);&apos;;
+  UnitPath += &apos;$(FallbackOutputRoot)/SynEdit/units/$(TargetCPU)-$(TargetOS)/$(LCLWidgetType);&apos;;
 end;
 end;
 
 
-if ((LCLWidgetType = 'qt') or (LCLWidgetType = 'qt5')) and (TargetOS &lt;> 'darwin') then
+if ((LCLWidgetType = &apos;qt&apos;) or (LCLWidgetType = &apos;qt5&apos;)) and (TargetOS &lt;> &apos;darwin&apos;) then
 begin
 begin
-  UnitPath += 'platform/$(SrcOS)/qt5;';
+  UnitPath += &apos;platform/$(SrcOS)/qt5;&apos;;
 end;
 end;
 
 
-if (LCLWidgetType = 'gtk2') and (SrcOS = 'unix') and (TargetOS &lt;> 'darwin') then
+if (LCLWidgetType = &apos;gtk2&apos;) and (SrcOS = &apos;unix&apos;) and (TargetOS &lt;> &apos;darwin&apos;) then
 begin
 begin
-  UnitPath += 'platform/$(SrcOS)/$(LCLWidgetType);';
+  UnitPath += &apos;platform/$(SrcOS)/$(LCLWidgetType);&apos;;
 end;"/>
 end;"/>
           <Parsing>
           <Parsing>
             <SyntaxOptions>
             <SyntaxOptions>
@@ -191,13 +191,13 @@ end;"/>
     </PublishOptions>
     </PublishOptions>
     <RunParams>
     <RunParams>
       <local>
       <local>
-        <LaunchingApplication PathPlusParams="\usr\X11R6\bin\xterm -T 'Lazarus Run Output' -e $(LazarusDir)\tools\runwait.sh $(TargetCmdLine)"/>
+        <LaunchingApplication PathPlusParams="\usr\X11R6\bin\xterm -T &apos;Lazarus Run Output&apos; -e $(LazarusDir)\tools\runwait.sh $(TargetCmdLine)"/>
       </local>
       </local>
       <FormatVersion Value="2"/>
       <FormatVersion Value="2"/>
       <Modes Count="1">
       <Modes Count="1">
         <Mode0 Name="default">
         <Mode0 Name="default">
           <local>
           <local>
-            <LaunchingApplication PathPlusParams="\usr\X11R6\bin\xterm -T 'Lazarus Run Output' -e $(LazarusDir)\tools\runwait.sh $(TargetCmdLine)"/>
+            <LaunchingApplication PathPlusParams="\usr\X11R6\bin\xterm -T &apos;Lazarus Run Output&apos; -e $(LazarusDir)\tools\runwait.sh $(TargetCmdLine)"/>
           </local>
           </local>
         </Mode0>
         </Mode0>
       </Modes>
       </Modes>
@@ -1128,6 +1128,7 @@ end;"/>
       <Unit135>
       <Unit135>
         <Filename Value="filesources\uvirtualfilesource.pas"/>
         <Filename Value="filesources\uvirtualfilesource.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
+        <UnitName Value="uVirtualFileSource"/>
       </Unit135>
       </Unit135>
       <Unit136>
       <Unit136>
         <Filename Value="filesources\filesystem\ffilesystemcopymoveoperationoptions.pas"/>
         <Filename Value="filesources\filesystem\ffilesystemcopymoveoperationoptions.pas"/>
@@ -1901,13 +1902,13 @@ end;"/>
     </Target>
     </Target>
     <SearchPaths>
     <SearchPaths>
       <IncludeFiles Value="$(LazarusDir)\ide;$(ProjOutDir);..\sdk;..\units"/>
       <IncludeFiles Value="$(LazarusDir)\ide;$(ProjOutDir);..\sdk;..\units"/>
-      <OtherUnitFiles Value="platform;platform\$(SrcOS);platform\$(SrcOS)\$(TargetOS);..\sdk;frames;fileviews;filesources;filesources\filesystem;filesources\multiarchive;filesources\multilist;filesources\searchresult;filesources\tempfilesystem;filesources\vfs;filesources\wcxarchive;filesources\wfxplugin;filesources\winnet;platform\unix\glib;platform\unix\mime;filesources\gio;rpc;rpc\sys\$(SrcOS);rpc\sys"/>
+      <OtherUnitFiles Value="platform;platform\$(SrcOS);platform\$(SrcOS)\$(TargetOS);..\sdk;frames;fileviews;filesources;filesources\filesystem;filesources\multiarchive;filesources\multilist;filesources\searchresult;filesources\tempfilesystem;filesources\vfs;filesources\wcxarchive;filesources\wfxplugin;filesources\winnet;platform\unix\glib;platform\unix\mime;filesources\gio;rpc;rpc\sys\$(SrcOS);rpc\sys;filesources\recyclebin"/>
       <UnitOutputDirectory Value="..\units\$(TargetCPU)-$(TargetOS)-$(LCLWidgetType)"/>
       <UnitOutputDirectory Value="..\units\$(TargetCPU)-$(TargetOS)-$(LCLWidgetType)"/>
       <SrcPath Value="$(LazarusDir)\lcl;$(LazarusDir)\lcl\interfaces\$(LCLWidgetType);$(fpcsrcdir)\packages\fcl-base\src"/>
       <SrcPath Value="$(LazarusDir)\lcl;$(LazarusDir)\lcl\interfaces\$(LCLWidgetType);$(fpcsrcdir)\packages\fcl-base\src"/>
     </SearchPaths>
     </SearchPaths>
-    <Conditionals Value="if TargetOS = 'darwin' then begin
-  UsageCustomOptions += ' -k-macosx_version_min -k10.5';
-  UsageCustomOptions += ' -XR/Developer/SDKs/MacOSX10.5.sdk/';
+    <Conditionals Value="if TargetOS = &apos;darwin&apos; then begin
+  UsageCustomOptions += &apos; -k-macosx_version_min -k10.5&apos;;
+  UsageCustomOptions += &apos; -XR/Developer/SDKs/MacOSX10.5.sdk/&apos;;
 end;"/>
 end;"/>
     <Parsing>
     <Parsing>
       <SyntaxOptions>
       <SyntaxOptions>

+ 116 - 0
src/filesources/recyclebin/urecyclebinfilesource.pas

@@ -0,0 +1,116 @@
+unit uRecycleBinFileSource;
+
+{$mode ObjFPC}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, Dialogs,
+  uFileSourceProperty,
+  uVirtualFileSource, uFileProperty, uFileSource,
+  uFileSourceOperation, uFile, uFileSourceOperationTypes;
+
+type
+
+  { IRecycleBinFileSource }
+
+  IRecycleBinFileSource = interface(IVirtualFileSource)
+    ['{1E598290-5E66-423C-BB55-333E293106E8}']
+  end;
+
+  { TRecycleBinFileSource }
+
+  TRecycleBinFileSource = class(TVirtualFileSource, IRecycleBinFileSource)
+  protected
+    function SetCurrentWorkingDirectory(NewDir: String): Boolean; override;
+  public
+    class function IsSupportedPath(const Path: String): Boolean; override;
+    class function CreateFile(const APath: String): TFile; override;
+
+    function GetOperationsTypes: TFileSourceOperationTypes; override;
+    function GetSupportedFileProperties: TFilePropertiesTypes; override;
+    function GetLocalName(var aFile: TFile): Boolean; override;
+    function GetRootDir(sPath: String): String; override; overload;
+    function GetProperties: TFileSourceProperties; override;
+
+    function CreateListOperation(TargetPath: String): TFileSourceOperation; override;
+  end;
+
+implementation
+
+uses
+  uRecycleBinListOperation, uLng;
+
+{ TRecycleBinFileSource }
+
+function TRecycleBinFileSource.SetCurrentWorkingDirectory(NewDir: String): Boolean;
+begin
+  Result := IsPathAtRoot(NewDir);
+end;
+
+class function TRecycleBinFileSource.IsSupportedPath(const Path: String): Boolean;
+begin
+  Result:= SameText(ExcludeTrailingBackslash(Path), PathDelim + PathDelim + PathDelim + rsVfsRecycleBin);
+end;
+
+class function TRecycleBinFileSource.CreateFile(const APath: String): TFile;
+begin
+  Result := TFile.Create(APath);
+  with Result do
+  begin
+    AttributesProperty := TFileAttributesProperty.CreateOSAttributes;
+    SizeProperty := TFileSizeProperty.Create;
+    ModificationTimeProperty := TFileModificationDateTimeProperty.Create;
+    CreationTimeProperty := TFileCreationDateTimeProperty.Create;
+    LastAccessTimeProperty := TFileLastAccessDateTimeProperty.Create;
+    ChangeTimeProperty:= TFileChangeDateTimeProperty.Create;
+    LinkProperty := TFileLinkProperty.Create;
+    CommentProperty := TFileCommentProperty.Create;
+  end;
+end;
+
+function TRecycleBinFileSource.GetOperationsTypes: TFileSourceOperationTypes;
+begin
+  Result := [fsoList];
+end;
+
+function TRecycleBinFileSource.GetSupportedFileProperties: TFilePropertiesTypes;
+begin
+  Result := inherited GetSupportedFileProperties
+          + [fpSize,
+             fpAttributes,
+             fpModificationTime,
+             fpCreationTime,
+             fpLastAccessTime,
+             fpChangeTime,
+             uFileProperty.fpLink,
+             fpComment
+            ];
+end;
+
+function TRecycleBinFileSource.GetLocalName(var aFile: TFile): Boolean;
+begin
+  Result:= True;
+  aFile.FullPath:= aFile.LinkProperty.LinkTo;
+end;
+
+function TRecycleBinFileSource.GetRootDir(sPath: String): String;
+begin
+  Result:= PathDelim + PathDelim + PathDelim + rsVfsRecycleBin + PathDelim;
+end;
+
+function TRecycleBinFileSource.GetProperties: TFileSourceProperties;
+begin
+  Result := [fspDirectAccess, fspVirtual, fspLinksToLocalFiles];
+end;
+
+function TRecycleBinFileSource.CreateListOperation(TargetPath: String): TFileSourceOperation;
+var
+  TargetFileSource: IFileSource;
+begin
+  TargetFileSource := Self;
+  Result:= TRecycleBinListOperation.Create(TargetFileSource, TargetPath);
+end;
+
+end.
+

+ 87 - 0
src/filesources/recyclebin/urecyclebinlistoperation.pas

@@ -0,0 +1,87 @@
+unit uRecycleBinListOperation;
+
+{$mode ObjFPC}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils,
+  uFileSystemListOperation,
+  uRecycleBinFileSource,
+  uFileSource;
+
+type
+
+  { TRecycleBinListOperation }
+
+  TRecycleBinListOperation = class(TFileSystemListOperation)
+  public
+    constructor Create(aFileSource: IFileSource; aPath: String); override;
+    procedure MainExecute; override;
+  end;
+
+implementation
+
+uses
+  Windows, ShlObj, ComObj, JwaShlGuid, Variants, DCOSUtils, DCDateTimeUtils,
+  uFile, uShellFolder, uShlObjAdditional, uShowMsg;
+
+const
+  SID_DISPLACED = '{9B174B33-40FF-11d2-A27E-00C04FC30871}';
+  SCID_OriginalLocation: TSHColumnID = ( fmtid: SID_DISPLACED; pid: PID_DISPLACED_FROM );
+  SCID_DateDeleted:      TSHColumnID = ( fmtid: SID_DISPLACED; pid: PID_DISPLACED_DATE );
+
+{ TRecycleBinListOperation }
+
+constructor TRecycleBinListOperation.Create(aFileSource: IFileSource;
+  aPath: String);
+begin
+  FFiles := TFiles.Create(aPath);
+  inherited Create(aFileSource, aPath);
+end;
+
+procedure TRecycleBinListOperation.MainExecute;
+var
+  AFile: TFile;
+  NumIDs: LongWord = 0;
+  AFolder: IShellFolder2;
+  EnumIDList: IEnumIDList;
+  Attr: TFileAttributeData;
+  DesktopFolder: IShellFolder;
+  PIDL, TrashPIDL: PItemIDList;
+begin
+  FFiles.Clear;
+  try
+    OleCheckUTF8(SHGetDesktopFolder(DesktopFolder));
+    OleCheckUTF8(SHGetFolderLocation(0, CSIDL_BITBUCKET, 0, 0, {%H-}TrashPIDL));
+    OleCheckUTF8(DesktopFolder.BindToObject(TrashPIDL, nil, IID_IShellFolder2, Pointer(AFolder)));
+    OleCheckUTF8(AFolder.EnumObjects(0, SHCONTF_FOLDERS or SHCONTF_NONFOLDERS or SHCONTF_INCLUDEHIDDEN, EnumIDList));
+
+    while EnumIDList.Next(1, PIDL, NumIDs) = S_OK do
+    begin
+      CheckOperationState;
+
+      aFile:= TRecycleBinFileSource.CreateFile(Path);
+      AFile.FullPath:= GetDisplayName(AFolder, PIDL, SHGDN_NORMAL);
+      AFile.LinkProperty.LinkTo:= GetDisplayName(AFolder, PIDL, SHGDN_FORPARSING);
+
+      if mbFileGetAttr(AFile.LinkProperty.LinkTo, Attr) then
+      begin
+        AFile.Size:= Attr.Size;
+        AFile.Attributes:= Attr.Attr;
+        AFile.CreationTime:= WinFileTimeToDateTime(Attr.PlatformTime);
+        AFile.LastAccessTime:= WinFileTimeToDateTime(Attr.LastAccessTime);
+        AFile.ModificationTime:= WinFileTimeToDateTime(Attr.LastWriteTime);
+        AFile.CommentProperty.Value:= GetDetails(AFolder, PIDL, SCID_OriginalLocation);
+        AFile.ChangeTime:= VariantTimeToDateTime(VarToDateTime(GetDetails(AFolder, PIDL, SCID_DateDeleted)));
+      end;
+
+      FFiles.Add(AFile);
+    end;
+  except
+    on E: Exception do msgError(Thread, E.Message);
+  end;
+end;
+
+end.
+

+ 2 - 0
src/platform/uosforms.pas

@@ -130,6 +130,7 @@ uses
   , uWinNetFileSource, uVfsModule, uLng, uMyWindows, DCStrUtils
   , uWinNetFileSource, uVfsModule, uLng, uMyWindows, DCStrUtils
   , uDCReadSVG, uFileSourceUtil, uGdiPlusJPEG, uListGetPreviewBitmap
   , uDCReadSVG, uFileSourceUtil, uGdiPlusJPEG, uListGetPreviewBitmap
   , Dialogs, Clipbrd, uShowMsg, uDebug, JwaDbt, uThumbnailProvider
   , Dialogs, Clipbrd, uShowMsg, uDebug, JwaDbt, uThumbnailProvider
+  , uRecycleBinFileSource
     {$IFDEF LCLQT5}
     {$IFDEF LCLQT5}
     , qt5, qtwidgets, uDarkStyle
     , qt5, qtwidgets, uDarkStyle
     {$ENDIF}
     {$ENDIF}
@@ -582,6 +583,7 @@ begin
 {$ENDIF}
 {$ENDIF}
   // Register network file source
   // Register network file source
   RegisterVirtualFileSource(rsVfsNetwork, TWinNetFileSource);
   RegisterVirtualFileSource(rsVfsNetwork, TWinNetFileSource);
+  RegisterVirtualFileSource(rsVfsRecycleBin, TRecycleBinFileSource);
   if (IsUserAdmin = dupAccept) then // if run under administrator
   if (IsUserAdmin = dupAccept) then // if run under administrator
     MainForm.Caption:= MainForm.Caption + ' - Administrator';
     MainForm.Caption:= MainForm.Caption + ' - Administrator';
 
 

+ 13 - 2
src/platform/win/ushellfolder.pas

@@ -5,7 +5,7 @@ unit uShellFolder;
 interface
 interface
 
 
 uses
 uses
-  Classes, SysUtils, Windows, ShlObj, ActiveX, ComObj;
+  Classes, SysUtils, Windows, ShlObj, ActiveX, ComObj, uShlObjAdditional;
 
 
 const
 const
   FOLDERID_AccountPictures: TGUID = '{008ca0b1-55b4-4c56-b8a8-4de4b299d3be}';
   FOLDERID_AccountPictures: TGUID = '{008ca0b1-55b4-4c56-b8a8-4de4b299d3be}';
@@ -58,11 +58,12 @@ const
 function GetKnownFolderPath(const rfid: TGUID; out APath: String): Boolean;
 function GetKnownFolderPath(const rfid: TGUID; out APath: String): Boolean;
 
 
 function GetDisplayName(AFolder: IShellFolder; PIDL: PItemIDList; Flags: DWORD): String;
 function GetDisplayName(AFolder: IShellFolder; PIDL: PItemIDList; Flags: DWORD): String;
+function GetDetails(AFolder: IShellFolder2; PIDL: PItemIDList; const pscid: SHCOLUMNID): OleVariant;
 
 
 implementation
 implementation
 
 
 uses
 uses
-  ShellApi, LazUTF8, DCConvertEncoding, uShlObjAdditional;
+  ShellApi, LazUTF8, DCConvertEncoding;
 
 
 function StrRetToString(PIDL: PItemIDList; StrRet: TStrRet): String;
 function StrRetToString(PIDL: PItemIDList; StrRet: TStrRet): String;
 var
 var
@@ -87,6 +88,16 @@ begin
     Result := GetDisplayName(AFolder, PIDL, SHGDN_NORMAL);
     Result := GetDisplayName(AFolder, PIDL, SHGDN_NORMAL);
 end;
 end;
 
 
+function GetDetails(AFolder: IShellFolder2; PIDL: PItemIDList; const pscid: SHCOLUMNID): OleVariant;
+var
+  AValue: OleVariant;
+begin
+ if Succeeded(AFolder.GetDetailsEx(pidl, @pscid, @AValue)) then
+   Result:= AValue
+ else
+   Result:= Unassigned;
+end;
+
 const
 const
   KF_FLAG_DEFAULT = $00000000;
   KF_FLAG_DEFAULT = $00000000;
 
 

+ 15 - 4
src/platform/win/ushlobjadditional.pas

@@ -68,6 +68,21 @@ type
       function GetOverlayIconIndex(pidl : PItemIDList; var IconIndex : Integer) : HResult; stdcall;
       function GetOverlayIconIndex(pidl : PItemIDList; var IconIndex : Integer) : HResult; stdcall;
    end; { IShellIconOverlay }
    end; { IShellIconOverlay }
 
 
+{$IF FPC_FULLVERSION < 30200}
+   PSHColumnID = ^TSHColumnID;
+
+   IShellFolder2 = interface(IShellFolder)
+      ['{93F2F68C-1D1B-11d3-A30E-00C04F79ABD1}']
+      function GetDefaultSearchGUID(out guid:TGUID):HResult;StdCall;
+      function EnumSearches(out ppenum:IEnumExtraSearch):HResult;StdCall;
+      function GetDefaultColumn(dwres:DWORD;psort :pulong; pdisplay:pulong):HResult;StdCall;
+      function GetDefaultColumnState(icolumn:UINT;pscflag:PSHCOLSTATEF):HResult;StdCall;
+      function GetDetailsEx(pidl:LPCITEMIDLIST;pscid:PSHCOLUMNID; pv : pOLEvariant):HResult;StdCall;
+      function GetDetailsOf(pidl:LPCITEMIDLIST;iColumn:UINT;psd:PSHELLDETAILS):HResult;StdCall;
+      function MapColumnToSCID(iColumn:UINT;pscid:PSHCOLUMNID):HResult;StdCall;
+   end;
+{$ENDIF}
+
 const
 const
   SIID_DRIVENET = 9;
   SIID_DRIVENET = 9;
   SIID_ZIPFILE = 105;
   SIID_ZIPFILE = 105;
@@ -93,12 +108,8 @@ function SHFileIsLinkToFolder(const FileName: String; out LinkTarget: String): B
 
 
 function SHGetFolderLocation(hwnd: HWND; csidl: Longint; hToken: HANDLE; dwFlags: DWORD; var ppidl: LPITEMIDLIST): HRESULT; stdcall; external shell32 name 'SHGetFolderLocation';
 function SHGetFolderLocation(hwnd: HWND; csidl: Longint; hToken: HANDLE; dwFlags: DWORD; var ppidl: LPITEMIDLIST): HRESULT; stdcall; external shell32 name 'SHGetFolderLocation';
 
 
-function PathIsUNCA(pszPath: LPCSTR): WINBOOL; stdcall; external 'shlwapi' name 'PathIsUNCA';
 function PathIsUNCW(pwszPath: LPCWSTR): WINBOOL; stdcall; external 'shlwapi' name 'PathIsUNCW';
 function PathIsUNCW(pwszPath: LPCWSTR): WINBOOL; stdcall; external 'shlwapi' name 'PathIsUNCW';
-
-function PathFindNextComponentA(pszPath: LPCSTR): LPSTR; stdcall; external 'shlwapi' name 'PathFindNextComponentA';
 function PathFindNextComponentW(pwszPath: LPCWSTR): LPWSTR; stdcall; external 'shlwapi' name 'PathFindNextComponentW';
 function PathFindNextComponentW(pwszPath: LPCWSTR): LPWSTR; stdcall; external 'shlwapi' name 'PathFindNextComponentW';
-
 function StrRetToBufW(pstr: PSTRRET; pidl: PItemIDList; pszBuf: LPWSTR; cchBuf: UINT): HRESULT; stdcall; external 'shlwapi.dll';
 function StrRetToBufW(pstr: PSTRRET; pidl: PItemIDList; pszBuf: LPWSTR; cchBuf: UINT): HRESULT; stdcall; external 'shlwapi.dll';
 
 
 procedure OleErrorUTF8(ErrorCode: HResult);
 procedure OleErrorUTF8(ErrorCode: HResult);

+ 1 - 0
src/ulng.pas

@@ -397,6 +397,7 @@ resourcestring
   rsMsgErrInvalidLink = 'Invalid link';
   rsMsgErrInvalidLink = 'Invalid link';
   // Vfs
   // Vfs
   rsVfsNetwork = 'Network';
   rsVfsNetwork = 'Network';
+  rsVfsRecycleBin = 'Recycle Bin';
 
 
   // Buttons.
   // Buttons.
   rsDlgButtonOK = '&OK';
   rsDlgButtonOK = '&OK';

+ 9 - 0
src/umaincommands.pas

@@ -727,6 +727,7 @@ end;
 
 
 procedure TMainCommands.DoContextMenu(Panel: TFileView; X, Y: Integer; Background: Boolean; UserWishForContextMenu:TUserWishForContextMenu);
 procedure TMainCommands.DoContextMenu(Panel: TFileView; X, Y: Integer; Background: Boolean; UserWishForContextMenu:TUserWishForContextMenu);
 var
 var
+  Index: Integer;
   aFile: TFile = nil;
   aFile: TFile = nil;
   aFiles: TFiles = nil;
   aFiles: TFiles = nil;
   sPath, sName: String;
   sPath, sName: String;
@@ -769,6 +770,14 @@ begin
     try
     try
       if aFiles.Count > 0 then
       if aFiles.Count > 0 then
       try
       try
+        if fspLinksToLocalFiles in Panel.FileSource.Properties then
+        begin
+          for Index:= 0 to aFiles.Count - 1 do
+          begin
+            aFile:= aFiles[Index];
+            Panel.FileSource.GetLocalName(aFile);
+          end;
+        end;
         ShowContextMenu(frmMain, aFiles, X, Y, Background, nil, UserWishForContextMenu);
         ShowContextMenu(frmMain, aFiles, X, Y, Background, nil, UserWishForContextMenu);
       except
       except
         on e: EContextMenuException do
         on e: EContextMenuException do