ソースを参照

Unifying calls to SHGetFileInfo

Source commit: 72c1c882d181c6f86928dad1698fba58bf63b4e6
Martin Prikryl 2 年 前
コミット
f6d3d47017
1 ファイル変更48 行追加49 行削除
  1. 48 49
      source/packages/filemng/DirView.pas

+ 48 - 49
source/packages/filemng/DirView.pas

@@ -225,7 +225,9 @@ type
     procedure WMDestroy(var Msg: TWMDestroy); message WM_DESTROY;
     procedure CMRecreateWnd(var Message: TMessage); message CM_RECREATEWND;
     procedure Load(DoFocusSomething: Boolean); override;
-    function GetFileInfo(pszPath: LPCWSTR; dwFileAttributes: DWORD; var psfi: TSHFileInfoW; cbFileInfo, uFlags: UINT): DWORD_PTR;
+    function GetFileInfo(
+      CanUsePIDL: Boolean; PIDL: PItemIDList; Path: string; CanTimeout: Boolean;
+      dwFileAttributes: DWORD; var psfi: TSHFileInfoW; uFlags: UINT): DWORD_PTR;
     function DoCopyToClipboard(Focused: Boolean; Cut: Boolean; Operation: TClipBoardOperation): Boolean;
 
     function HiddenCount: Integer; override;
@@ -707,16 +709,9 @@ begin
             PChar(CurrentFilePath), Eaten, CurrentItemData.PIDL, ShAttr);
         end;
 
-        if (not ForceByName) and Assigned(CurrentItemData.PIDL) then
-        begin
-          SHGetFileInfo(PChar(CurrentItemData.PIDL), 0, FileInfo, SizeOf(FileInfo),
-            SHGFI_TYPENAME or SHGFI_USEFILEATTRIBUTES or SHGFI_SYSICONINDEX or SHGFI_PIDL)
-        end
-          else
-        begin
-          SHGetFileInfo(PChar(FileIconForName), 0, FileInfo, SizeOf(FileInfo),
-            SHGFI_TYPENAME or SHGFI_USEFILEATTRIBUTES or SHGFI_SYSICONINDEX);
-        end;
+        FOwner.GetFileInfo(
+          (not ForceByName), CurrentItemData.PIDL, FileIconForName, False,
+          0, FileInfo, SHGFI_TYPENAME or SHGFI_USEFILEATTRIBUTES or SHGFI_SYSICONINDEX);
       except
         {Capture exceptions generated by the shell}
         FSyncIcon := UnKnownFileIcon;
@@ -1159,8 +1154,7 @@ begin
              FileMatches(DisplayName, SRec)) then
          begin
            {Filetype and icon:}
-           SHGetFileInfo(PChar(FQPIDL), 0, FileInfo, SizeOf(FileInfo),
-            SHGFI_PIDL or SHGFI_TYPENAME or SHGFI_SYSICONINDEX);
+           GetFileInfo(True, FQPIDL, '', False, 0, FileInfo, SHGFI_TYPENAME or SHGFI_SYSICONINDEX);
 
            NewItem := AddItem(Srec);
            NewItem.Caption := DisplayName;
@@ -1759,16 +1753,37 @@ begin
 end; {GetAttrString}
 
 function TDirView.GetFileInfo(
-  pszPath: LPCWSTR; dwFileAttributes: DWORD; var psfi: TSHFileInfoW; cbFileInfo, uFlags: UINT): DWORD_PTR;
+  CanUsePIDL: Boolean; PIDL: PItemIDList; Path: string; CanTimeout: Boolean;
+  dwFileAttributes: DWORD; var psfi: TSHFileInfoW; uFlags: UINT): DWORD_PTR;
+var
+  pszPath: LPCWSTR;
+  cbFileInfo: UINT;
 begin
-  if TimeoutShellIconRetrieval then
+  cbFileInfo := SizeOf(psfi);
+  FillChar(psfi, cbFileInfo, #0);
+
+  if CanUsePIDL and Assigned(PIDL) then
   begin
-     Result := SHGetFileInfoWithTimeout(pszPath, dwFileAttributes, psfi, cbFileInfo, uFlags, MSecsPerSec div 4);
+    pszPath := PChar(PIDL);
+    uFlags := uFlags or SHGFI_PIDL;
+  end
+    else pszPath := PChar(Path);
+
+  // CanTimeout is False in scenarios, where we did not have any reports of hangs, to avoid thread overhead.
+  if TimeoutShellIconRetrieval and CanTimeout then
+  begin
+    Result := SHGetFileInfoWithTimeout(pszPath, dwFileAttributes, psfi, cbFileInfo, uFlags, MSecsPerSec div 4);
   end
     else
   begin
     Result := SHGetFileInfo(pszPath, dwFileAttributes, psfi, cbFileInfo, uFlags);
   end;
+
+  if Result = 0 then
+  begin
+    psfi.szTypeName[0] := #0;
+    psfi.iIcon := 0;
+  end;
 end;
 
 procedure TDirView.GetDisplayData(Item: TListItem; FetchIcon: Boolean);
@@ -1779,6 +1794,7 @@ var
   Eaten: ULONG;
   shAttr: ULONG;
   FileIconForName, FullName: string;
+  FileAttributes: UINT;
 begin
   Assert(Assigned(Item) and Assigned(Item.Data));
   with PFileRec(Item.Data)^ do
@@ -1808,23 +1824,13 @@ begin
           begin
             try
               {Retrieve icon and typename for the directory}
-              if Assigned(PIDL) then
-              begin
-                SHGetFileInfo(PChar(PIDL), 0, FileInfo, SizeOf(FileInfo),
-                  SHGFI_TYPENAME or SHGFI_SYSICONINDEX or SHGFI_PIDL)
-              end
-                else
-              begin
-                SHGetFileInfo(PChar(FPath + '\' + FileName), 0, FileInfo, SizeOf(FileInfo),
-                  SHGFI_TYPENAME or SHGFI_SYSICONINDEX);
-              end;
+              GetFileInfo(True, PIDL, FPath + '\' + FileName, False, 0, FileInfo, SHGFI_TYPENAME or SHGFI_SYSICONINDEX);
 
               if (FileInfo.iIcon <= 0) or (FileInfo.iIcon > SmallImages.Count) then
               begin
                 {Invalid icon returned: retry with access file attribute flag:}
-                SHGetFileInfo(PChar(FPath + '\' + FileName), FILE_ATTRIBUTE_DIRECTORY,
-                  FileInfo, SizeOf(FileInfo),
-                  SHGFI_TYPENAME or SHGFI_SYSICONINDEX or SHGFI_USEFILEATTRIBUTES);
+                GetFileInfo(False, nil, FPath + '\' + FileName, False,
+                  FILE_ATTRIBUTE_DIRECTORY, FileInfo, SHGFI_TYPENAME or SHGFI_SYSICONINDEX or SHGFI_USEFILEATTRIBUTES);
               end;
               TypeName := FileInfo.szTypeName;
               ImageIndex := FileInfo.iIcon;
@@ -1854,25 +1860,18 @@ begin
               OnFileIconForName(Self, Item, FileIconForName);
               ForceByName := (FileIconForName <> FullName);
             end;
-            if (not ForceByName) and Assigned(PIDL) then
+            // Files with PIDL are typically .exe files.
+            // It may take long to retrieve an icon from exe file.
+            // We typically do not get here, now that we have UseIconUpdateThread enabled.
+            if GetFileInfo(
+                 (not ForceByName), PIDL, FileIconForName, True, FILE_ATTRIBUTE_NORMAL, FileInfo,
+                 SHGFI_TYPENAME or SHGFI_USEFILEATTRIBUTES or SHGFI_SYSICONINDEX) = 0 then
             begin
-              // Files with PIDL are typically .exe files.
-              // It may take long to retrieve an icon from exe file.
-              // We typically do not get here, now that we have UseIconUpdateThread enabled.
-              if GetFileInfo(
-                   PChar(PIDL), FILE_ATTRIBUTE_NORMAL, FileInfo, SizeOf(FileInfo),
-                   SHGFI_TYPENAME or SHGFI_USEFILEATTRIBUTES or SHGFI_SYSICONINDEX or SHGFI_PIDL) = 0 then
+              if Assigned(PIDL) then
               begin
-                FileInfo.szTypeName[0] := #0;
                 FileInfo.iIcon := DefaultExeIcon;
               end;
-            end
-              else
-            begin
-              GetFileInfo(PChar(FileIconForName), FILE_ATTRIBUTE_NORMAL, FileInfo, SizeOf(FileInfo),
-                SHGFI_TYPENAME or SHGFI_USEFILEATTRIBUTES or SHGFI_SYSICONINDEX);
             end;
-
             TypeName := FileInfo.szTypeName;
             ImageIndex := FileInfo.iIcon;
             IconEmpty := False;
@@ -1890,12 +1889,12 @@ begin
         else
       begin
         try
-          if IsDirectory then
-            SHGetFileInfo(PChar(FPath + '\' + FileName), FILE_ATTRIBUTE_DIRECTORY, FileInfo, SizeOf(FileInfo),
-              SHGFI_TYPENAME or SHGFI_USEFILEATTRIBUTES)
-          else
-            SHGetFileInfo(PChar(FPath + '\' + FileName), FILE_ATTRIBUTE_NORMAL, FileInfo, SizeOf(FileInfo),
-              SHGFI_TYPENAME or SHGFI_USEFILEATTRIBUTES);
+          if IsDirectory then FileAttributes := FILE_ATTRIBUTE_DIRECTORY
+            else FileAttributes := FILE_ATTRIBUTE_NORMAL;
+
+          GetFileInfo(
+            False, nil, FPath + '\' + FileName, False, FileAttributes, FileInfo,
+            SHGFI_TYPENAME or SHGFI_USEFILEATTRIBUTES);
           TypeName := FileInfo.szTypeName;
         except
           {Capture exceptions generated by the shell}