[SHELL32]
authorAleksandar Andrejevic <aandrejevic@reactos.org>
Sat, 9 Aug 2014 13:40:13 +0000 (13:40 +0000)
committerAleksandar Andrejevic <aandrejevic@reactos.org>
Sat, 9 Aug 2014 13:40:13 +0000 (13:40 +0000)
- Greatly optimize file icon retrieval by reducing the times we try to access the disk.
- Store icons in a binary tree in the shell icon cache for faster retrieval.
Patch by Huw Campbell committed at the request of Giannis Adamopoulos.

svn path=/trunk/; revision=63845

reactos/dll/win32/shell32/folders.cpp
reactos/dll/win32/shell32/iconcache.cpp
reactos/dll/win32/shell32/shfldr.h
reactos/dll/win32/shell32/shlfolder.cpp

index 9df6d6d..5dc06b1 100644 (file)
@@ -28,6 +28,7 @@ static HRESULT getIconLocationForFolder(LPCITEMIDLIST pidl, UINT uFlags,
                                         LPWSTR szIconFile, UINT cchMax, int *piIndex, UINT *pwFlags)
 {
     int icon_idx;
+    bool cont=TRUE;
     WCHAR wszPath[MAX_PATH];
     WCHAR wszCLSIDValue[CHARS_IN_GUID];
     static const WCHAR shellClassInfo[] = { '.', 'S', 'h', 'e', 'l', 'l', 'C', 'l', 'a', 's', 's', 'I', 'n', 'f', 'o', 0 };
@@ -36,27 +37,40 @@ static HRESULT getIconLocationForFolder(LPCITEMIDLIST pidl, UINT uFlags,
     static const WCHAR clsid2[] = { 'C', 'L', 'S', 'I', 'D', '2', 0 };
     static const WCHAR iconIndex[] = { 'I', 'c', 'o', 'n', 'I', 'n', 'd', 'e', 'x', 0 };
 
-    if (SHELL32_GetCustomFolderAttribute(pidl, shellClassInfo, iconFile,
-                                         wszPath, MAX_PATH))
+    /*
+    Optimisation. GetCustomFolderAttribute has a critical lock on it, and isn't fast.
+    Test the water (i.e., see if the attribute exists) before questioning it three times
+    when most folders don't use it at all.
+    */
+    WCHAR wszBigToe[3];
+    if (!(uFlags & GIL_DEFAULTICON) && SHELL32_GetCustomFolderAttributes(pidl, shellClassInfo,
+                                         wszBigToe, 3))
     {
-        WCHAR wszIconIndex[10];
-        SHELL32_GetCustomFolderAttribute(pidl, shellClassInfo, iconIndex,
-                                         wszIconIndex, 10);
-        *piIndex = _wtoi(wszIconIndex);
-    }
-    else if (SHELL32_GetCustomFolderAttribute(pidl, shellClassInfo, clsid,
-             wszCLSIDValue, CHARS_IN_GUID) &&
-             HCR_GetIconW(wszCLSIDValue, szIconFile, NULL, cchMax, &icon_idx))
-    {
-        *piIndex = icon_idx;
-    }
-    else if (SHELL32_GetCustomFolderAttribute(pidl, shellClassInfo, clsid2,
-             wszCLSIDValue, CHARS_IN_GUID) &&
-             HCR_GetIconW(wszCLSIDValue, szIconFile, NULL, cchMax, &icon_idx))
-    {
-        *piIndex = icon_idx;
+        if (SHELL32_GetCustomFolderAttribute(pidl, shellClassInfo, iconFile,
+                                             wszPath, MAX_PATH))
+        {
+            WCHAR wszIconIndex[10];
+            SHELL32_GetCustomFolderAttribute(pidl, shellClassInfo, iconIndex,
+                                             wszIconIndex, 10);
+            *piIndex = _wtoi(wszIconIndex);
+            cont=FALSE;
+        }
+        else if (SHELL32_GetCustomFolderAttribute(pidl, shellClassInfo, clsid,
+                 wszCLSIDValue, CHARS_IN_GUID) &&
+                 HCR_GetIconW(wszCLSIDValue, szIconFile, NULL, cchMax, &icon_idx))
+        {
+            *piIndex = icon_idx;
+            cont=FALSE;
+        }
+        else if (SHELL32_GetCustomFolderAttribute(pidl, shellClassInfo, clsid2,
+                 wszCLSIDValue, CHARS_IN_GUID) &&
+                 HCR_GetIconW(wszCLSIDValue, szIconFile, NULL, cchMax, &icon_idx))
+        {
+            *piIndex = icon_idx;
+            cont=FALSE;
+        }
     }
-    else
+    if (cont)
     {
         static const WCHAR folder[] = { 'F', 'o', 'l', 'd', 'e', 'r', 0 };
 
@@ -322,6 +336,10 @@ IExtractIconW* IExtractIconW_Constructor(LPCITEMIDLIST pidl)
                           &flags)))
         {
             initIcon->SetNormalIcon(wTemp, icon_idx);
+            // FIXME: if/when getIconLocationForFolder does something for 
+            //        GIL_FORSHORTCUT, code below should be uncommented. and
+            //        the following line removed.
+            initIcon->SetShortcutIcon(wTemp, icon_idx);
         }
         if (SUCCEEDED(getIconLocationForFolder(
                           pidl, GIL_DEFAULTICON, wTemp, MAX_PATH,
@@ -330,13 +348,13 @@ IExtractIconW* IExtractIconW_Constructor(LPCITEMIDLIST pidl)
         {
             initIcon->SetDefaultIcon(wTemp, icon_idx);
         }
-        if (SUCCEEDED(getIconLocationForFolder(
-                          pidl, GIL_FORSHORTCUT, wTemp, MAX_PATH,
-                          &icon_idx,
-                          &flags)))
-        {
-            initIcon->SetShortcutIcon(wTemp, icon_idx);
-        }
+        // if (SUCCEEDED(getIconLocationForFolder(
+        //                   pidl, GIL_FORSHORTCUT, wTemp, MAX_PATH,
+        //                   &icon_idx,
+        //                   &flags)))
+        // {
+        //     initIcon->SetShortcutIcon(wTemp, icon_idx);
+        // }
         if (SUCCEEDED(getIconLocationForFolder(
                           pidl, GIL_OPENICON, wTemp, MAX_PATH,
                           &icon_idx,
index 5027d77..713b34b 100644 (file)
@@ -64,14 +64,14 @@ static INT CALLBACK SIC_CompareEntries( LPVOID p1, LPVOID p2, LPARAM lparam)
      * loaded from, their resource index and the fact if they have a shortcut
      * icon overlay or not.
      */
-    if (e1->dwSourceIndex != e2->dwSourceIndex || /* first the faster one */
-        (e1->dwFlags & GIL_FORSHORTCUT) != (e2->dwFlags & GIL_FORSHORTCUT))
-      return 1;
-
-    if (wcsicmp(e1->sSourceFile,e2->sSourceFile))
-      return 1;
-
-    return 0;
+    /* first the faster one */
+    if (e1->dwSourceIndex != e2->dwSourceIndex)
+      return (e1->dwSourceIndex < e2->dwSourceIndex) ? -1 : 1;
+
+    if ((e1->dwFlags & GIL_FORSHORTCUT) != (e2->dwFlags & GIL_FORSHORTCUT)) 
+      return ((e1->dwFlags & GIL_FORSHORTCUT) < (e2->dwFlags & GIL_FORSHORTCUT)) ? -1 : 1;
+  
+    return wcsicmp(e1->sSourceFile,e2->sSourceFile);
 }
 
 /* declare SIC_LoadOverlayIcon() */
@@ -338,7 +338,8 @@ static INT SIC_IconAppend (LPCWSTR sSourceFile, INT dwSourceIndex, HICON hSmallI
 
     EnterCriticalSection(&SHELL32_SicCS);
 
-    indexDPA = DPA_InsertPtr(sic_hdpa, 0x7fff, lpsice);
+    indexDPA = DPA_Search (sic_hdpa, lpsice, 0, SIC_CompareEntries, 0, DPAS_SORTED|DPAS_INSERTAFTER);
+    indexDPA = DPA_InsertPtr(sic_hdpa, indexDPA, lpsice);
     if ( -1 == indexDPA )
     {
         ret = INVALID_INDEX;
@@ -468,7 +469,7 @@ INT SIC_GetIconIndex (LPCWSTR sSourceFile, INT dwSourceIndex, DWORD dwFlags )
     if (NULL != DPA_GetPtr (sic_hdpa, 0))
     {
       /* search linear from position 0*/
-      index = DPA_Search (sic_hdpa, &sice, 0, SIC_CompareEntries, 0, 0);
+      index = DPA_Search (sic_hdpa, &sice, 0, SIC_CompareEntries, 0, DPAS_SORTED);
     }
 
     if ( INVALID_INDEX == index )
index 81111ce..3374b19 100644 (file)
@@ -37,6 +37,7 @@ typedef struct {
 #define GET_SHGDN_RELATION(dwFlags)    ((DWORD)dwFlags & (DWORD)0x000000FF)
 
 BOOL SHELL32_GetCustomFolderAttribute (LPCITEMIDLIST pidl, LPCWSTR pwszHeading, LPCWSTR pwszAttribute, LPWSTR pwszValue, DWORD cchValue);
+BOOL SHELL32_GetCustomFolderAttributes (LPCITEMIDLIST pidl, LPCWSTR pwszHeading, LPWSTR pwszValue, DWORD cchValue);
 
 LPCWSTR GetNextElementW (LPCWSTR pszNext, LPWSTR pszOut, DWORD dwOut);
 HRESULT SHELL32_ParseNextElement (IShellFolder2 * psf, HWND hwndOwner, LPBC pbc, LPITEMIDLIST * pidlInOut,
index e821066..5f9a8ec 100644 (file)
@@ -81,6 +81,33 @@ BOOL SHELL32_GetCustomFolderAttribute(
     return FALSE;
 }
 
+BOOL SHELL32_GetCustomFolderAttributes(
+    LPCITEMIDLIST pidl, LPCWSTR pwszHeading,
+    LPWSTR pwszValue, DWORD cchValue)
+{
+    DWORD dwAttrib = FILE_ATTRIBUTE_SYSTEM;
+    WCHAR wszFolderPath[MAX_PATH];
+
+    /* Hack around not having system attribute on non-Windows file systems */
+    if (0)
+        dwAttrib = _ILGetFileAttributes(pidl, NULL, 0);
+
+    if (dwAttrib & FILE_ATTRIBUTE_SYSTEM)
+    {
+        if (!SHGetPathFromIDListW(pidl, wszFolderPath))
+            return FALSE;
+
+        static const WCHAR wszDesktopIni[] =
+                {'d','e','s','k','t','o','p','.','i','n','i',0};
+
+        PathAddBackslashW(wszFolderPath);
+        PathAppendW(wszFolderPath, wszDesktopIni);
+        return GetPrivateProfileSectionW(pwszHeading, pwszValue, cchValue, wszFolderPath);
+    }
+    return FALSE;
+}
+
+
 /***************************************************************************
  *  GetNextElement (internal function)
  *