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