+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]);
+}
+