1 /* 2 * PROJECT: ReactOS API tests 3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) 4 * PURPOSE: Test for SHCreateFileExtractIconW 5 * COPYRIGHT: Copyright 2017,2018 Mark Jansen (mark.jansen@reactos.org) 6 */ 7 8 #include "shelltest.h" 9 10 #include <wincon.h> 11 #include <wingdi.h> 12 13 ULONG DbgPrint(PCH Format,...); 14 #include <shellutils.h> 15 16 HRESULT (STDAPICALLTYPE *pSHCreateFileExtractIconW)(LPCWSTR pszFile, DWORD dwFileAttributes, REFIID riid, void **ppv); 17 18 struct TestData 19 { 20 const WCHAR* Name; 21 DWORD dwFlags; 22 }; 23 24 static TestData IconTests[] = 25 { 26 { L"xxx.zip", FILE_ATTRIBUTE_NORMAL }, 27 { L"xxx.zip", FILE_ATTRIBUTE_DIRECTORY }, 28 { L"xxx.exe", FILE_ATTRIBUTE_NORMAL }, 29 { L"xxx.exe", FILE_ATTRIBUTE_DIRECTORY }, 30 { L"xxx.dll", FILE_ATTRIBUTE_NORMAL }, 31 { L"xxx.dll", FILE_ATTRIBUTE_DIRECTORY }, 32 { L"xxx.txt", FILE_ATTRIBUTE_NORMAL }, 33 { L"xxx.txt", FILE_ATTRIBUTE_DIRECTORY }, 34 { NULL, FILE_ATTRIBUTE_NORMAL }, 35 { NULL, FILE_ATTRIBUTE_DIRECTORY }, 36 }; 37 38 struct TestIID 39 { 40 const GUID* IID; 41 HRESULT ExpectedCreate; 42 HRESULT ExpectedQueryInterface; 43 }; 44 45 static TestIID InterfaceTests[] = 46 { 47 { &IID_IDefaultExtractIconInit, E_NOINTERFACE, E_NOINTERFACE }, 48 { &IID_IExtractIconW, S_OK, S_OK }, 49 { &IID_IExtractIconA, S_OK, S_OK }, 50 { &IID_IPersist, E_NOINTERFACE, E_NOINTERFACE }, 51 { &IID_IPersistFile, E_NOINTERFACE, E_NOINTERFACE }, 52 }; 53 54 55 static void ExtractOneBitmap(HBITMAP hbm, CComHeapPtr<BYTE>& data, DWORD& size) 56 { 57 HDC hdc = CreateCompatibleDC(NULL); 58 HGDIOBJ obj = SelectObject(hdc, hbm); 59 60 CComHeapPtr<BITMAPINFO> pInfoBM; 61 62 pInfoBM.AllocateBytes(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)); 63 memset(pInfoBM, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)); 64 pInfoBM->bmiHeader.biSize = sizeof(pInfoBM->bmiHeader); 65 if (!GetDIBits(hdc, hbm, 0, 0, NULL, pInfoBM, DIB_RGB_COLORS)) 66 return; 67 68 size = pInfoBM->bmiHeader.biSizeImage; 69 data.Allocate(size); 70 GetDIBits(hdc, hbm, 0, pInfoBM->bmiHeader.biHeight, data, pInfoBM, DIB_RGB_COLORS); 71 72 SelectObject(hdc, obj); 73 DeleteDC(hdc); 74 } 75 76 static bool GetIconData(HICON icon, CComHeapPtr<BYTE>& colorData, DWORD& colorSize, CComHeapPtr<BYTE>& maskData, DWORD& maskSize) 77 { 78 ICONINFO iconinfo; 79 80 if (!GetIconInfo(icon, &iconinfo)) 81 return false; 82 83 ExtractOneBitmap(iconinfo.hbmColor, colorData, colorSize); 84 ExtractOneBitmap(iconinfo.hbmMask, maskData, maskSize); 85 86 DeleteObject(iconinfo.hbmColor); 87 DeleteObject(iconinfo.hbmMask); 88 89 return true; 90 } 91 92 93 START_TEST(SHCreateFileExtractIconW) 94 { 95 WCHAR CurrentModule[MAX_PATH]; 96 HMODULE shell32 = LoadLibraryA("shell32.dll"); 97 HICON myIcon; 98 pSHCreateFileExtractIconW = (HRESULT (__stdcall *)(LPCWSTR, DWORD, REFIID, void **))GetProcAddress(shell32, "SHCreateFileExtractIconW"); 99 100 /* Show that icons returned are always the same */ 101 UINT tryFlags[4] = { 0, GIL_FORSHORTCUT, GIL_OPENICON }; 102 103 CoInitialize(NULL); 104 105 GetModuleFileNameW(NULL, CurrentModule, _countof(CurrentModule)); 106 { 107 SHFILEINFOW shfi; 108 ULONG_PTR firet = SHGetFileInfoW(CurrentModule, 0, &shfi, sizeof(shfi), SHGFI_ICON); 109 myIcon = shfi.hIcon; 110 if (!firet) 111 { 112 skip("Unable to get my own icon\n"); 113 return; 114 } 115 } 116 117 if (!pSHCreateFileExtractIconW) 118 { 119 skip("SHCreateFileExtractIconW not available\n"); 120 return; 121 } 122 123 for (size_t n = 0; n < _countof(InterfaceTests); ++n) 124 { 125 { 126 CComPtr<IUnknown> spUnknown; 127 HRESULT hr = pSHCreateFileExtractIconW(L"test.txt", FILE_ATTRIBUTE_NORMAL, *InterfaceTests[n].IID, (void**)&spUnknown); 128 ok(hr == InterfaceTests[n].ExpectedCreate, "Expected hr to be 0x%lx, was 0x%lx for %u\n", InterfaceTests[n].ExpectedCreate, hr, n); 129 } 130 131 { 132 CComPtr<IUnknown> spUnknown, spUnknown2; 133 HRESULT hr = pSHCreateFileExtractIconW(L"test.txt", FILE_ATTRIBUTE_NORMAL, IID_PPV_ARG(IUnknown, &spUnknown)); 134 ok(hr == S_OK, "Expected hr to be S_OK, was 0x%lx for %u\n", hr, n); 135 136 hr = spUnknown->QueryInterface(*InterfaceTests[n].IID, (void**)&spUnknown2); 137 ok(hr == InterfaceTests[n].ExpectedQueryInterface, "Expected hr to be 0x%lx, was 0x%lx for %u\n", InterfaceTests[n].ExpectedQueryInterface, hr, n); 138 } 139 } 140 141 for (size_t n = 0; n < _countof(IconTests); ++n) 142 { 143 TestData& cur = IconTests[n]; 144 bool useMyIcon = false; 145 146 if (cur.Name == NULL) 147 { 148 cur.Name = CurrentModule; 149 useMyIcon = true; 150 } 151 152 CComPtr<IExtractIconW> spExtract; 153 HRESULT hr = pSHCreateFileExtractIconW(cur.Name, cur.dwFlags, IID_PPV_ARG(IExtractIconW, &spExtract)); 154 ok(hr == S_OK, "Expected hr to be S_OK, was 0x%lx for %S(%lx)\n", hr, cur.Name, cur.dwFlags); 155 156 if (!SUCCEEDED(hr)) 157 continue; 158 159 /* Show that GIL_DEFAULTICON does not work. */ 160 { 161 int ilIndex = -1; 162 UINT wFlags = 0xdeaddead; 163 WCHAR Buffer[MAX_PATH]; 164 165 hr = spExtract->GetIconLocation(GIL_DEFAULTICON, Buffer, _countof(Buffer), &ilIndex, &wFlags); 166 ok(hr == S_FALSE, "Expected hr to be S_FALSE, was 0x%lx for %S(0x%lx)\n", hr, cur.Name, cur.dwFlags); 167 } 168 169 170 for (UINT idFlags = 0; idFlags < _countof(tryFlags); ++idFlags) 171 { 172 int ilIndex = -1; 173 UINT wFlags = 0xdeaddead; 174 WCHAR Buffer[MAX_PATH]; 175 176 hr = spExtract->GetIconLocation(tryFlags[idFlags], Buffer, _countof(Buffer), &ilIndex, &wFlags); 177 ok(hr == S_OK, "Expected hr to be S_OK, was 0x%lx for %S(0x%lx,0x%x)\n", hr, cur.Name, cur.dwFlags, tryFlags[idFlags]); 178 if (!SUCCEEDED(hr)) 179 continue; 180 181 ok(wFlags & (GIL_NOTFILENAME|GIL_PERCLASS), "Expected GIL_NOTFILENAME|GIL_PERCLASS to be set for %S(0x%lx,0x%x)\n", cur.Name, cur.dwFlags, tryFlags[idFlags]); 182 ok(!wcscmp(Buffer, L"*"), "Expected '*', was '%S' for %S(0x%lx,0x%x)\n", Buffer, cur.Name, cur.dwFlags, tryFlags[idFlags]); 183 184 HICON ico; 185 hr = spExtract->Extract(Buffer, ilIndex, &ico, NULL, 0); 186 187 /* Visualize the icon extracted for whoever is stepping through this code. */ 188 HWND console = GetConsoleWindow(); 189 SendMessage(console, WM_SETICON, ICON_BIG, (LPARAM)ico); 190 SendMessage(console, WM_SETICON, ICON_SMALL, (LPARAM)ico); 191 192 CComHeapPtr<BYTE> colorData, maskData; 193 DWORD colorSize = 0, maskSize = 0; 194 195 GetIconData(ico, colorData, colorSize, maskData, maskSize); 196 197 if (!colorSize || !maskSize) 198 continue; 199 200 SHFILEINFOW shfi; 201 ULONG_PTR firet = SHGetFileInfoW(cur.Name, cur.dwFlags, &shfi, sizeof(shfi), SHGFI_USEFILEATTRIBUTES | SHGFI_ICON | SHGFI_SYSICONINDEX); 202 203 if (!firet) 204 continue; 205 206 ok(shfi.iIcon == ilIndex, "Expected ilIndex to be 0%x, was 0x%x for %S(0x%lx,0x%x)\n", shfi.iIcon, ilIndex, cur.Name, cur.dwFlags, tryFlags[idFlags]); 207 208 209 CComHeapPtr<BYTE> colorDataRef, maskDataRef; 210 DWORD colorSizeRef = 0, maskSizeRef = 0; 211 GetIconData(shfi.hIcon, colorDataRef, colorSizeRef, maskDataRef, maskSizeRef); 212 213 ok(colorSizeRef == colorSize, "Expected %lu, was %lu for %S(0x%lx,0x%x)\n", colorSizeRef, colorSize, cur.Name, cur.dwFlags, tryFlags[idFlags]); 214 ok(maskSizeRef == maskSize, "Expected %lu, was %lu for %S(0x%lx,0x%x)\n", maskSizeRef, maskSize, cur.Name, cur.dwFlags, tryFlags[idFlags]); 215 216 if (colorSizeRef == colorSize) 217 { 218 ok(!memcmp(colorData, colorDataRef, colorSize), "Expected equal colorData for %S(0x%lx,0x%x)\n", cur.Name, cur.dwFlags, tryFlags[idFlags]); 219 } 220 221 if (maskSizeRef == maskSize) 222 { 223 ok(!memcmp(maskData, maskDataRef, maskSize), "Expected equal maskData for %S(0x%lx,0x%x)\n", cur.Name, cur.dwFlags, tryFlags[idFlags]); 224 } 225 226 if (useMyIcon) 227 { 228 colorDataRef.Free(); 229 maskDataRef.Free(); 230 colorSizeRef = maskSizeRef = 0; 231 GetIconData(myIcon, colorDataRef, colorSizeRef, maskDataRef, maskSizeRef); 232 233 ok(colorSizeRef == colorSize, "Expected %lu, was %lu for %S(0x%lx,0x%x)\n", colorSizeRef, colorSize, cur.Name, cur.dwFlags, tryFlags[idFlags]); 234 ok(maskSizeRef == maskSize, "Expected %lu, was %lu for %S(0x%lx,0x%x)\n", maskSizeRef, maskSize, cur.Name, cur.dwFlags, tryFlags[idFlags]); 235 236 if (colorSizeRef == colorSize) 237 { 238 /* In case requested filetype does not match, the exe icon is not used! */ 239 if (cur.dwFlags == FILE_ATTRIBUTE_DIRECTORY) 240 { 241 ok(memcmp(colorData, colorDataRef, colorSize), "Expected colorData to be changed for %S(0x%lx,0x%x)\n", cur.Name, cur.dwFlags, tryFlags[idFlags]); 242 } 243 else 244 { 245 ok(!memcmp(colorData, colorDataRef, colorSize), "Expected equal colorData for %S(0x%lx,0x%x)\n", cur.Name, cur.dwFlags, tryFlags[idFlags]); 246 } 247 } 248 249 // Mask is not reliable for some reason 250 //if (maskSizeRef == maskSize) 251 //{ 252 // ok(!memcmp(maskData, maskDataRef, maskSize), "Expected equal maskData for %S(0x%lx,0x%lx)\n", cur.Name, cur.dwFlags); 253 //} 254 } 255 } 256 } 257 } 258