Sync to Wine-0_9_3:
[reactos.git] / reactos / lib / shell32 / iconcache.c
index 8ccdc3e..0008f34 100644 (file)
@@ -67,7 +67,7 @@ static CRITICAL_SECTION_DEBUG critsect_debug =
 {
     0, 0, &SHELL32_SicCS,
     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
-      0, 0, { 0, (DWORD)(__FILE__ ": SHELL32_SicCS") }
+      0, 0, { (DWORD_PTR)(__FILE__ ": SHELL32_SicCS") }
 };
 static CRITICAL_SECTION SHELL32_SicCS = { &critsect_debug, -1, 0, 0, 0, 0 };
 
@@ -96,6 +96,9 @@ static INT CALLBACK SIC_CompareEntries( LPVOID p1, LPVOID p2, LPARAM lparam)
        return 0;
 }
 
+/* declare SIC_LoadOverlayIcon() */
+static int SIC_LoadOverlayIcon(int idx);
+
 /*****************************************************************************
  * SIC_OverlayShortcutImage                    [internal]
  *
@@ -103,7 +106,7 @@ static INT CALLBACK SIC_CompareEntries( LPVOID p1, LPVOID p2, LPARAM lparam)
  *  Creates a new icon as a copy of the passed-in icon, overlayed with a
  *  shortcut image. 
  */
-static HICON SIC_OverlayShortcutImage(HICON SourceIcon)
+static HICON SIC_OverlayShortcutImage(HICON SourceIcon, BOOL large)
 {      ICONINFO SourceIconInfo, ShortcutIconInfo, TargetIconInfo;
        HICON ShortcutIcon, TargetIcon;
        BITMAP SourceBitmapInfo, ShortcutBitmapInfo;
@@ -115,15 +118,31 @@ static HICON SIC_OverlayShortcutImage(HICON SourceIcon)
          OldShortcutBitmap = NULL,
          OldTargetBitmap = NULL;
 
+       static int s_imgListIdx = -1;
+
        /* Get information about the source icon and shortcut overlay */
        if (! GetIconInfo(SourceIcon, &SourceIconInfo)
            || 0 == GetObjectW(SourceIconInfo.hbmColor, sizeof(BITMAP), &SourceBitmapInfo))
        {
          return NULL;
        }
-       ShortcutIcon = LoadImageW(shell32_hInstance, MAKEINTRESOURCEW(IDI_SHELL_SHORTCUT),
-                                 IMAGE_ICON, SourceBitmapInfo.bmWidth, SourceBitmapInfo.bmWidth,
-                                 LR_SHARED);
+
+       /* search for the shortcut icon only once */
+       if (s_imgListIdx == -1)
+           s_imgListIdx = SIC_LoadOverlayIcon(- IDI_SHELL_SHORTCUT);
+                           /* FIXME should use icon index 29 instead of the
+                              resource id, but not all icons are present yet
+                              so we can't use icon indices */
+
+       if (s_imgListIdx != -1)
+       {
+           if (large)
+               ShortcutIcon = ImageList_GetIcon(ShellBigIconList, s_imgListIdx, ILD_TRANSPARENT);
+           else
+               ShortcutIcon = ImageList_GetIcon(ShellSmallIconList, s_imgListIdx, ILD_TRANSPARENT);
+       } else
+           ShortcutIcon = NULL;
+
        if (NULL == ShortcutIcon
            || ! GetIconInfo(ShortcutIcon, &ShortcutIconInfo)
            || 0 == GetObjectW(ShortcutIconInfo.hbmColor, sizeof(BITMAP), &ShortcutBitmapInfo))
@@ -313,8 +332,8 @@ static INT SIC_LoadIcon (LPCWSTR sSourceFile, INT dwSourceIndex, DWORD dwFlags)
 
        if (0 != (dwFlags & GIL_FORSHORTCUT))
        {
-         hiconLargeShortcut = SIC_OverlayShortcutImage(hiconLarge);
-         hiconSmallShortcut = SIC_OverlayShortcutImage(hiconSmall);
+         hiconLargeShortcut = SIC_OverlayShortcutImage(hiconLarge, TRUE);
+         hiconSmallShortcut = SIC_OverlayShortcutImage(hiconSmall, FALSE);
          if (NULL != hiconLargeShortcut && NULL != hiconSmallShortcut)
          {
            hiconLarge = hiconLargeShortcut;
@@ -365,7 +384,7 @@ INT SIC_GetIconIndex (LPCWSTR sSourceFile, INT dwSourceIndex, DWORD dwFlags )
 
        if ( INVALID_INDEX == index )
        {
-         ret = SIC_LoadIcon (sSourceFile, dwSourceIndex, dwFlags);
+          ret = SIC_LoadIcon (sSourceFile, dwSourceIndex, dwFlags);
        }
        else
        {
@@ -378,15 +397,10 @@ INT SIC_GetIconIndex (LPCWSTR sSourceFile, INT dwSourceIndex, DWORD dwFlags )
 }
 /*****************************************************************************
  * SIC_Initialize                      [internal]
- *
- * NOTES
- *  hack to load the resources from the shell32.dll under a different dll name
- *  will be removed when the resource-compiler is ready
  */
 BOOL SIC_Initialize(void)
 {
        HICON           hSm, hLg;
-       UINT            index;
        int             cx_small, cy_small;
        int             cx_large, cy_large;
 
@@ -407,26 +421,27 @@ BOOL SIC_Initialize(void)
          return(FALSE);
        }
 
-       ShellSmallIconList = ImageList_Create(16,16,ILC_COLOR32|ILC_MASK,0,0x20);
-       ShellBigIconList = ImageList_Create(32,32,ILC_COLOR32|ILC_MASK,0,0x20);
+        ShellSmallIconList = ImageList_Create(cx_small,cy_small,ILC_COLOR32|ILC_MASK,0,0x20);
+        ShellBigIconList = ImageList_Create(cx_large,cy_large,ILC_COLOR32|ILC_MASK,0,0x20);
 
-       ImageList_SetBkColor(ShellSmallIconList, CLR_NONE);
-       ImageList_SetBkColor(ShellBigIconList, CLR_NONE);
+        ImageList_SetBkColor(ShellSmallIconList, CLR_NONE);
+        ImageList_SetBkColor(ShellBigIconList, CLR_NONE);
 
-       for (index=1; index<39; index++)
-       {
-         hSm = (HICON)LoadImageA(shell32_hInstance, MAKEINTRESOURCEA(index), IMAGE_ICON, cx_small, cy_small, LR_SHARED);
-         hLg = (HICON)LoadImageA(shell32_hInstance, MAKEINTRESOURCEA(index), IMAGE_ICON, cx_large, cy_large, LR_SHARED);
+        /* Load the document icon, which is used as the default if an icon isn't found. */
+        hSm = (HICON)LoadImageA(shell32_hInstance, MAKEINTRESOURCEA(IDI_SHELL_DOCUMENT), 
+                                IMAGE_ICON, cx_small, cy_small, LR_SHARED);
+        hLg = (HICON)LoadImageA(shell32_hInstance, MAKEINTRESOURCEA(IDI_SHELL_DOCUMENT), 
+                                IMAGE_ICON, cx_large, cy_large, LR_SHARED);
 
-         if(!hSm)
-         {
-           hSm = LoadImageA(shell32_hInstance, MAKEINTRESOURCEA(1), IMAGE_ICON, cx_small, cy_small, LR_SHARED);
-           hLg = LoadImageA(shell32_hInstance, MAKEINTRESOURCEA(1), IMAGE_ICON, cx_large, cy_large, LR_SHARED);
-         }
-         SIC_IconAppend (swShell32Name, index - 1, hSm, hLg, 0);
-         SIC_IconAppend (swShell32Name, -index, hSm, hLg, 0);
-       }
+        if (!hSm || !hLg) 
+        {
+          FIXME("Failed to load IDI_SHELL_DOCUMENT icon!\n");
+          return FALSE;
+        }
 
+        SIC_IconAppend (swShell32Name, IDI_SHELL_DOCUMENT-1, hSm, hLg, 0);
+        SIC_IconAppend (swShell32Name, -IDI_SHELL_DOCUMENT, hSm, hLg, 0);
+   
        TRACE("hIconSmall=%p hIconBig=%p\n",ShellSmallIconList, ShellBigIconList);
 
        return TRUE;
@@ -460,6 +475,52 @@ void SIC_Destroy(void)
        LeaveCriticalSection(&SHELL32_SicCS);
 }
 
+/*****************************************************************************
+ * SIC_LoadOverlayIcon                 [internal]
+ *
+ * Load a shell overlay icon and return its icon cache index.
+ */
+static int SIC_LoadOverlayIcon(int idx)
+{
+       WCHAR buffer[1024], wszIdx[8];
+       HKEY hKeyShellIcons;
+       LPCWSTR iconPath;
+       int iconIdx;
+
+       static const WCHAR wszShellIcons[] = {
+           'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
+           'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
+           'E','x','p','l','o','r','e','r','\\','S','h','e','l','l',' ','I','c','o','n','s',0
+       }; 
+       static const WCHAR wszNumFmt[] = {'%','d',0};
+
+       iconPath = swShell32Name;       /* default: load icon from shell32.dll */
+       iconIdx = idx;
+
+       if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszShellIcons, 0, KEY_READ, &hKeyShellIcons) == ERROR_SUCCESS)
+       {
+           DWORD count = sizeof(buffer);
+
+           sprintfW(wszIdx, wszNumFmt, idx);
+
+           /* read icon path and index */
+           if (RegQueryValueExW(hKeyShellIcons, wszIdx, NULL, NULL, (LPBYTE)buffer, &count) == ERROR_SUCCESS)
+           {
+               LPWSTR p = strchrW(buffer, ',');
+
+               if (p)
+                   *p++ = 0;
+
+               iconPath = buffer;
+               iconIdx = atoiW(p);
+           }
+
+           RegCloseKey(hKeyShellIcons);
+       }
+
+       return SIC_LoadIcon(iconPath, iconIdx, 0);
+}
+
 /*************************************************************************
  * Shell_GetImageList                  [SHELL32.71]
  *
@@ -498,29 +559,15 @@ BOOL PidlToSicIndex (
 {
        IExtractIconW   *ei;
        WCHAR           szIconFile[MAX_PATH];   /* file containing the icon */
-       char            szTemp[MAX_PATH];
        INT             iSourceIndex;           /* index or resID(negated) in this file */
        BOOL            ret = FALSE;
        UINT            dwFlags = 0;
-       HKEY            keyCls;
        int             iShortcutDefaultIndex = INVALID_INDEX;
 
        TRACE("sf=%p pidl=%p %s\n", sh, pidl, bBigIcon?"Big":"Small");
 
        if (SUCCEEDED (IShellFolder_GetUIObjectOf(sh, 0, 1, &pidl, &IID_IExtractIconW, 0, (void **)&ei)))
        {
-         if (_ILGetExtension(pidl, szTemp, MAX_PATH) &&
-             HCR_MapTypeToValueA(szTemp, szTemp, MAX_PATH, TRUE))
-         {
-           if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CLASSES_ROOT, szTemp, 0, KEY_QUERY_VALUE, &keyCls))
-           {
-             if (ERROR_SUCCESS == RegQueryValueExA(keyCls, "IsShortcut", NULL, NULL, NULL, NULL))
-             {
-               uFlags |= GIL_FORSHORTCUT;
-             }
-             RegCloseKey(keyCls);
-           }
-         }
          if (SUCCEEDED(IExtractIconW_GetIconLocation(ei, uFlags, szIconFile, MAX_PATH, &iSourceIndex, &dwFlags)))
          {
            *pIndex = SIC_GetIconIndex(szIconFile, iSourceIndex, uFlags);
@@ -564,15 +611,19 @@ int WINAPI SHMapPIDLToSystemImageListIndex(
        int *pIndex)
 {
        int Index;
+       UINT uGilFlags = 0;
 
        TRACE("(SF=%p,pidl=%p,%p)\n",sh,pidl,pIndex);
        pdump(pidl);
 
+       if (SHELL_IsShortcut(pidl))
+           uGilFlags |= GIL_FORSHORTCUT;
+
        if (pIndex)
-           if (!PidlToSicIndex ( sh, pidl, 1, 0, pIndex))
-               *pIndex = -1;      
+           if (!PidlToSicIndex ( sh, pidl, 1, uGilFlags, pIndex))
+               *pIndex = -1;
 
-       if (!PidlToSicIndex ( sh, pidl, 0, 0, &Index))
+       if (!PidlToSicIndex ( sh, pidl, 0, uGilFlags, &Index))
            return -1;
 
        return Index;
@@ -670,7 +721,12 @@ HICON WINAPI ExtractAssociatedIconA(HINSTANCE hInst, LPSTR lpIconPath, LPWORD lp
 {      
     HICON hIcon = NULL;
     INT len = MultiByteToWideChar(CP_ACP, 0, lpIconPath, -1, NULL, 0);
-    LPWSTR lpIconPathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+    /* Note that we need to allocate MAX_PATH, since we are supposed to fill
+     * the correct executable if there is no icon in lpIconPath directly.
+     * lpIconPath itself is supposed to be large enough, so make sure lpIconPathW
+     * is large enough too. Yes, I am puking too.
+     */
+    LPWSTR lpIconPathW = HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR));
 
     TRACE("%p %s %p\n", hInst, debugstr_a(lpIconPath), lpiIcon);
 
@@ -678,11 +734,18 @@ HICON WINAPI ExtractAssociatedIconA(HINSTANCE hInst, LPSTR lpIconPath, LPWORD lp
     {
         MultiByteToWideChar(CP_ACP, 0, lpIconPath, -1, lpIconPathW, len);
         hIcon = ExtractAssociatedIconW(hInst, lpIconPathW, lpiIcon);
+        WideCharToMultiByte(CP_ACP, 0, lpIconPathW, -1, lpIconPath, MAX_PATH , NULL, NULL);
         HeapFree(GetProcessHeap(), 0, lpIconPathW);
     }
     return hIcon;
 }
 
+/*************************************************************************
+ *                             ExtractAssociatedIconW (SHELL32.@)
+ *
+ * Return icon for given file (either from file itself or from associated
+ * executable) and patch parameters if needed.
+ */
 HICON WINAPI ExtractAssociatedIconW(HINSTANCE hInst, LPWSTR lpIconPath, LPWORD lpiIcon)
 {
     HICON hIcon = NULL;