Sync to Wine-0_9_3:
[reactos.git] / reactos / lib / shell32 / iconcache.c
index 75bd3af..0008f34 100644 (file)
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif
+
+#define COBJMACROS
+
 #include "windef.h"
 #include "winbase.h"
 #include "wingdi.h"
 #include "winuser.h"
 #include "winreg.h"
-#include "wine/winuser16.h"
-#include "wine/winbase16.h"
-#include "heap.h"
 #include "wine/debug.h"
 
 #include "shellapi.h"
@@ -43,7 +43,7 @@
 #include "pidl.h"
 #include "shell32_main.h"
 #include "undocshell.h"
-#include "shlwapi.h"
+#include "shresdef.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(shell);
 
@@ -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 };
 
@@ -78,23 +78,184 @@ static CRITICAL_SECTION SHELL32_SicCS = { &critsect_debug, -1, 0, 0, 0, 0 };
  *  Callback for DPA_Search
  */
 static INT CALLBACK SIC_CompareEntries( LPVOID p1, LPVOID p2, LPARAM lparam)
-{      TRACE("%p %p %8lx\n", p1, p2, lparam);
-
-       if (((LPSIC_ENTRY)p1)->dwSourceIndex != ((LPSIC_ENTRY)p2)->dwSourceIndex) /* first the faster one*/
+{      LPSIC_ENTRY e1 = (LPSIC_ENTRY)p1, e2 = (LPSIC_ENTRY)p2;
+       
+       TRACE("%p %p %8lx\n", p1, p2, lparam);
+
+       /* Icons in the cache are keyed by the name of the file they are
+        * 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 (strcmpiW(((LPSIC_ENTRY)p1)->sSourceFile,((LPSIC_ENTRY)p2)->sSourceFile))
+       if (strcmpiW(e1->sSourceFile,e2->sSourceFile))
          return 1;
 
        return 0;
 }
+
+/* declare SIC_LoadOverlayIcon() */
+static int SIC_LoadOverlayIcon(int idx);
+
+/*****************************************************************************
+ * SIC_OverlayShortcutImage                    [internal]
+ *
+ * NOTES
+ *  Creates a new icon as a copy of the passed-in icon, overlayed with a
+ *  shortcut image. 
+ */
+static HICON SIC_OverlayShortcutImage(HICON SourceIcon, BOOL large)
+{      ICONINFO SourceIconInfo, ShortcutIconInfo, TargetIconInfo;
+       HICON ShortcutIcon, TargetIcon;
+       BITMAP SourceBitmapInfo, ShortcutBitmapInfo;
+       HDC SourceDC = NULL,
+         ShortcutDC = NULL,
+         TargetDC = NULL,
+         ScreenDC = NULL;
+       HBITMAP OldSourceBitmap = NULL,
+         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;
+       }
+
+       /* 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))
+       {
+         return NULL;
+       }
+
+       TargetIconInfo = SourceIconInfo;
+       TargetIconInfo.hbmMask = NULL;
+       TargetIconInfo.hbmColor = NULL;
+
+       /* Setup the source, shortcut and target masks */
+       SourceDC = CreateCompatibleDC(NULL);
+       if (NULL == SourceDC) goto fail;
+       OldSourceBitmap = SelectObject(SourceDC, SourceIconInfo.hbmMask);
+       if (NULL == OldSourceBitmap) goto fail;
+
+       ShortcutDC = CreateCompatibleDC(NULL);
+       if (NULL == ShortcutDC) goto fail;
+       OldShortcutBitmap = SelectObject(ShortcutDC, ShortcutIconInfo.hbmMask);
+       if (NULL == OldShortcutBitmap) goto fail;
+
+       TargetDC = CreateCompatibleDC(NULL);
+       if (NULL == TargetDC) goto fail;
+       TargetIconInfo.hbmMask = CreateCompatibleBitmap(TargetDC, SourceBitmapInfo.bmWidth,
+                                                       SourceBitmapInfo.bmHeight);
+       if (NULL == TargetIconInfo.hbmMask) goto fail;
+       ScreenDC = GetDC(NULL);
+       if (NULL == ScreenDC) goto fail;
+       TargetIconInfo.hbmColor = CreateCompatibleBitmap(ScreenDC, SourceBitmapInfo.bmWidth,
+                                                        SourceBitmapInfo.bmHeight);
+       ReleaseDC(NULL, ScreenDC);
+       if (NULL == TargetIconInfo.hbmColor) goto fail;
+       OldTargetBitmap = SelectObject(TargetDC, TargetIconInfo.hbmMask);
+       if (NULL == OldTargetBitmap) goto fail;
+
+       /* Create the target mask by ANDing the source and shortcut masks */
+       if (! BitBlt(TargetDC, 0, 0, SourceBitmapInfo.bmWidth, SourceBitmapInfo.bmHeight,
+                    SourceDC, 0, 0, SRCCOPY) ||
+           ! BitBlt(TargetDC, 0, SourceBitmapInfo.bmHeight - ShortcutBitmapInfo.bmHeight,
+                    ShortcutBitmapInfo.bmWidth, ShortcutBitmapInfo.bmHeight,
+                    ShortcutDC, 0, 0, SRCAND))
+       {
+         goto fail;
+       }
+
+       /* Setup the source and target xor bitmap */
+       if (NULL == SelectObject(SourceDC, SourceIconInfo.hbmColor) ||
+           NULL == SelectObject(TargetDC, TargetIconInfo.hbmColor))
+       {
+         goto fail;
+       }
+
+       /* Copy the source xor bitmap to the target and clear out part of it by using
+          the shortcut mask */
+       if (! BitBlt(TargetDC, 0, 0, SourceBitmapInfo.bmWidth, SourceBitmapInfo.bmHeight,
+                    SourceDC, 0, 0, SRCCOPY) ||
+           ! BitBlt(TargetDC, 0, SourceBitmapInfo.bmHeight - ShortcutBitmapInfo.bmHeight,
+                    ShortcutBitmapInfo.bmWidth, ShortcutBitmapInfo.bmHeight,
+                    ShortcutDC, 0, 0, SRCAND))
+       {
+         goto fail;
+       }
+
+       if (NULL == SelectObject(ShortcutDC, ShortcutIconInfo.hbmColor)) goto fail;
+
+       /* Now put in the shortcut xor mask */
+       if (! BitBlt(TargetDC, 0, SourceBitmapInfo.bmHeight - ShortcutBitmapInfo.bmHeight,
+                    ShortcutBitmapInfo.bmWidth, ShortcutBitmapInfo.bmHeight,
+                    ShortcutDC, 0, 0, SRCINVERT))
+       {
+         goto fail;
+       }
+
+       /* Clean up, we're not goto'ing to 'fail' after this so we can be lazy and not set
+          handles to NULL */
+       SelectObject(TargetDC, OldTargetBitmap);
+       DeleteObject(TargetDC);
+       SelectObject(ShortcutDC, OldShortcutBitmap);
+       DeleteObject(ShortcutDC);
+       SelectObject(SourceDC, OldSourceBitmap);
+       DeleteObject(SourceDC);
+
+       /* Create the icon using the bitmaps prepared earlier */
+       TargetIcon = CreateIconIndirect(&TargetIconInfo);
+
+       /* CreateIconIndirect copies the bitmaps, so we can release our bitmaps now */
+       DeleteObject(TargetIconInfo.hbmColor);
+       DeleteObject(TargetIconInfo.hbmMask);
+
+       return TargetIcon;
+
+fail:
+       /* Clean up scratch resources we created */
+       if (NULL != OldTargetBitmap) SelectObject(TargetDC, OldTargetBitmap);
+       if (NULL != TargetIconInfo.hbmColor) DeleteObject(TargetIconInfo.hbmColor);
+       if (NULL != TargetIconInfo.hbmMask) DeleteObject(TargetIconInfo.hbmMask);
+       if (NULL != TargetDC) DeleteObject(TargetDC);
+       if (NULL != OldShortcutBitmap) SelectObject(ShortcutDC, OldShortcutBitmap);
+       if (NULL != ShortcutDC) DeleteObject(ShortcutDC);
+       if (NULL != OldSourceBitmap) SelectObject(SourceDC, OldSourceBitmap);
+       if (NULL != SourceDC) DeleteObject(SourceDC);
+
+       return NULL;
+}
+
 /*****************************************************************************
  * SIC_IconAppend                      [internal]
  *
  * NOTES
  *  appends an icon pair to the end of the cache
  */
-static INT SIC_IconAppend (LPCWSTR sSourceFile, INT dwSourceIndex, HICON hSmallIcon, HICON hBigIcon)
+static INT SIC_IconAppend (LPCWSTR sSourceFile, INT dwSourceIndex, HICON hSmallIcon, HICON hBigIcon, DWORD dwFlags)
 {      LPSIC_ENTRY lpsice;
        INT ret, index, index1;
        WCHAR path[MAX_PATH];
@@ -107,6 +268,7 @@ static INT SIC_IconAppend (LPCWSTR sSourceFile, INT dwSourceIndex, HICON hSmallI
        strcpyW( lpsice->sSourceFile, path );
 
        lpsice->dwSourceIndex = dwSourceIndex;
+       lpsice->dwFlags = dwFlags;
 
        EnterCriticalSection(&SHELL32_SicCS);
 
@@ -139,9 +301,11 @@ static INT SIC_IconAppend (LPCWSTR sSourceFile, INT dwSourceIndex, HICON hSmallI
  * NOTES
  *  gets small/big icon by number from a file
  */
-static INT SIC_LoadIcon (LPCWSTR sSourceFile, INT dwSourceIndex)
+static INT SIC_LoadIcon (LPCWSTR sSourceFile, INT dwSourceIndex, DWORD dwFlags)
 {      HICON   hiconLarge=0;
        HICON   hiconSmall=0;
+       HICON   hiconLargeShortcut;
+       HICON   hiconSmallShortcut;
 
 #if defined(__CYGWIN__) || defined (__MINGW32__) || defined(_MSC_VER)
        static UINT (WINAPI*PrivateExtractIconExW)(LPCWSTR,int,HICON*,HICON*,UINT) = NULL;
@@ -165,7 +329,26 @@ static INT SIC_LoadIcon (LPCWSTR sSourceFile, INT dwSourceIndex)
          WARN("failure loading icon %i from %s (%p %p)\n", dwSourceIndex, debugstr_w(sSourceFile), hiconLarge, hiconSmall);
          return -1;
        }
-       return SIC_IconAppend (sSourceFile, dwSourceIndex, hiconSmall, hiconLarge);
+
+       if (0 != (dwFlags & GIL_FORSHORTCUT))
+       {
+         hiconLargeShortcut = SIC_OverlayShortcutImage(hiconLarge, TRUE);
+         hiconSmallShortcut = SIC_OverlayShortcutImage(hiconSmall, FALSE);
+         if (NULL != hiconLargeShortcut && NULL != hiconSmallShortcut)
+         {
+           hiconLarge = hiconLargeShortcut;
+           hiconSmall = hiconSmallShortcut;
+         }
+         else
+         {
+           WARN("Failed to create shortcut overlayed icons\n");
+           if (NULL != hiconLargeShortcut) DestroyIcon(hiconLargeShortcut);
+           if (NULL != hiconSmallShortcut) DestroyIcon(hiconSmallShortcut);
+           dwFlags &= ~ GIL_FORSHORTCUT;
+         }
+       }
+
+       return SIC_IconAppend (sSourceFile, dwSourceIndex, hiconSmall, hiconLarge, dwFlags);
 }
 /*****************************************************************************
  * SIC_GetIconIndex                    [internal]
@@ -178,7 +361,7 @@ static INT SIC_LoadIcon (LPCWSTR sSourceFile, INT dwSourceIndex)
  *  look in the cache for a proper icon. if not available the icon is taken
  *  from the file and cached
  */
-INT SIC_GetIconIndex (LPCWSTR sSourceFile, INT dwSourceIndex )
+INT SIC_GetIconIndex (LPCWSTR sSourceFile, INT dwSourceIndex, DWORD dwFlags )
 {
        SIC_ENTRY sice;
        INT ret, index = INVALID_INDEX;
@@ -189,6 +372,7 @@ INT SIC_GetIconIndex (LPCWSTR sSourceFile, INT dwSourceIndex )
        GetFullPathNameW(sSourceFile, MAX_PATH, path, NULL);
        sice.sSourceFile = path;
        sice.dwSourceIndex = dwSourceIndex;
+       sice.dwFlags = dwFlags;
 
        EnterCriticalSection(&SHELL32_SicCS);
 
@@ -200,7 +384,7 @@ INT SIC_GetIconIndex (LPCWSTR sSourceFile, INT dwSourceIndex )
 
        if ( INVALID_INDEX == index )
        {
-         ret = SIC_LoadIcon (sSourceFile, dwSourceIndex);
+          ret = SIC_LoadIcon (sSourceFile, dwSourceIndex, dwFlags);
        }
        else
        {
@@ -211,40 +395,12 @@ INT SIC_GetIconIndex (LPCWSTR sSourceFile, INT dwSourceIndex )
        LeaveCriticalSection(&SHELL32_SicCS);
        return ret;
 }
-/****************************************************************************
- * SIC_GetIcon                         [internal]
- *
- * NOTES
- *  retrieves the specified icon from the iconcache.
- */
-static HICON WINE_UNUSED SIC_GetIcon (LPCWSTR sSourceFile, INT dwSourceIndex, BOOL bSmallIcon )
-{      INT index;
-
-       TRACE("%s %i\n", debugstr_w(sSourceFile), dwSourceIndex);
-
-       index = SIC_GetIconIndex(sSourceFile, dwSourceIndex);
-
-       if (INVALID_INDEX == index)
-       {
-         return (HICON)INVALID_INDEX;
-       }
-
-       if (bSmallIcon)
-         return ImageList_GetIcon(ShellSmallIconList, index, ILD_NORMAL);
-
-       return ImageList_GetIcon(ShellBigIconList, index, ILD_NORMAL);
-}
 /*****************************************************************************
  * 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;
 
@@ -265,25 +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, hSm, hLg);
-       }
+        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;
@@ -309,10 +467,60 @@ void SIC_Destroy(void)
        if (sic_hdpa) DPA_DestroyCallback(sic_hdpa, sic_free, NULL );
 
        sic_hdpa = NULL;
+       ImageList_Destroy(ShellSmallIconList);
+       ShellSmallIconList = 0;
+       ImageList_Destroy(ShellBigIconList);
+       ShellBigIconList = 0;
 
        LeaveCriticalSection(&SHELL32_SicCS);
-       DeleteCriticalSection(&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]
  *
@@ -331,7 +539,6 @@ BOOL WINAPI Shell_GetImageList(HIMAGELIST * lpBigList, HIMAGELIST * lpSmallList)
 
        return TRUE;
 }
-
 /*************************************************************************
  * PidlToSicIndex                      [INTERNAL]
  *
@@ -355,6 +562,7 @@ BOOL PidlToSicIndex (
        INT             iSourceIndex;           /* index or resID(negated) in this file */
        BOOL            ret = FALSE;
        UINT            dwFlags = 0;
+       int             iShortcutDefaultIndex = INVALID_INDEX;
 
        TRACE("sf=%p pidl=%p %s\n", sh, pidl, bBigIcon?"Big":"Small");
 
@@ -362,16 +570,30 @@ BOOL PidlToSicIndex (
        {
          if (SUCCEEDED(IExtractIconW_GetIconLocation(ei, uFlags, szIconFile, MAX_PATH, &iSourceIndex, &dwFlags)))
          {
-           *pIndex = SIC_GetIconIndex(szIconFile, iSourceIndex);
+           *pIndex = SIC_GetIconIndex(szIconFile, iSourceIndex, uFlags);
            ret = TRUE;
          }
          IExtractIconW_Release(ei);
        }
 
        if (INVALID_INDEX == *pIndex)   /* default icon when failed */
-         *pIndex = 0;
+       {
+         if (0 == (uFlags & GIL_FORSHORTCUT))
+         {
+           *pIndex = 0;
+         }
+         else
+         {
+           if (INVALID_INDEX == iShortcutDefaultIndex)
+           {
+             iShortcutDefaultIndex = SIC_LoadIcon(swShell32Name, 0, GIL_FORSHORTCUT);
+           }
+           *pIndex = (INVALID_INDEX != iShortcutDefaultIndex ? iShortcutDefaultIndex : 0);
+         }
+       }
 
        return ret;
+
 }
 
 /*************************************************************************
@@ -389,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;
@@ -418,7 +644,7 @@ INT WINAPI Shell_GetCachedImageIndexA(LPCSTR szPath, INT nIndex, BOOL bSimulateD
        szTemp = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
        MultiByteToWideChar( CP_ACP, 0, szPath, -1, szTemp, len );
 
-       ret = SIC_GetIconIndex( szTemp, nIndex );
+       ret = SIC_GetIconIndex( szTemp, nIndex, 0 );
 
        HeapFree( GetProcessHeap(), 0, szTemp );
 
@@ -429,7 +655,7 @@ INT WINAPI Shell_GetCachedImageIndexW(LPCWSTR szPath, INT nIndex, BOOL bSimulate
 {
        WARN("(%s,%08x,%08x) semi-stub.\n",debugstr_w(szPath), nIndex, bSimulateDoc);
 
-       return SIC_GetIconIndex(szPath, nIndex);
+       return SIC_GetIconIndex(szPath, nIndex, 0);
 }
 
 INT WINAPI Shell_GetCachedImageIndexAW(LPCVOID szPath, INT nIndex, BOOL bSimulateDoc)
@@ -438,18 +664,9 @@ INT WINAPI Shell_GetCachedImageIndexAW(LPCVOID szPath, INT nIndex, BOOL bSimulat
        return Shell_GetCachedImageIndexA(szPath, nIndex, bSimulateDoc);
 }
 
-/*************************************************************************
- * ExtractIconEx                       [SHELL32.@]
- */
-UINT WINAPI ExtractIconExAW(LPCVOID lpszFile, INT nIconIndex, HICON * phiconLarge, HICON * phiconSmall, UINT nIcons)
-{      if (SHELL_OsIsUnicode())
-         return ExtractIconExW ( lpszFile, nIconIndex, phiconLarge, phiconSmall, nIcons);
-       return ExtractIconExA ( lpszFile, nIconIndex, phiconLarge, phiconSmall, nIcons);
-}
-
 /*************************************************************************
  * ExtractIconExW                      [SHELL32.@]
- * RETURNS
+ * RETURNS
  *  0 no icon found
  *  -1 file is not valid
  *  or number of icons extracted
@@ -479,15 +696,18 @@ UINT WINAPI ExtractIconExW(LPCWSTR lpszFile, INT nIconIndex, HICON * phiconLarge
  */
 UINT WINAPI ExtractIconExA(LPCSTR lpszFile, INT nIconIndex, HICON * phiconLarge, HICON * phiconSmall, UINT nIcons)
 {
-    UINT ret;
+    UINT ret = 0;
     INT len = MultiByteToWideChar(CP_ACP, 0, lpszFile, -1, NULL, 0);
     LPWSTR lpwstrFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
 
     TRACE("%s %i %p %p %i\n", lpszFile, nIconIndex, phiconLarge, phiconSmall, nIcons);
 
-    MultiByteToWideChar(CP_ACP, 0, lpszFile, -1, lpwstrFile, len);
-    ret = ExtractIconExW (lpwstrFile, nIconIndex, phiconLarge, phiconSmall, nIcons);
-    HeapFree(GetProcessHeap(), 0, lpwstrFile);
+    if (lpwstrFile)
+    {
+        MultiByteToWideChar(CP_ACP, 0, lpszFile, -1, lpwstrFile, len);
+        ret = ExtractIconExW(lpwstrFile, nIconIndex, phiconLarge, phiconSmall, nIcons);
+        HeapFree(GetProcessHeap(), 0, lpwstrFile);
+    }
     return ret;
 }
 
@@ -499,39 +719,67 @@ UINT WINAPI ExtractIconExA(LPCSTR lpszFile, INT nIconIndex, HICON * phiconLarge,
  */
 HICON WINAPI ExtractAssociatedIconA(HINSTANCE hInst, LPSTR lpIconPath, LPWORD lpiIcon)
 {      
-       HICON hIcon;
-       WORD wDummyIcon = 0;
-       
-       TRACE("\n");
-
-       if(lpiIcon == NULL)
-           lpiIcon = &wDummyIcon;
-
-       hIcon = ExtractIconA(hInst, lpIconPath, *lpiIcon);
-
-       if( hIcon < (HICON)2 )
-       { if( hIcon == (HICON)1 ) /* no icons found in given file */
-         { char  tempPath[0x80];
-           HINSTANCE uRet = FindExecutableA(lpIconPath,NULL,tempPath);
-
-           if( uRet > (HINSTANCE)32 && tempPath[0] )
-           { strcpy(lpIconPath,tempPath);
-             hIcon = ExtractIconA(hInst, lpIconPath, *lpiIcon);
-             if( hIcon > (HICON)2 )
-               return hIcon;
-           }
-           else hIcon = 0;
-         }
-
-         if( hIcon == (HICON)1 )
-           *lpiIcon = 2;   /* MSDOS icon - we found .exe but no icons in it */
-         else
-           *lpiIcon = 6;   /* generic icon - found nothing */
+    HICON hIcon = NULL;
+    INT len = MultiByteToWideChar(CP_ACP, 0, lpIconPath, -1, NULL, 0);
+    /* 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);
+
+    if (lpIconPathW)
+    {
+        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;
+}
 
-         GetModuleFileNameA(hInst, lpIconPath, 0x80);
-         hIcon = LoadIconA( hInst, MAKEINTRESOURCEA(*lpiIcon));
-       }
-       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;
+    WORD wDummyIcon = 0;
+
+    TRACE("%p %s %p\n", hInst, debugstr_w(lpIconPath), lpiIcon);
+
+    if(lpiIcon == NULL)
+        lpiIcon = &wDummyIcon;
+
+    hIcon = ExtractIconW(hInst, lpIconPath, *lpiIcon);
+
+    if( hIcon < (HICON)2 )
+    { if( hIcon == (HICON)1 ) /* no icons found in given file */
+      { WCHAR tempPath[MAX_PATH];
+        HINSTANCE uRet = FindExecutableW(lpIconPath,NULL,tempPath);
+
+        if( uRet > (HINSTANCE)32 && tempPath[0] )
+        { lstrcpyW(lpIconPath,tempPath);
+          hIcon = ExtractIconW(hInst, lpIconPath, *lpiIcon);
+          if( hIcon > (HICON)2 )
+            return hIcon;
+        }
+      }
+
+      if( hIcon == (HICON)1 )
+        *lpiIcon = 2;   /* MSDOS icon - we found .exe but no icons in it */
+      else
+        *lpiIcon = 6;   /* generic icon - found nothing */
+
+      if (GetModuleFileNameW(hInst, lpIconPath, MAX_PATH))
+        hIcon = LoadIconW(hInst, MAKEINTRESOURCEW(*lpiIcon));
+    }
+    return hIcon;
 }
 
 /*************************************************************************