Reactos
at master 236 lines 6.8 kB view raw
1/* 2 * PROJECT: ReactOS API Tests 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Tests for ExtractIconEx routine 5 * COPYRIGHT: Copyright 2019 George Bișoc (george.bisoc@reactos.org) 6 * Copyright 2023 Doug Lyons (douglyons@douglyons.com) 7 */ 8 9#include "shelltest.h" 10#include <stdio.h> 11 12EXTERN_C BOOL WINAPI SHAreIconsEqual(HICON hIcon1, HICON hIcon2); 13 14static void SafeDestroyIcon(HICON hIco) 15{ 16 if (hIco) 17 DestroyIcon(hIco); 18} 19 20static UINT GetIcoSize(HICON hIco) 21{ 22 ICONINFO info; 23 if (!GetIconInfo(hIco, &info)) 24 return 0; 25 26 BITMAP bm; 27 if (!GetObject(info.hbmColor ? info.hbmColor : info.hbmMask, sizeof(bm), &bm)) 28 bm.bmWidth = 0; 29 DeleteObject(info.hbmMask); 30 DeleteObject(info.hbmColor); 31 return bm.bmWidth; 32} 33 34typedef struct 35{ 36 PCWSTR pszFilePath; 37 UINT nIcons; 38} EXTRACTICONTEST; 39 40BOOL FileExists(LPCSTR FileName) 41{ 42 FILE *fp = NULL; 43 bool exists = FALSE; 44 45 fp = fopen(FileName, "r"); 46 if (fp != NULL) 47 { 48 exists = TRUE; 49 fclose(fp); 50 } 51 return exists; 52} 53 54BOOL ResourceToFile(INT i, LPCSTR FileName) 55{ 56 FILE *fout; 57 HGLOBAL hData; 58 HRSRC hRes; 59 LPVOID lpResLock; 60 UINT iSize; 61 62 if (FileExists(FileName)) 63 { 64 skip("'%s' already exists. Exiting now\n", FileName); 65 return FALSE; 66 } 67 68 hRes = FindResourceW(NULL, MAKEINTRESOURCEW(i), MAKEINTRESOURCEW(RT_RCDATA)); 69 if (hRes == NULL) 70 { 71 skip("Could not locate resource (%d). Exiting now\n", i); 72 return FALSE; 73 } 74 75 iSize = SizeofResource(NULL, hRes); 76 77 hData = LoadResource(NULL, hRes); 78 if (hData == NULL) 79 { 80 skip("Could not load resource (%d). Exiting now\n", i); 81 return FALSE; 82 } 83 84 // Lock the resource into global memory. 85 lpResLock = LockResource(hData); 86 if (lpResLock == NULL) 87 { 88 skip("Could not lock resource (%d). Exiting now\n", i); 89 return FALSE; 90 } 91 92 fout = fopen(FileName, "wb"); 93 fwrite(lpResLock, iSize, 1, fout); 94 fclose(fout); 95 return TRUE; 96} 97 98EXTRACTICONTEST IconTests[] = 99{ 100 /* Executable file with icon */ 101 {L"%SystemRoot%\\System32\\cmd.exe", 1}, 102 103 /* Executable file without icon */ 104 {L"%SystemRoot%\\System32\\autochk.exe", 0}, 105 106 /* Non-existing files */ 107 {L"%SystemRoot%\\non-existent-file.sdf", 0}, 108 109 /* Multiple icons in the same ICO file (6 icons) 110 * Per MS: If the file is an .ico file, the return value is 1. */ 111 {L"sysicon.ico", 1}, 112 113 /* ICO file with both normal and PNG icons */ 114 {L"ROS.ico", (UINT)(GetNTVersion() >= _WIN32_WINNT_VISTA ? 1 : 0)} 115}; 116 117VOID RunExtractIconTest(EXTRACTICONTEST *Test) 118{ 119 UINT nReturnedIcons, nExtractedIcons; 120 121 /* Check count of icons returned */ 122 nReturnedIcons = ExtractIconExW(Test->pszFilePath, -1, NULL, NULL, 0); 123 ok(nReturnedIcons == Test->nIcons, "ExtractIconExW(L\"%S\"): Expects %u icons, got %u\n", Test->pszFilePath, Test->nIcons, nReturnedIcons); 124 125 /* Check if the 0th icon can be extracted successfully */ 126 nExtractedIcons = ExtractIconExW(Test->pszFilePath, 0, NULL, NULL, 1); 127 ok(nExtractedIcons == Test->nIcons, "ExtractIconExW(L\"%S\"): Expects %u icons, got %u\n", Test->pszFilePath, Test->nIcons, nExtractedIcons); 128} 129 130START_TEST(ExtractIconEx) 131{ 132 UINT i; 133 CHAR FileName[2][13] = { "ROS.ico", "sysicon.ico" }; 134 EXTRACTICONTEST explorer_exe = {L"%SystemRoot%\\explorer.exe", 0}; 135 136 if (!ResourceToFile(2, FileName[0])) 137 return; 138 if (!ResourceToFile(3, FileName[1])) 139 return; 140 141 /* Run normal tests */ 142 for (i = 0; i < _countof(IconTests); ++i) 143 RunExtractIconTest(&IconTests[i]); 144 145 /* Run special case checks */ 146 switch (GetNTVersion()) 147 { 148 case _WIN32_WINNT_WS03: 149 explorer_exe.nIcons = 18; 150 break; 151 case _WIN32_WINNT_VISTA: 152 explorer_exe.nIcons = 23; 153 break; 154 case _WIN32_WINNT_WIN7: 155 explorer_exe.nIcons = 25; 156 break; 157 case _WIN32_WINNT_WIN8: 158 case _WIN32_WINNT_WINBLUE: 159 explorer_exe.nIcons = 24; 160 break; 161 case _WIN32_WINNT_WIN10: 162 explorer_exe.nIcons = 28; 163 break; 164 } 165 166 if (explorer_exe.nIcons) 167 RunExtractIconTest(&explorer_exe); 168 else 169 skip("Unknown NT Version: 0x%lX\n", GetNTVersion()); 170 171 DeleteFileA(FileName[0]); 172 DeleteFileA(FileName[1]); 173} 174 175static HRESULT SHDEI(LPCWSTR pszIconFile, int Index = 0, UINT GIL = 0, UINT Size = 0) 176{ 177 HICON hIco = NULL; 178 HRESULT hr = SHDefExtractIcon(pszIconFile, Index, GIL, &hIco, NULL, Size); 179 if (hr == S_OK) 180 { 181 hr = GetIcoSize(hIco); 182 SafeDestroyIcon(hIco); 183 } 184 return hr; 185} 186 187START_TEST(SHDefExtractIcon) 188{ 189 HRESULT hr; 190 int SysBigIconSize = GetSystemMetrics(SM_CXICON); 191 192 // Modern Windows requires the system image list to be initialized for GIL_SIMULATEDOC to work! 193 SHFILEINFOW shfi; 194 SHGetFileInfoW(L"x", 0, &shfi, sizeof(shfi), SHGFI_SYSICONINDEX | SHGFI_USEFILEATTRIBUTES); 195 196 WCHAR path[MAX_PATH]; 197 GetSystemDirectoryW(path, _countof(path)); 198 PathAppendW(path, L"user32.dll"); 199 int index = 1; 200 201 ok(SHDEI(path, index, 0, 0) == SysBigIconSize, "0 size must match GetSystemMetrics\n"); 202 ok(SHDEI(path, index, 0, SysBigIconSize * 2) == SysBigIconSize * 2, "Resize failed\n"); 203 204 HICON hIcoLarge, hIcoSmall; 205 if (SHDefExtractIcon(path, index, 0, &hIcoLarge, &hIcoSmall, 0) != S_OK) 206 hIcoLarge = hIcoSmall = NULL; 207 ok(hIcoLarge && hIcoSmall && !SHAreIconsEqual(hIcoLarge, hIcoSmall), "Large+Small failed\n"); 208 SafeDestroyIcon(hIcoLarge); 209 SafeDestroyIcon(hIcoSmall); 210 211 static const int sizes[] = { 0, SysBigIconSize * 2 }; 212 for (UINT i = 0; i < _countof(sizes); ++i) 213 { 214 HICON hIcoNormal, hIcoSimDoc; 215 if (FAILED(hr = SHDefExtractIcon(path, index, 0, &hIcoNormal, NULL, sizes[i]))) 216 hIcoNormal = NULL; 217 if (FAILED(hr = SHDefExtractIcon(path, index, GIL_SIMULATEDOC, &hIcoSimDoc, NULL, sizes[i]))) 218 hIcoSimDoc = NULL; 219 ok(hIcoNormal && hIcoSimDoc && !SHAreIconsEqual(hIcoNormal, hIcoSimDoc), "GIL_SIMULATEDOC failed\n"); 220 SafeDestroyIcon(hIcoNormal); 221 SafeDestroyIcon(hIcoSimDoc); 222 } 223 224 GetTempPathW(_countof(path), path); 225 GetTempFileNameW(path, L"TEST", 0, path); 226 ok(SHDEI(path) == S_FALSE, "Empty file should return S_FALSE\n"); 227 HANDLE hFile = CreateFileW(path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL); 228 if (hFile != INVALID_HANDLE_VALUE) 229 { 230 DWORD io; 231 WriteFile(hFile, "!", 1, &io, NULL); 232 CloseHandle(hFile); 233 ok(SHDEI(path) == S_FALSE, "File without icons should return S_FALSE\n"); 234 } 235 DeleteFile(path); 236}