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 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 39 static void ExtractOneBitmap(HBITMAP hbm, CComHeapPtr<BYTE>& data, DWORD& size) 40 { 41 HDC hdc = CreateCompatibleDC(NULL); 42 HGDIOBJ obj = SelectObject(hdc, hbm); 43 44 CComHeapPtr<BITMAPINFO> pInfoBM; 45 46 pInfoBM.AllocateBytes(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)); 47 memset(pInfoBM, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)); 48 pInfoBM->bmiHeader.biSize = sizeof(pInfoBM->bmiHeader); 49 if (!GetDIBits(hdc, hbm, 0, 0, NULL, pInfoBM, DIB_RGB_COLORS)) 50 return; 51 52 size = pInfoBM->bmiHeader.biSizeImage; 53 data.Allocate(size); 54 GetDIBits(hdc, hbm, 0, pInfoBM->bmiHeader.biHeight, data, pInfoBM, DIB_RGB_COLORS); 55 56 SelectObject(hdc, obj); 57 DeleteDC(hdc); 58 } 59 60 static bool GetIconData(HICON icon, CComHeapPtr<BYTE>& colorData, DWORD& colorSize, CComHeapPtr<BYTE>& maskData, DWORD& maskSize) 61 { 62 ICONINFO iconinfo; 63 64 if (!GetIconInfo(icon, &iconinfo)) 65 return false; 66 67 ExtractOneBitmap(iconinfo.hbmColor, colorData, colorSize); 68 ExtractOneBitmap(iconinfo.hbmMask, maskData, maskSize); 69 70 DeleteObject(iconinfo.hbmColor); 71 DeleteObject(iconinfo.hbmMask); 72 73 return true; 74 } 75 76 77 START_TEST(SHCreateFileExtractIconW) 78 { 79 WCHAR CurrentModule[MAX_PATH]; 80 HMODULE shell32 = LoadLibraryA("shell32.dll"); 81 HICON myIcon; 82 pSHCreateFileExtractIconW = (HRESULT (__stdcall *)(LPCWSTR, DWORD, REFIID, void **))GetProcAddress(shell32, "SHCreateFileExtractIconW"); 83 84 CoInitialize(NULL); 85 86 GetModuleFileNameW(NULL, CurrentModule, _countof(CurrentModule)); 87 { 88 SHFILEINFOW shfi; 89 ULONG_PTR firet = SHGetFileInfoW(CurrentModule, 0, &shfi, sizeof(shfi), SHGFI_ICON); 90 myIcon = shfi.hIcon; 91 if (!firet) 92 { 93 skip("Unable to get my own icon\n"); 94 return; 95 } 96 } 97 98 if (!pSHCreateFileExtractIconW) 99 { 100 skip("SHCreateFileExtractIconW not available\n"); 101 return; 102 } 103 104 for (size_t n = 0; n < _countof(IconTests); ++n) 105 { 106 TestData& cur = IconTests[n]; 107 bool useMyIcon = false; 108 109 if (cur.Name == NULL) 110 { 111 cur.Name = CurrentModule; 112 useMyIcon = true; 113 } 114 115 CComPtr<IExtractIconW> spExtract; 116 HRESULT hr = pSHCreateFileExtractIconW(cur.Name, cur.dwFlags, IID_PPV_ARG(IExtractIconW, &spExtract)); 117 ok(hr == S_OK, "Expected hr to be S_OK, was 0x%lx for %S(%lx)\n", hr, cur.Name, cur.dwFlags); 118 119 if (!SUCCEEDED(hr)) 120 continue; 121 122 int ilIndex = -1; 123 UINT wFlags = 0xdeaddead; 124 WCHAR Buffer[MAX_PATH]; 125 126 hr = spExtract->GetIconLocation(0, Buffer, _countof(Buffer), &ilIndex, &wFlags); 127 ok(hr == S_OK, "Expected hr to be S_OK, was 0x%lx for %S(%lx)\n", hr, cur.Name, cur.dwFlags); 128 if (!SUCCEEDED(hr)) 129 continue; 130 131 ok(wFlags & (GIL_NOTFILENAME|GIL_PERCLASS), "Expected GIL_NOTFILENAME|GIL_PERCLASS to be set for %S(%lx)\n", cur.Name, cur.dwFlags); 132 ok(!wcscmp(Buffer, L"*"), "Expected '*', was '%S' for %S(%lx)\n", Buffer, cur.Name, cur.dwFlags); 133 134 HICON ico; 135 hr = spExtract->Extract(Buffer, ilIndex, &ico, NULL, 0); 136 137 /* Visualize the icon extracted for whoever is stepping through this code. */ 138 HWND console = GetConsoleWindow(); 139 SendMessage(console, WM_SETICON, ICON_BIG, (LPARAM)ico); 140 SendMessage(console, WM_SETICON, ICON_SMALL, (LPARAM)ico); 141 142 CComHeapPtr<BYTE> colorData, maskData; 143 DWORD colorSize = 0, maskSize = 0; 144 145 GetIconData(ico, colorData, colorSize, maskData, maskSize); 146 147 if (!colorSize || !maskSize) 148 continue; 149 150 SHFILEINFOW shfi; 151 ULONG_PTR firet = SHGetFileInfoW(cur.Name, cur.dwFlags, &shfi, sizeof(shfi), SHGFI_USEFILEATTRIBUTES | SHGFI_ICON); 152 153 if (!firet) 154 continue; 155 156 CComHeapPtr<BYTE> colorDataRef, maskDataRef; 157 DWORD colorSizeRef = 0, maskSizeRef = 0; 158 GetIconData(shfi.hIcon, colorDataRef, colorSizeRef, maskDataRef, maskSizeRef); 159 160 ok(colorSizeRef == colorSize, "Expected %lu, was %lu for %S(%lx)\n", colorSizeRef, colorSize, cur.Name, cur.dwFlags); 161 ok(maskSizeRef == maskSize, "Expected %lu, was %lu for %S(%lx)\n", maskSizeRef, maskSize, cur.Name, cur.dwFlags); 162 163 if (colorSizeRef == colorSize) 164 { 165 ok(!memcmp(colorData, colorDataRef, colorSize), "Expected equal colorData for %S(%lx)\n", cur.Name, cur.dwFlags); 166 } 167 168 if (maskSizeRef == maskSize) 169 { 170 ok(!memcmp(maskData, maskDataRef, maskSize), "Expected equal maskData for %S(%lx)\n", cur.Name, cur.dwFlags); 171 } 172 173 if (useMyIcon) 174 { 175 colorDataRef.Free(); 176 maskDataRef.Free(); 177 colorSizeRef = maskSizeRef = 0; 178 GetIconData(myIcon, colorDataRef, colorSizeRef, maskDataRef, maskSizeRef); 179 180 ok(colorSizeRef == colorSize, "Expected %lu, was %lu for %S(%lx)\n", colorSizeRef, colorSize, cur.Name, cur.dwFlags); 181 ok(maskSizeRef == maskSize, "Expected %lu, was %lu for %S(%lx)\n", maskSizeRef, maskSize, cur.Name, cur.dwFlags); 182 183 if (colorSizeRef == colorSize) 184 { 185 /* Incase requested filetype does not match, the exe icon is not used! */ 186 if (cur.dwFlags == FILE_ATTRIBUTE_DIRECTORY) 187 { 188 ok(memcmp(colorData, colorDataRef, colorSize), "Expected colorData to be changed for %S(%lx)\n", cur.Name, cur.dwFlags); 189 } 190 else 191 { 192 ok(!memcmp(colorData, colorDataRef, colorSize), "Expected equal colorData for %S(%lx)\n", cur.Name, cur.dwFlags); 193 } 194 } 195 196 // Mask is not reliable for some reason 197 //if (maskSizeRef == maskSize) 198 //{ 199 // ok(!memcmp(maskData, maskDataRef, maskSize), "Expected equal maskData for %S(%lx)\n", cur.Name, cur.dwFlags); 200 //} 201 } 202 } 203 } 204