Sfoglia il codice sorgente

UPD: Use "parsing" name to get objects

Alexander Koblov 2 anni fa
parent
commit
c6322a03ee

+ 5 - 5
src/filesources/shellfolder/ushellcopyoperation.pas

@@ -101,7 +101,7 @@ end;
 
 procedure TShellCopyOperation.Initialize;
 var
-  aFile: TFile;
+  AName: String;
   Index: Integer;
   AObject: PItemIDList;
   AFolder: IShellFolder2;
@@ -112,14 +112,14 @@ begin
   try
     for Index := 0 to SourceFiles.Count - 1 do
     begin
-      aFile:= SourceFiles[Index];
-      CheckObject(FShellFileSource.FindObject(aFile.FullPath, AObject), aFile.FullPath);
+      AName:= SourceFiles[Index].LinkProperty.LinkTo;
+      OleCheck(FShellFileSource.ParseDisplayName(AName, AObject));
       FSourceFilesTree.Add(AObject);
     end;
     case GetID of
       fsoCopy:
       begin
-        CheckObject(FShellFileSource.FindFolder(TargetPath, AFolder), TargetPath);
+        OleCheck(FShellFileSource.FindFolder(TargetPath, AFolder));
         OleCheck(SHGetIDListFromObject(AFolder, AObject));
         try
           OleCheck(SHCreateItemFromIDList(AObject, IShellItem, FTargetFolder));
@@ -183,7 +183,7 @@ begin
       AObject:= ILCreateFromPathW(PWideChar(CeUtf8ToUtf16(aFile.FullPath)));
       FSourceFilesTree.Add(AObject);
     end;
-    CheckObject(FShellFileSource.FindFolder(TargetPath, AFolder), TargetPath);
+    OleCheck(FShellFileSource.FindFolder(TargetPath, AFolder));
     OleCheck(SHGetIDListFromObject(AFolder, AObject));
     OleCheck(SHCreateItemFromIDList(AObject, IShellItem, FTargetFolder));
   except

+ 3 - 3
src/filesources/shellfolder/ushelldeleteoperation.pas

@@ -73,7 +73,7 @@ end;
 
 procedure TShellDeleteOperation.Initialize;
 var
-  aFile: TFile;
+  AName: String;
   Index: Integer;
   AObject: PItemIDList;
 begin
@@ -84,8 +84,8 @@ begin
   try
     for Index := 0 to FilesToDelete.Count - 1 do
     begin
-      aFile := FilesToDelete[Index];
-      CheckObject(FShellFileSource.FindObject(aFile.FullPath, AObject), aFile.FullPath);
+      AName := FilesToDelete[Index].LinkProperty.LinkTo;
+      OleCheck(FShellFileSource.ParseDisplayName(AName, AObject));
       FSourceFilesTree.Add(AObject);
     end;
   except

+ 8 - 0
src/filesources/shellfolder/ushellfilesource.pas

@@ -20,6 +20,7 @@ type
     function CreateFolder(AParent: IShellFolder2; const Name: String): HRESULT;
     function FindFolder(const Path: String; out AValue: IShellFolder2): HRESULT;
     function FindObject(const AObject: String; out AValue: PItemIDList): HRESULT;
+    function ParseDisplayName(const AName: String; out PIDL: PItemIDList): HRESULT;
     function FindObject(AParent: IShellFolder2; const AName: String; out AValue: PItemIDList): HRESULT;
   end;
 
@@ -46,6 +47,7 @@ type
     function CreateFolder(AParent: IShellFolder2; const Name: String): HRESULT;
     function FindFolder(const Path: String; out AValue: IShellFolder2): HRESULT;
     function FindObject(const AObject: String; out AValue: PItemIDList): HRESULT;
+    function ParseDisplayName(const AName: String; out PIDL: PItemIDList): HRESULT;
     function FindObject(AParent: IShellFolder2; const AName: String; out AValue: PItemIDList): HRESULT;
 
     function CreateDirectory(const Path: String): Boolean; override;
@@ -172,6 +174,12 @@ begin
   end;
 end;
 
+function TShellFileSource.ParseDisplayName(const AName: String; out
+  PIDL: PItemIDList): HRESULT;
+begin
+  Result:= uShellFolder.ParseDisplayName(FDesktopFolder, AName, PIDL);
+end;
+
 function TShellFileSource.FindObject(AParent: IShellFolder2;
   const AName: String; out AValue: PItemIDList): HRESULT;
 var

+ 0 - 10
src/filesources/shellfolder/ushellfilesourceutil.pas

@@ -58,8 +58,6 @@ type
     function ResumeTimer: HResult; stdcall;
   end;
 
-procedure CheckObject(Result: HResult; const AName: String); inline;
-
 var
   SHCreateItemWithParent: function(pidlParent: PCIDLIST_ABSOLUTE; psfParent: IShellFolder;
                                    pidl: PCUITEMID_CHILD; const riid: REFIID; out ppvItem): HRESULT; stdcall;
@@ -84,14 +82,6 @@ uses
 var
   AModule: HMODULE;
 
-procedure CheckObject(Result: HResult; const AName: String);
-begin
-  if Failed(Result) then
-  begin
-    raise EOleError.Create(mbSysErrorMessage(Result) + LineEnding + AName);
-  end;
-end;
-
 { TItemList }
 
 destructor TItemList.Destroy;

+ 0 - 2
src/filesources/shellfolder/ushelllistoperation.pas

@@ -60,12 +60,10 @@ begin
 
     if Succeeded(AFolder.GetAttributesOf(1, PIDL, rgfInOut)) then
     begin
-      {
       if (rgfInOut and SFGAO_STORAGE <> 0) then
       begin
         AFile.Attributes:= FILE_ATTRIBUTE_DEVICE or FILE_ATTRIBUTE_VIRTUAL;
       end;
-      }
       if (rgfInOut and SFGAO_FOLDER <> 0) then
       begin
         AFile.Attributes:= AFile.Attributes or FILE_ATTRIBUTE_DIRECTORY;

+ 4 - 4
src/filesources/shellfolder/ushellmoveoperation.pas

@@ -78,7 +78,7 @@ end;
 
 procedure TShellMoveOperation.Initialize;
 var
-  aFile: TFile;
+  AName: String;
   Index: Integer;
   AObject: PItemIDList;
   AFolder: IShellFolder2;
@@ -89,11 +89,11 @@ begin
   try
     for Index := 0 to SourceFiles.Count - 1 do
     begin
-      aFile := SourceFiles[Index];
-      CheckObject(FShellFileSource.FindObject(aFile.FullPath, AObject), aFile.FullPath);
+      AName:= SourceFiles[Index].LinkProperty.LinkTo;
+      OleCheck(FShellFileSource.ParseDisplayName(AName, AObject));
       FSourceFilesTree.Add(AObject);
     end;
-    CheckObject(FShellFileSource.FindFolder(TargetPath, AFolder), TargetPath);
+    OleCheck(FShellFileSource.FindFolder(TargetPath, AFolder));
     OleCheck(SHGetIDListFromObject(AFolder, AObject));
     try
       OleCheck(SHCreateItemFromIDList(AObject, IShellItem, FTargetFolder));

+ 3 - 3
src/filesources/shellfolder/ushellsetfilepropertyoperation.pas

@@ -84,7 +84,7 @@ end;
 
 procedure TShellSetFilePropertyOperation.Initialize;
 var
-  aFile: TFile;
+  AName: String;
   Index: Integer;
   AObject: PItemIDList;
 begin
@@ -94,8 +94,8 @@ begin
   try
     for Index := 0 to TargetFiles.Count - 1 do
     begin
-      aFile := TargetFiles[Index];
-      CheckObject(FShellFileSource.FindObject(aFile.FullPath, AObject), aFile.FullPath);
+      AName:= TargetFiles[Index].LinkProperty.LinkTo;
+      OleCheck(FShellFileSource.ParseDisplayName(AName, AObject));
       FSourceFilesTree.Add(AObject);
     end;
   except

+ 1 - 7
src/platform/upixmapmanager.pas

@@ -1344,15 +1344,9 @@ const
   uFlags: UINT = SHGFI_SYSICONINDEX or SHGFI_PIDL;
 var
   PIDL: PItemIDList;
-  pchEaten: ULONG = 0;
-  AName: UnicodeString;
   FileInfo: TSHFileInfoW;
-  dwAttributes: ULONG = 0;
 begin
-  AName:= CeUtf8ToUtf16(AFile.LinkProperty.LinkTo);
-
-  if Succeeded(FDesktopFolder.ParseDisplayName(0, nil, PWideChar(AName),
-                                               pchEaten, PIDL, dwAttributes)) then
+  if Succeeded(ParseDisplayName(FDesktopFolder, AFile.LinkProperty.LinkTo, PIDL)) then
   try
     if (SHGetFileInfoW(PWideChar(PIDL), 0, {%H-}FileInfo,
                        SizeOf(FileInfo), uFlags) <> 0) then

+ 106 - 1
src/platform/win/ushellfolder.pas

@@ -114,13 +114,14 @@ function GetIsFolder(AParent: IShellFolder; PIDL: PItemIDList): Boolean;
 function GetDisplayName(AFolder: IShellFolder; PIDL: PItemIDList; Flags: DWORD): String;
 function GetDisplayNameEx(AFolder: IShellFolder2; PIDL: PItemIDList; Flags: DWORD): String;
 function GetDetails(AFolder: IShellFolder2; PIDL: PItemIDList; const pscid: SHCOLUMNID): OleVariant;
+function ParseDisplayName(Desktop: IShellFolder; const AName: String; out PIDL: PItemIDList): HRESULT;
 
 function CreateDefaultContextMenu(constref pdcm: TDefContextMenu; const riid: REFIID; out ppv): HRESULT;
 
 implementation
 
 uses
-  Variants, ShellApi, LazUTF8, DCConvertEncoding;
+  Variants, ShellApi, LazUTF8, DCConvertEncoding, DCStrUtils;
 
 const
   KF_FLAG_DEFAULT = $00000000;
@@ -189,6 +190,110 @@ begin
    Result:= Unassigned;
 end;
 
+function SplitParsingPath(const S: String): TStringArray;
+var
+  P: PAnsiChar;
+  AItem: String;
+  I, Len: Integer;
+  Start: Integer = 0;
+begin
+  I:= 0;
+  Len:= Length(S);
+  P:= PAnsiChar(S);
+  Result:= Default(TStringArray);
+  while I < Len do
+  begin
+    if P[I] = '\' then
+    begin
+      SetString(AItem, @P[Start], I - Start);
+      AddString(Result, AItem);
+      Start:= I + 1;
+      // Special case for "\\?\" and "\\.\"
+      if (P[I + 1] = '\') and (P[I + 2] = '\') and (P[I + 3] in ['?', '.']) and (P[I + 4] = '\') then
+        Inc(I, 4);
+    end;
+    Inc(I);
+  end;
+  if Start < Len then
+  begin
+    SetString(AItem, @P[Start], Len - Start);
+    AddString(Result, AItem);
+  end;
+end;
+
+function ParseDisplayName(Desktop: IShellFolder; const AName: String; out
+  PIDL: PItemIDList): HRESULT;
+var
+  AItem: String;
+  Index: Integer;
+  pchEaten: ULONG;
+  APath: TStringArray;
+  NumIDs: LongWord = 0;
+  dwAttributes: ULONG = 0;
+  EnumIDList: IEnumIDList;
+  ParentFolder, AFolder: IShellFolder;
+  ParentPIDL, RelativePIDL: PItemIDList;
+begin
+  APath:= SplitParsingPath(AName);
+
+  ParentFolder:= Desktop;
+  SHGetFolderLocation(0, CSIDL_DESKTOP, 0, 0, {%H-}ParentPIDL);
+
+  for Index:= 0 to High(APath) do
+  begin
+    dwAttributes:= 0;
+    AItem:= APath[Index];
+    Result:= ParentFolder.ParseDisplayName(0, nil, PWideChar(CeUtf8ToUtf16(AItem)), pchEaten, RelativePIDL, dwAttributes);
+
+    if Failed(Result) then
+    begin
+      Result:= ParentFolder.EnumObjects(0, SHCONTF_FOLDERS or SHCONTF_NONFOLDERS or SHCONTF_STORAGE or SHCONTF_INCLUDEHIDDEN, EnumIDList);
+
+      if Succeeded(Result) then
+      begin
+        Result:= STG_E_PATHNOTFOUND;
+
+        while EnumIDList.Next(1, RelativePIDL, NumIDs) = S_OK do
+        begin
+          if AItem = GetDisplayName(ParentFolder, RelativePIDL, SHGDN_INFOLDER or SHGDN_FORPARSING) then
+          begin
+            Result:= S_OK;
+            Break;
+          end;
+          CoTaskMemFree(RelativePIDL);
+        end;
+      end;
+    end;
+
+    if Succeeded(Result) then
+    begin
+      PIDL:= ILCombine(ParentPIDL, RelativePIDL);
+    end;
+
+    CoTaskMemFree(ParentPIDL);
+
+    if Failed(Result) then Break;
+
+    if Index < High(APath) then
+    begin
+      Result:= ParentFolder.BindToObject(RelativePIDL, nil, IID_IShellFolder, Pointer(AFolder));
+      if Succeeded(Result) then
+      begin
+        ParentPIDL:= PIDL;
+        ParentFolder:= AFolder;
+      end;
+    end;
+
+    CoTaskMemFree(RelativePIDL);
+
+    if Failed(Result) then
+    begin
+      CoTaskMemFree(PIDL);
+      Break;
+    end;
+  end;
+end;
+
 function CreateDefaultContextMenu(constref pdcm: TDefContextMenu;
   const riid: REFIID; out ppv): HRESULT;
 begin