[SHELL32_WINETEST]
[reactos.git] / rostests / winetests / shell32 / shelllink.c
index b22079c..0b2b7be 100755 (executable)
@@ -26,6 +26,7 @@
 #include "shlguid.h"
 #include "shobjidl.h"
 #include "shlobj.h"
 #include "shlguid.h"
 #include "shobjidl.h"
 #include "shlobj.h"
+#include "shellapi.h"
 #include "wine/test.h"
 
 #include "shell32_test.h"
 #include "wine/test.h"
 
 #include "shell32_test.h"
@@ -38,9 +39,10 @@ static void (WINAPI *pILFree)(LPITEMIDLIST);
 static BOOL (WINAPI *pILIsEqual)(LPCITEMIDLIST, LPCITEMIDLIST);
 static HRESULT (WINAPI *pSHILCreateFromPath)(LPCWSTR, LPITEMIDLIST *,DWORD*);
 static HRESULT (WINAPI *pSHDefExtractIconA)(LPCSTR, int, UINT, HICON*, HICON*, UINT);
 static BOOL (WINAPI *pILIsEqual)(LPCITEMIDLIST, LPCITEMIDLIST);
 static HRESULT (WINAPI *pSHILCreateFromPath)(LPCWSTR, LPITEMIDLIST *,DWORD*);
 static HRESULT (WINAPI *pSHDefExtractIconA)(LPCSTR, int, UINT, HICON*, HICON*, UINT);
-
+static HRESULT (WINAPI *pSHGetStockIconInfo)(SHSTOCKICONID, UINT, SHSTOCKICONINFO *);
 static DWORD (WINAPI *pGetLongPathNameA)(LPCSTR, LPSTR, DWORD);
 static DWORD (WINAPI *pGetShortPathNameA)(LPCSTR, LPSTR, DWORD);
 static DWORD (WINAPI *pGetLongPathNameA)(LPCSTR, LPSTR, DWORD);
 static DWORD (WINAPI *pGetShortPathNameA)(LPCSTR, LPSTR, DWORD);
+static UINT (WINAPI *pSHExtractIconsW)(LPCWSTR, int, int, int, HICON *, UINT *, UINT, UINT);
 
 static const GUID _IID_IShellLinkDataList = {
     0x45e2b4ae, 0xb1c3, 0x11d0,
 
 static const GUID _IID_IShellLinkDataList = {
     0x45e2b4ae, 0xb1c3, 0x11d0,
@@ -126,7 +128,7 @@ static void test_get_set(void)
     strcpy(buffer,"garbage");
     r = IShellLinkA_GetDescription(sl, buffer, sizeof(buffer));
     ok(r == S_OK, "GetDescription failed (0x%08x)\n", r);
     strcpy(buffer,"garbage");
     r = IShellLinkA_GetDescription(sl, buffer, sizeof(buffer));
     ok(r == S_OK, "GetDescription failed (0x%08x)\n", r);
-    ok(lstrcmp(buffer,str)==0, "GetDescription returned '%s'\n", buffer);
+    ok(strcmp(buffer,str)==0, "GetDescription returned '%s'\n", buffer);
 
     r = IShellLinkA_SetDescription(sl, NULL);
     ok(r == S_OK, "SetDescription failed (0x%08x)\n", r);
 
     r = IShellLinkA_SetDescription(sl, NULL);
     ok(r == S_OK, "SetDescription failed (0x%08x)\n", r);
@@ -134,8 +136,7 @@ static void test_get_set(void)
     strcpy(buffer,"garbage");
     r = IShellLinkA_GetDescription(sl, buffer, sizeof(buffer));
     ok(r == S_OK, "GetDescription failed (0x%08x)\n", r);
     strcpy(buffer,"garbage");
     r = IShellLinkA_GetDescription(sl, buffer, sizeof(buffer));
     ok(r == S_OK, "GetDescription failed (0x%08x)\n", r);
-    ok(*buffer=='\0' || broken(lstrcmp(buffer,str)==0), "GetDescription returned '%s'\n", buffer); /* NT4 */
-
+    ok(*buffer=='\0' || broken(strcmp(buffer,str)==0), "GetDescription returned '%s'\n", buffer); /* NT4 */
 
     /* Test Getting / Setting the work directory */
     strcpy(buffer,"garbage");
 
     /* Test Getting / Setting the work directory */
     strcpy(buffer,"garbage");
@@ -150,7 +151,7 @@ static void test_get_set(void)
     strcpy(buffer,"garbage");
     r = IShellLinkA_GetWorkingDirectory(sl, buffer, sizeof(buffer));
     ok(r == S_OK, "GetWorkingDirectory failed (0x%08x)\n", r);
     strcpy(buffer,"garbage");
     r = IShellLinkA_GetWorkingDirectory(sl, buffer, sizeof(buffer));
     ok(r == S_OK, "GetWorkingDirectory failed (0x%08x)\n", r);
-    ok(lstrcmpi(buffer,str)==0, "GetWorkingDirectory returned '%s'\n", buffer);
+    ok(lstrcmpiA(buffer,str)==0, "GetWorkingDirectory returned '%s'\n", buffer);
 
     /* Test Getting / Setting the path */
     strcpy(buffer,"garbage");
 
     /* Test Getting / Setting the path */
     strcpy(buffer,"garbage");
@@ -187,7 +188,7 @@ static void test_get_set(void)
     strcpy(buffer,"garbage");
     r = IShellLinkA_GetPath(sl, buffer, sizeof(buffer), NULL, SLGP_RAWPATH);
     ok(r == S_OK, "GetPath failed (0x%08x)\n", r);
     strcpy(buffer,"garbage");
     r = IShellLinkA_GetPath(sl, buffer, sizeof(buffer), NULL, SLGP_RAWPATH);
     ok(r == S_OK, "GetPath failed (0x%08x)\n", r);
-    ok(lstrcmpi(buffer,str)==0, "GetPath returned '%s'\n", buffer);
+    ok(lstrcmpiA(buffer,str)==0, "GetPath returned '%s'\n", buffer);
 
     /* Get some real path to play with */
     GetWindowsDirectoryA( mypath, sizeof(mypath)-12 );
 
     /* Get some real path to play with */
     GetWindowsDirectoryA( mypath, sizeof(mypath)-12 );
@@ -205,7 +206,7 @@ static void test_get_set(void)
         ret = SHGetPathFromIDListA(tmp_pidl, buffer);
         ok(ret, "SHGetPathFromIDListA failed\n");
         if (ret)
         ret = SHGetPathFromIDListA(tmp_pidl, buffer);
         ok(ret, "SHGetPathFromIDListA failed\n");
         if (ret)
-            ok(lstrcmpi(buffer,str)==0, "GetIDList returned '%s'\n", buffer);
+            ok(lstrcmpiA(buffer,str)==0, "GetIDList returned '%s'\n", buffer);
         pILFree(tmp_pidl);
     }
 
         pILFree(tmp_pidl);
     }
 
@@ -239,8 +240,7 @@ static void test_get_set(void)
         r = IShellLinkA_GetPath(sl, buffer, sizeof(buffer), NULL, SLGP_RAWPATH);
         ok(r == S_OK, "GetPath failed (0x%08x)\n", r);
         todo_wine
         r = IShellLinkA_GetPath(sl, buffer, sizeof(buffer), NULL, SLGP_RAWPATH);
         ok(r == S_OK, "GetPath failed (0x%08x)\n", r);
         todo_wine
-        ok(lstrcmpi(buffer, mypath)==0, "GetPath returned '%s'\n", buffer);
-
+        ok(lstrcmpiA(buffer, mypath)==0, "GetPath returned '%s'\n", buffer);
     }
 
     /* test path with quotes (IShellLinkA_SetPath returns S_FALSE on W2K and below and S_OK on XP and above */
     }
 
     /* test path with quotes (IShellLinkA_SetPath returns S_FALSE on W2K and below and S_OK on XP and above */
@@ -250,8 +250,8 @@ static void test_get_set(void)
     strcpy(buffer,"garbage");
     r = IShellLinkA_GetPath(sl, buffer, sizeof(buffer), NULL, SLGP_RAWPATH);
     ok(r==S_OK, "GetPath failed (0x%08x)\n", r);
     strcpy(buffer,"garbage");
     r = IShellLinkA_GetPath(sl, buffer, sizeof(buffer), NULL, SLGP_RAWPATH);
     ok(r==S_OK, "GetPath failed (0x%08x)\n", r);
-    ok(!lstrcmp(buffer, "C:\\nonexistent\\file") ||
-       broken(!lstrcmp(buffer, "C:\\\"c:\\nonexistent\\file\"")), /* NT4 */
+    ok(!strcmp(buffer, "C:\\nonexistent\\file") ||
+       broken(!strcmp(buffer, "C:\\\"c:\\nonexistent\\file\"")), /* NT4 */
        "case doesn't match\n");
 
     r = IShellLinkA_SetPath(sl, "\"c:\\foo");
        "case doesn't match\n");
 
     r = IShellLinkA_SetPath(sl, "\"c:\\foo");
@@ -282,14 +282,14 @@ static void test_get_set(void)
     strcpy(buffer,"garbage");
     r = IShellLinkA_GetArguments(sl, buffer, sizeof(buffer));
     ok(r == S_OK, "GetArguments failed (0x%08x)\n", r);
     strcpy(buffer,"garbage");
     r = IShellLinkA_GetArguments(sl, buffer, sizeof(buffer));
     ok(r == S_OK, "GetArguments failed (0x%08x)\n", r);
-    ok(lstrcmp(buffer,str)==0, "GetArguments returned '%s'\n", buffer);
+    ok(strcmp(buffer,str)==0, "GetArguments returned '%s'\n", buffer);
 
     strcpy(buffer,"garbage");
     r = IShellLinkA_SetArguments(sl, NULL);
     ok(r == S_OK, "SetArguments failed (0x%08x)\n", r);
     r = IShellLinkA_GetArguments(sl, buffer, sizeof(buffer));
     ok(r == S_OK, "GetArguments failed (0x%08x)\n", r);
 
     strcpy(buffer,"garbage");
     r = IShellLinkA_SetArguments(sl, NULL);
     ok(r == S_OK, "SetArguments failed (0x%08x)\n", r);
     r = IShellLinkA_GetArguments(sl, buffer, sizeof(buffer));
     ok(r == S_OK, "GetArguments failed (0x%08x)\n", r);
-    ok(!buffer[0] || lstrcmp(buffer,str)==0, "GetArguments returned '%s'\n", buffer);
+    ok(!buffer[0] || strcmp(buffer,str)==0, "GetArguments returned '%s'\n", buffer);
 
     strcpy(buffer,"garbage");
     r = IShellLinkA_SetArguments(sl, "");
 
     strcpy(buffer,"garbage");
     r = IShellLinkA_SetArguments(sl, "");
@@ -327,7 +327,7 @@ static void test_get_set(void)
     i=0xdeadbeef;
     r = IShellLinkA_GetIconLocation(sl, buffer, sizeof(buffer), &i);
     ok(r == S_OK, "GetIconLocation failed (0x%08x)\n", r);
     i=0xdeadbeef;
     r = IShellLinkA_GetIconLocation(sl, buffer, sizeof(buffer), &i);
     ok(r == S_OK, "GetIconLocation failed (0x%08x)\n", r);
-    ok(lstrcmpi(buffer,str)==0, "GetIconLocation returned '%s'\n", buffer);
+    ok(lstrcmpiA(buffer,str)==0, "GetIconLocation returned '%s'\n", buffer);
     ok(i==0xbabecafe, "GetIconLocation returned %d'\n", i);
 
     /* Test Getting / Setting the hot key */
     ok(i==0xbabecafe, "GetIconLocation returned %d'\n", i);
 
     /* Test Getting / Setting the hot key */
@@ -535,7 +535,7 @@ static void check_lnk_(int line, const WCHAR* path, lnk_desc_t* desc, int todo)
         strcpy(buffer,"garbage");
         r = IShellLinkA_GetDescription(sl, buffer, sizeof(buffer));
         lok(r == S_OK, "GetDescription failed (0x%08x)\n", r);
         strcpy(buffer,"garbage");
         r = IShellLinkA_GetDescription(sl, buffer, sizeof(buffer));
         lok(r == S_OK, "GetDescription failed (0x%08x)\n", r);
-        lok_todo_4(0x1, lstrcmp(buffer, desc->description)==0,
+        lok_todo_4(0x1, strcmp(buffer, desc->description)==0,
            "GetDescription returned '%s' instead of '%s'\n",
            buffer, desc->description);
     }
            "GetDescription returned '%s' instead of '%s'\n",
            buffer, desc->description);
     }
@@ -544,7 +544,7 @@ static void check_lnk_(int line, const WCHAR* path, lnk_desc_t* desc, int todo)
         strcpy(buffer,"garbage");
         r = IShellLinkA_GetWorkingDirectory(sl, buffer, sizeof(buffer));
         lok(r == S_OK, "GetWorkingDirectory failed (0x%08x)\n", r);
         strcpy(buffer,"garbage");
         r = IShellLinkA_GetWorkingDirectory(sl, buffer, sizeof(buffer));
         lok(r == S_OK, "GetWorkingDirectory failed (0x%08x)\n", r);
-        lok_todo_4(0x2, lstrcmpi(buffer, desc->workdir)==0,
+        lok_todo_4(0x2, lstrcmpiA(buffer, desc->workdir)==0,
            "GetWorkingDirectory returned '%s' instead of '%s'\n",
            buffer, desc->workdir);
     }
            "GetWorkingDirectory returned '%s' instead of '%s'\n",
            buffer, desc->workdir);
     }
@@ -553,7 +553,7 @@ static void check_lnk_(int line, const WCHAR* path, lnk_desc_t* desc, int todo)
         strcpy(buffer,"garbage");
         r = IShellLinkA_GetPath(sl, buffer, sizeof(buffer), NULL, SLGP_RAWPATH);
         lok(SUCCEEDED(r), "GetPath failed (0x%08x)\n", r);
         strcpy(buffer,"garbage");
         r = IShellLinkA_GetPath(sl, buffer, sizeof(buffer), NULL, SLGP_RAWPATH);
         lok(SUCCEEDED(r), "GetPath failed (0x%08x)\n", r);
-        lok_todo_4(0x4, lstrcmpi(buffer, desc->path)==0,
+        lok_todo_4(0x4, lstrcmpiA(buffer, desc->path)==0,
            "GetPath returned '%s' instead of '%s'\n",
            buffer, desc->path);
     }
            "GetPath returned '%s' instead of '%s'\n",
            buffer, desc->path);
     }
@@ -580,7 +580,7 @@ static void check_lnk_(int line, const WCHAR* path, lnk_desc_t* desc, int todo)
         strcpy(buffer,"garbage");
         r = IShellLinkA_GetIconLocation(sl, buffer, sizeof(buffer), &i);
         lok(r == S_OK, "GetIconLocation failed (0x%08x)\n", r);
         strcpy(buffer,"garbage");
         r = IShellLinkA_GetIconLocation(sl, buffer, sizeof(buffer), &i);
         lok(r == S_OK, "GetIconLocation failed (0x%08x)\n", r);
-        lok_todo_4(0x20, lstrcmpi(buffer, desc->icon)==0,
+        lok_todo_4(0x20, lstrcmpiA(buffer, desc->icon)==0,
            "GetIconLocation returned '%s' instead of '%s'\n",
            buffer, desc->icon);
         lok_todo_4(0x20, i==desc->icon_id,
            "GetIconLocation returned '%s' instead of '%s'\n",
            buffer, desc->icon);
         lok_todo_4(0x20, i==desc->icon_id,
@@ -650,7 +650,7 @@ static void test_load_save(void)
     create_lnk(lnkfile, &desc, 0);
     check_lnk(lnkfile, &desc, 0x0);
 
     create_lnk(lnkfile, &desc, 0);
     check_lnk(lnkfile, &desc, 0x0);
 
-    r=GetModuleFileName(NULL, mypath, sizeof(mypath));
+    r=GetModuleFileNameA(NULL, mypath, sizeof(mypath));
     ok(r<sizeof(mypath), "GetModuleFileName failed (%d)\n", r);
     strcpy(mydir, mypath);
     p=strrchr(mydir, '\\');
     ok(r<sizeof(mypath), "GetModuleFileName failed (%d)\n", r);
     strcpy(mydir, mypath);
     p=strrchr(mydir, '\\');
@@ -724,7 +724,7 @@ static void test_load_save(void)
     check_lnk(lnkfile, &desc, 0x4);
 
     /* Create a temporary non-executable file */
     check_lnk(lnkfile, &desc, 0x4);
 
     /* Create a temporary non-executable file */
-    r=GetTempPath(sizeof(mypath), mypath);
+    r=GetTempPathA(sizeof(mypath), mypath);
     ok(r<sizeof(mypath), "GetTempPath failed (%d), err %d\n", r, GetLastError());
     r=pGetLongPathNameA(mypath, mydir, sizeof(mydir));
     ok(r<sizeof(mydir), "GetLongPathName failed (%d), err %d\n", r, GetLastError());
     ok(r<sizeof(mypath), "GetTempPath failed (%d), err %d\n", r, GetLastError());
     r=pGetLongPathNameA(mypath, mydir, sizeof(mydir));
     ok(r<sizeof(mydir), "GetLongPathName failed (%d), err %d\n", r, GetLastError());
@@ -734,8 +734,8 @@ static void test_load_save(void)
 
     strcpy(mypath, mydir);
     strcat(mypath, "\\test.txt");
 
     strcpy(mypath, mydir);
     strcat(mypath, "\\test.txt");
-    hf = CreateFile(mypath, GENERIC_WRITE, 0, NULL,
-                    CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+    hf = CreateFileA(mypath, GENERIC_WRITE, 0, NULL,
+                     CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
     CloseHandle(hf);
 
     /* Overwrite the existing lnk file and test link to an existing non-executable file */
     CloseHandle(hf);
 
     /* Overwrite the existing lnk file and test link to an existing non-executable file */
@@ -778,8 +778,8 @@ static void test_load_save(void)
     /* Create a temporary .bat file */
     strcpy(mypath, mydir);
     strcat(mypath, "\\test.bat");
     /* Create a temporary .bat file */
     strcpy(mypath, mydir);
     strcat(mypath, "\\test.bat");
-    hf = CreateFile(mypath, GENERIC_WRITE, 0, NULL,
-                    CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+    hf = CreateFileA(mypath, GENERIC_WRITE, 0, NULL,
+                     CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
     CloseHandle(hf);
 
     strcpy(realpath, mypath);
     CloseHandle(hf);
 
     strcpy(realpath, mypath);
@@ -985,12 +985,174 @@ static void test_GetIconLocation(void)
     i = 0xdeadbeef;
     r = IShellLinkA_GetIconLocation(sl, buffer, sizeof(buffer), &i);
     ok(r == S_OK, "GetIconLocation failed (0x%08x)\n", r);
     i = 0xdeadbeef;
     r = IShellLinkA_GetIconLocation(sl, buffer, sizeof(buffer), &i);
     ok(r == S_OK, "GetIconLocation failed (0x%08x)\n", r);
-    ok(lstrcmpi(buffer,str) == 0, "GetIconLocation returned '%s'\n", buffer);
+    ok(lstrcmpiA(buffer,str) == 0, "GetIconLocation returned '%s'\n", buffer);
     ok(i == 0xbabecafe, "GetIconLocation returned %d'\n", i);
 
     IShellLinkA_Release(sl);
 }
 
     ok(i == 0xbabecafe, "GetIconLocation returned %d'\n", i);
 
     IShellLinkA_Release(sl);
 }
 
+static void test_SHGetStockIconInfo(void)
+{
+    BYTE buffer[sizeof(SHSTOCKICONINFO) + 16];
+    SHSTOCKICONINFO *sii = (SHSTOCKICONINFO *) buffer;
+    BOOL atleast_win7;
+    HRESULT hr;
+    INT i;
+
+    /* not present before vista */
+    if (!pSHGetStockIconInfo)
+    {
+        win_skip("SHGetStockIconInfo not available\n");
+        return;
+    }
+
+    /* negative values are handled */
+    memset(buffer, '#', sizeof(buffer));
+    sii->cbSize = sizeof(SHSTOCKICONINFO);
+    hr = pSHGetStockIconInfo(-1, SHGSI_ICONLOCATION, sii);
+    ok(hr == E_INVALIDARG, "-1: got 0x%x (expected E_INVALIDARG)\n", hr);
+
+    /* max. id for vista is 140 (no definition exists for this value) */
+    for (i = 0; i <= 140; i++)
+    {
+        memset(buffer, '#', sizeof(buffer));
+        sii->cbSize = sizeof(SHSTOCKICONINFO);
+        hr = pSHGetStockIconInfo(i, SHGSI_ICONLOCATION, sii);
+
+        ok(hr == S_OK,
+            "%3d: got 0x%x, iSysImageIndex: 0x%x, iIcon: 0x%x (expected S_OK)\n",
+            i, hr, sii->iSysImageIndex, sii->iIcon);
+
+        if ((hr == S_OK) && (winetest_debug > 1))
+            trace("%3d: got iSysImageIndex %3d, iIcon %3d and %s\n", i, sii->iSysImageIndex,
+                  sii->iIcon, wine_dbgstr_w(sii->szPath));
+    }
+
+    /* there are more icons since win7 */
+    memset(buffer, '#', sizeof(buffer));
+    sii->cbSize = sizeof(SHSTOCKICONINFO);
+    hr = pSHGetStockIconInfo(i, SHGSI_ICONLOCATION, sii);
+    atleast_win7 = (!hr);
+
+    for (; i < (SIID_MAX_ICONS + 25) ; i++)
+    {
+        memset(buffer, '#', sizeof(buffer));
+        sii->cbSize = sizeof(SHSTOCKICONINFO);
+        hr = pSHGetStockIconInfo(i, SHGSI_ICONLOCATION, sii);
+
+        if (atleast_win7 && (i == (SIID_MAX_ICONS - 1)) && broken(hr == E_INVALIDARG))
+        {
+            /* Off by one windows bug: there are SIID_MAX_ICONS icons from 0
+             * up to SIID_MAX_ICONS-1 on Windows 8, but the last one is missing
+             * on Windows 7.
+             */
+            trace("%3d: got E_INVALIDARG (windows bug: off by one)\n", i);
+        }
+        else if (atleast_win7 && (i < (SIID_MAX_ICONS)))
+        {
+            ok(hr == S_OK,
+                "%3d: got 0x%x, iSysImageIndex: 0x%x, iIcon: 0x%x (expected S_OK)\n",
+                i, hr, sii->iSysImageIndex, sii->iIcon);
+
+            if ((hr == S_OK) && (winetest_debug > 1))
+                trace("%3d: got iSysImageIndex %3d, iIcon %3d and %s\n", i, sii->iSysImageIndex,
+                      sii->iIcon, wine_dbgstr_w(sii->szPath));
+        }
+        else
+            ok(hr == E_INVALIDARG, "%3d: got 0x%x (expected E_INVALIDARG)\n", i, hr);
+    }
+
+    /* test more returned SHSTOCKICONINFO elements without extra flags */
+    memset(buffer, '#', sizeof(buffer));
+    sii->cbSize = sizeof(SHSTOCKICONINFO);
+    hr = pSHGetStockIconInfo(SIID_FOLDER, SHGSI_ICONLOCATION, sii);
+    ok(hr == S_OK, "got 0x%x (expected S_OK)\n", hr);
+    ok(!sii->hIcon, "got %p (expected NULL)\n", sii->hIcon);
+    ok(sii->iSysImageIndex == -1, "got %d (expected -1)\n", sii->iSysImageIndex);
+
+    /* the exact size is required of the struct */
+    memset(buffer, '#', sizeof(buffer));
+    sii->cbSize = sizeof(SHSTOCKICONINFO) + 2;
+    hr = pSHGetStockIconInfo(SIID_FOLDER, SHGSI_ICONLOCATION, sii);
+    ok(hr == E_INVALIDARG, "+2: got 0x%x, iSysImageIndex: 0x%x, iIcon: 0x%x\n", hr, sii->iSysImageIndex, sii->iIcon);
+
+    memset(buffer, '#', sizeof(buffer));
+    sii->cbSize = sizeof(SHSTOCKICONINFO) + 1;
+    hr = pSHGetStockIconInfo(SIID_FOLDER, SHGSI_ICONLOCATION, sii);
+    ok(hr == E_INVALIDARG, "+1: got 0x%x, iSysImageIndex: 0x%x, iIcon: 0x%x\n", hr, sii->iSysImageIndex, sii->iIcon);
+
+    memset(buffer, '#', sizeof(buffer));
+    sii->cbSize = sizeof(SHSTOCKICONINFO) - 1;
+    hr = pSHGetStockIconInfo(SIID_FOLDER, SHGSI_ICONLOCATION, sii);
+    ok(hr == E_INVALIDARG, "-1: got 0x%x, iSysImageIndex: 0x%x, iIcon: 0x%x\n", hr, sii->iSysImageIndex, sii->iIcon);
+
+    memset(buffer, '#', sizeof(buffer));
+    sii->cbSize = sizeof(SHSTOCKICONINFO) - 2;
+    hr = pSHGetStockIconInfo(SIID_FOLDER, SHGSI_ICONLOCATION, sii);
+    ok(hr == E_INVALIDARG, "-2: got 0x%x, iSysImageIndex: 0x%x, iIcon: 0x%x\n", hr, sii->iSysImageIndex, sii->iIcon);
+
+    /* 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);
+}
+
+static void test_SHExtractIcons(void)
+{
+    static const WCHAR notepadW[] = {'n','o','t','e','p','a','d','.','e','x','e',0};
+    static const WCHAR shell32W[] = {'s','h','e','l','l','3','2','.','d','l','l',0};
+    static const WCHAR emptyW[] = {0};
+    UINT ret, ret2;
+    HICON icons[256];
+    UINT ids[256], i;
+
+    if (!pSHExtractIconsW)
+    {
+        win_skip("SHExtractIconsW not available\n");
+        return;
+    }
+
+    ret = pSHExtractIconsW(emptyW, 0, 16, 16, icons, ids, 1, 0);
+    ok(ret == ~0u, "got %u\n", ret);
+
+    ret = pSHExtractIconsW(notepadW, 0, 16, 16, NULL, NULL, 1, 0);
+    ok(ret == 1 || broken(ret == 2) /* win2k */, "got %u\n", ret);
+
+    icons[0] = (HICON)0xdeadbeef;
+    ret = pSHExtractIconsW(notepadW, 0, 16, 16, icons, NULL, 1, 0);
+    ok(ret == 1, "got %u\n", ret);
+    ok(icons[0] != (HICON)0xdeadbeef, "icon not set\n");
+    DestroyIcon(icons[0]);
+
+    icons[0] = (HICON)0xdeadbeef;
+    ids[0] = 0xdeadbeef;
+    ret = pSHExtractIconsW(notepadW, 0, 16, 16, icons, ids, 1, 0);
+    ok(ret == 1, "got %u\n", ret);
+    ok(icons[0] != (HICON)0xdeadbeef, "icon not set\n");
+    ok(ids[0] != 0xdeadbeef, "id not set\n");
+    DestroyIcon(icons[0]);
+
+    ret = pSHExtractIconsW(shell32W, 0, 16, 16, NULL, NULL, 0, 0);
+    ret2 = pSHExtractIconsW(shell32W, 4, MAKELONG(32,16), MAKELONG(32,16), NULL, NULL, 256, 0);
+    ok(ret && ret == ret2,
+       "icon count should be independent of requested icon sizes and base icon index\n");
+
+    ret = pSHExtractIconsW(shell32W, 0, 16, 16, icons, ids, 0, 0);
+    ok(ret == ~0u || !ret /* < vista */, "got %u\n", ret);
+
+    ret = pSHExtractIconsW(shell32W, 0, 16, 16, icons, ids, 3, 0);
+    ok(ret == 3, "got %u\n", ret);
+    for (i = 0; i < ret; i++) DestroyIcon(icons[i]);
+
+    /* count must be a multiple of two when getting two sizes */
+    ret = pSHExtractIconsW(shell32W, 0, MAKELONG(16,32), MAKELONG(16,32), icons, ids, 3, 0);
+    ok(!ret /* vista */ || ret == 4, "got %u\n", ret);
+    for (i = 0; i < ret; i++) DestroyIcon(icons[i]);
+
+    ret = pSHExtractIconsW(shell32W, 0, MAKELONG(16,32), MAKELONG(16,32), icons, ids, 4, 0);
+    ok(ret == 4, "got %u\n", ret);
+    for (i = 0; i < ret; i++) DestroyIcon(icons[i]);
+}
+
 START_TEST(shelllink)
 {
     HRESULT r;
 START_TEST(shelllink)
 {
     HRESULT r;
@@ -1001,9 +1163,10 @@ START_TEST(shelllink)
     pILIsEqual = (void *)GetProcAddress(hmod, (LPSTR)21);
     pSHILCreateFromPath = (void *)GetProcAddress(hmod, (LPSTR)28);
     pSHDefExtractIconA = (void *)GetProcAddress(hmod, "SHDefExtractIconA");
     pILIsEqual = (void *)GetProcAddress(hmod, (LPSTR)21);
     pSHILCreateFromPath = (void *)GetProcAddress(hmod, (LPSTR)28);
     pSHDefExtractIconA = (void *)GetProcAddress(hmod, "SHDefExtractIconA");
-
+    pSHGetStockIconInfo = (void *)GetProcAddress(hmod, "SHGetStockIconInfo");
     pGetLongPathNameA = (void *)GetProcAddress(hkernel32, "GetLongPathNameA");
     pGetShortPathNameA = (void *)GetProcAddress(hkernel32, "GetShortPathNameA");
     pGetLongPathNameA = (void *)GetProcAddress(hkernel32, "GetLongPathNameA");
     pGetShortPathNameA = (void *)GetProcAddress(hkernel32, "GetShortPathNameA");
+    pSHExtractIconsW = (void *)GetProcAddress(hmod, "SHExtractIconsW");
 
     r = CoInitialize(NULL);
     ok(r == S_OK, "CoInitialize failed (0x%08x)\n", r);
 
     r = CoInitialize(NULL);
     ok(r == S_OK, "CoInitialize failed (0x%08x)\n", r);
@@ -1015,6 +1178,8 @@ START_TEST(shelllink)
     test_datalink();
     test_shdefextracticon();
     test_GetIconLocation();
     test_datalink();
     test_shdefextracticon();
     test_GetIconLocation();
+    test_SHGetStockIconInfo();
+    test_SHExtractIcons();
 
     CoUninitialize();
 }
 
     CoUninitialize();
 }