[PATCH] shell32: Improve semi-stub SHGetStockIconInfo, try find existing iconhandle

Louis Lenders xerox.xerox2000x at gmail.com
Fri Oct 12 04:57:18 CDT 2018


v3: try find handle to existing icon
 
this is the best I can come up with for now, on windows afaict all these icons mostly come from imegares.dll
so the attached patch is not really how windows does it

Fix for bug https://bugs.winehq.org/show_bug.cgi?id=45868

Signed-off-by: Louis Lenders <xerox.xerox2000x at gmail.com>
---
 dlls/shell32/iconcache.c       | 158 +++++++++++++++++++++++++++++++--
 dlls/shell32/tests/shelllink.c |  15 ++++
 2 files changed, 165 insertions(+), 8 deletions(-)

diff --git a/dlls/shell32/iconcache.c b/dlls/shell32/iconcache.c
index 6107e0c33b..da3e043d95 100644
--- a/dlls/shell32/iconcache.c
+++ b/dlls/shell32/iconcache.c
@@ -987,6 +987,119 @@ INT WINAPI SHGetIconOverlayIndexW(LPCWSTR pszIconPath, INT iIconIndex)
   return -1;
 }
 
+/****************************************************************************
+ * For SHGetStockIconInfo
+ */
+typedef struct {
+    SHSTOCKICONID id;
+    DWORD iconid;
+} SI_ENTRY;
+
+static const SI_ENTRY si_table[] =
+{
+    [0]   = { SIID_DOCNOASSOC, IDI_SHELL_FILE},
+    [1]   = { SIID_DOCASSOC, IDI_SHELL_DOCUMENT},
+    [2]   = { SIID_APPLICATION, IDI_SHELL_WINDOW},
+    [3]   = { SIID_FOLDER, IDI_SHELL_FOLDER},
+    [4]   = { SIID_FOLDEROPEN, IDI_SHELL_FOLDER_OPEN},
+    [5]   = { SIID_DRIVE525, 0},
+    [6]   = { SIID_DRIVE35, 0},
+    [7]   = { SIID_DRIVERREMOVE, 0},
+    [8]   = { SIID_DRIVERFIXED, IDI_SHELL_DRIVE},
+    [9]   = { SIID_DRIVERNET, IDI_SHELL_NETDRIVE},
+    [10]  = { SIID_DRIVERNETDISABLE, IDI_SHELL_NETDRIVE2},
+    [11]  = { SIID_DRIVERCD, IDI_SHELL_OPTICAL_DRIVE},
+    [12]  = { SIID_DRIVERRAM, IDI_SHELL_RAMDISK},
+    [13]  = { SIID_WORLD, 0},
+    /* Missing: 14 */
+    [15]  = { SIID_SERVER, 0},
+    [16]  = { SIID_PRINTER, IDI_SHELL_PRINT},
+    [17]  = { SIID_MYNETWORK, 0},
+    /* Missing: 18 - 21 */
+    [22]  = { SIID_FIND, 0},
+    [23]  = { SIID_HELP, IDI_SHELL_HELP},
+    /* Missing: 24 - 27 */
+    [28]  = {SIID_SHARE, 0},
+    [29]  = {SIID_LINK, 0},
+    [30]  = {SIID_SLOWFILE, 0},
+    [31]  = {SIID_RECYCLER, IDI_SHELL_TRASH_FOLDER},
+    [32]  = {SIID_RECYCLERFULL, IDI_SHELL_FULL_RECYCLE_BIN},
+    /* Missing: 33 - 39 */
+    [40]  = {SIID_MEDIACDAUDIO, 0},
+    /* Missing: 41 - 46 */
+    [47]  = {SIID_LOCK, IDI_SHELL_PASSWORDS},
+    /* Missing: 48 */
+    [49]  = {SIID_AUTOLIST, 0},
+    [50]  = {SIID_PRINTERNET, 0},
+    [51]  = {SIID_SERVERSHARE, 0},
+    [52]  = {SIID_PRINTERFAX, 0},
+    [53]  = {SIID_PRINTERFAXNET, 0},
+    [54]  = {SIID_PRINTERFILE, 0},
+    [55]  = {SIID_STACK, 0},
+    [56]  = {SIID_MEDIASVCD, 0},
+    [57]  = {SIID_STUFFEDFOLDER, 0},
+    [58]  = {SIID_DRIVEUNKNOWN, 0},
+    [59]  = {SIID_DRIVEDVD, 0},
+    [60]  = {SIID_MEDIADVD, 0},
+    [61]  = {SIID_MEDIADVDRAM, 0},
+    [62]  = {SIID_MEDIADVDRW, 0},
+    [63]  = {SIID_MEDIADVDR, 0},
+    [64]  = {SIID_MEDIADVDROM, 0},
+    [65]  = {SIID_MEDIACDAUDIOPLUS, 0},
+    [66]  = {SIID_MEDIACDRW, 0},
+    [67]  = {SIID_MEDIACDR, 0},
+    [68]  = {SIID_MEDIACDBURN, 0},
+    [69]  = {SIID_MEDIABLANKCD, 0},
+    [70]  = {SIID_MEDIACDROM, 0},
+    [71]  = {SIID_AUDIOFILES, IDI_SHELL_AUDIO_FILE},
+    [72]  = {SIID_IMAGEFILES, IDI_SHELL_IMAGE_FILE},
+    [73]  = {SIID_VIDEOFILES, IDI_SHELL_VIDEO_FILE},
+    [74]  = {SIID_MIXEDFILES, 0},
+    [75]  = {SIID_FOLDERBACK, 0},
+    [76]  = {SIID_FOLDERFRONT, 0},
+    [77]  = {SIID_SHIELD, 0},
+    [78]  = {SIID_WARNING, 0},
+    [79]  = {SIID_INFO, 0},
+    [80]  = {SIID_ERROR, 0},
+    [81]  = {SIID_KEY, 0},
+    [82]  = {SIID_SOFTWARE, 0},
+    [83]  = {SIID_RENAME, IDI_SHELL_RENAME},
+    [84]  = {SIID_DELETE, IDI_SHELL_CONFIRM_DELETE},
+    [85]  = {SIID_MEDIAAUDIODVD, 0},
+    [86]  = {SIID_MEDIAMOVIEDVD, 0},
+    [87]  = {SIID_MEDIAENHANCEDCD, 0},
+    [88]  = {SIID_MEDIAENHANCEDDVD, 0},
+    [89]  = {SIID_MEDIAHDDVD, 0},
+    [90]  = {SIID_MEDIABLUERAY, 0},
+    [91]  = {SIID_MEDIAVCD, 0},
+    [92]  = {SIID_MEDIADVDPLUSR, 0},
+    [93]  = {SIID_MEDIADVDPLUSRW, 0},
+    [94]  = {SIID_DESKTOPPC, IDI_SHELL_MY_COMPUTER},
+    [95]  = {SIID_MOBILEPC, 0},
+    [96]  = {SIID_USERS, IDI_SHELL_USERS},
+    [97]  = {SIID_MEDIASMARTMEDIA, 0},
+    [98]  = {SIID_MEDIACOMPACTFLASH, 0},
+    [99]  = {SIID_DEVICECELLPHONE, 0},
+    [100] = {SIID_DEVICECAMERA, 0},
+    [101] = {SIID_DEVICEVIDEOCAMERA, 0},
+    [102] = {SIID_DEVICEAUDIOPLAYER, 0},
+    [103] = {SIID_NETWORKCONNECT, 0},
+    [104] = {SIID_INTERNET, IDI_SHELL_WEB_BROWSER},
+    [105] = {SIID_ZIPFILE, 0},
+    [106] = {SIID_SETTINGS, IDI_SHELL_SETTINGS},
+    /* Missing: 107 - 131 */
+    [132] = {SIID_DRIVEHDDVD, 0},
+    [133] = {SIID_DRIVEBD, 0},
+    [134] = {SIID_MEDIAHDDVDROM, 0},
+    [135] = {SIID_MEDIAHDDVDR, 0},
+    [136] = {SIID_MEDIAHDDVDRAM, 0},
+    [137] = {SIID_MEDIABDROM, 0},
+    [138] = {SIID_MEDIABDR, 0},
+    [139] = {SIID_MEDIABDRE, 0},
+    [140] = {SIID_CLUSTEREDDRIVE, 0}
+    /* Missing: 141 - 180  and  SIID_MAX_ICONS = 181*/
+ };
+
 /****************************************************************************
  * SHGetStockIconInfo [SHELL32.@]
  *
@@ -1004,25 +1117,54 @@ INT WINAPI SHGetIconOverlayIndexW(LPCWSTR pszIconPath, INT iIconIndex)
  */
 HRESULT WINAPI SHGetStockIconInfo(SHSTOCKICONID id, UINT flags, SHSTOCKICONINFO *sii)
 {
-    static const WCHAR shell32dll[] = {'\\','s','h','e','l','l','3','2','.','d','l','l',0};
+    static const WCHAR shell32dllW[] = {'s','h','e','l','l','3','2','.','d','l','l',0};
+    static const WCHAR slashW[] = {'\\',0};
+    HMODULE hmod;
 
-    FIXME("(%d, 0x%x, %p) semi-stub\n", id, flags, sii);
+    TRACE("(%d, 0x%x, %p)\n", id, flags, sii);
     if ((id < 0) || (id >= SIID_MAX_ICONS) || !sii || (sii->cbSize != sizeof(SHSTOCKICONINFO))) {
         return E_INVALIDARG;
     }
 
     GetSystemDirectoryW(sii->szPath, MAX_PATH);
+    lstrcatW(sii->szPath, slashW);
+    lstrcatW(sii->szPath, shell32dllW);
+
+    sii->hIcon = NULL;
+    sii->iSysImageIndex = -1;
 
-    /* no icons defined: use default */
-    sii->iIcon = -IDI_SHELL_FILE;
-    lstrcatW(sii->szPath, shell32dll);
+    /* this is not how windows does it, on windows picked mostly from imageres.dll !*/
+    if (si_table[id].iconid)
+        sii->iIcon = sii->iSysImageIndex - si_table[id].id;
+    else
+    {
+        FIXME("Couldn`t find SIID %d, returning default values (IDI_SHELL_FILE)\n", id);
+        sii->iIcon = sii->iSysImageIndex - IDI_SHELL_FILE;
+    }
+
+    if (flags & SHGSI_ICON)
+    {
+        flags &= ~SHGSI_ICON;
+
+        hmod = GetModuleHandleW(shell32dllW);
+        if (hmod)
+        {
+            if (si_table[id].iconid)
+                sii->hIcon = LoadIconW(hmod, MAKEINTRESOURCEW(si_table[id].iconid));
+            else
+                sii->hIcon = LoadIconW(hmod, MAKEINTRESOURCEW(IDI_SHELL_FILE));
+        }
+
+        if (!sii->hIcon)
+        {
+            ERR("failed to get an icon handle\n");
+            return E_INVALIDARG;
+        }
+    }
 
     if (flags)
         FIXME("flags 0x%x not implemented\n", flags);
 
-    sii->hIcon = NULL;
-    sii->iSysImageIndex = -1;
-
     TRACE("%3d: returning %s (%d)\n", id, debugstr_w(sii->szPath), sii->iIcon);
 
     return S_OK;
diff --git a/dlls/shell32/tests/shelllink.c b/dlls/shell32/tests/shelllink.c
index 3bfd9cbe38..e7e3dac987 100644
--- a/dlls/shell32/tests/shelllink.c
+++ b/dlls/shell32/tests/shelllink.c
@@ -1139,6 +1139,21 @@ static void test_SHGetStockIconInfo(void)
     /* there is a NULL check for the struct  */
     hr = pSHGetStockIconInfo(SIID_FOLDER, SHGSI_ICONLOCATION, NULL);
     ok(hr == E_INVALIDARG, "NULL: got 0x%x\n", hr);
+
+    for(i = 0; i < 140; i++)  /* highest on wvista, i > 140 gives E_INVALIDARG, win7 can go higher */
+    {
+        memset(buffer, 0, sizeof(buffer));
+        sii->cbSize = sizeof(SHSTOCKICONINFO);
+        hr = pSHGetStockIconInfo(i, SHGSI_ICON | SHGSI_SMALLICON, sii);
+        ok(hr == S_OK, "got 0x%x (expected S_OK)\n", hr);
+        ok(sii->hIcon != NULL, "got NULL, expected an icon handle\n");
+        ok(sii->iIcon != 0, "got unexpected 0 for SIID %d\n", i); /* howto find out exact sii->iIcon value??? */
+        ok(sii->iSysImageIndex == -1, "got %d (expected -1)\n", sii->iSysImageIndex);
+        ok(DestroyIcon(sii->hIcon), "DestroyIcon failed\n");
+        if (winetest_debug > 1)
+            trace("%3d: got iSysImageIndex %3d, iIcon %3d and %s\n", i, sii->iSysImageIndex,
+            sii->iIcon, wine_dbgstr_w(sii->szPath));
+    }
 }
 
 static void test_SHExtractIcons(void)
-- 
2.17.1




More information about the wine-devel mailing list