mirror of
https://github.com/reactos/reactos.git
synced 2025-07-22 16:13:46 +00:00
252 lines
8 KiB
C
252 lines
8 KiB
C
/*
|
|
* PROJECT: ReactOS api tests
|
|
* LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory
|
|
* PURPOSE: Test for PrivateExtractIcons
|
|
* PROGRAMMER: Hermes Belusca-Maito
|
|
* Doug Lyons <douglyons@douglyons.com>
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
#include <stdio.h>
|
|
#include <versionhelpers.h>
|
|
|
|
BOOL IsValidIcon(HICON hIco)
|
|
{
|
|
ICONINFO info = { 0 };
|
|
|
|
if (!hIco || !GetIconInfo(hIco, &info))
|
|
return FALSE;
|
|
|
|
DeleteObject(info.hbmMask);
|
|
if (info.hbmColor)
|
|
DeleteObject(info.hbmColor);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL FileExists(PCWSTR FileName)
|
|
{
|
|
DWORD Attribute = GetFileAttributesW(FileName);
|
|
|
|
return (Attribute != INVALID_FILE_ATTRIBUTES &&
|
|
!(Attribute & FILE_ATTRIBUTE_DIRECTORY));
|
|
}
|
|
|
|
BOOL ResourceToFile(INT i, PCWSTR FileName)
|
|
{
|
|
FILE *fout;
|
|
HGLOBAL hData;
|
|
HRSRC hRes;
|
|
PVOID pResLock;
|
|
UINT iSize;
|
|
|
|
if (FileExists(FileName))
|
|
{
|
|
/* We should only be using %temp% paths, so deleting here should be OK */
|
|
printf("Deleting '%S' that already exists.\n", FileName);
|
|
DeleteFileW(FileName);
|
|
}
|
|
|
|
hRes = FindResourceW(NULL, MAKEINTRESOURCEW(i), MAKEINTRESOURCEW(RT_RCDATA));
|
|
if (hRes == NULL)
|
|
{
|
|
skip("Could not locate resource (%d). Exiting now\n", i);
|
|
return FALSE;
|
|
}
|
|
|
|
iSize = SizeofResource(NULL, hRes);
|
|
|
|
hData = LoadResource(NULL, hRes);
|
|
if (hData == NULL)
|
|
{
|
|
skip("Could not load resource (%d). Exiting now\n", i);
|
|
return FALSE;
|
|
}
|
|
|
|
// Lock the resource into global memory.
|
|
pResLock = LockResource(hData);
|
|
if (pResLock == NULL)
|
|
{
|
|
skip("Could not lock resource (%d). Exiting now\n", i);
|
|
return FALSE;
|
|
}
|
|
|
|
fout = _wfopen(FileName, L"wb");
|
|
fwrite(pResLock, iSize, 1, fout);
|
|
fclose(fout);
|
|
return TRUE;
|
|
}
|
|
|
|
static struct
|
|
{
|
|
PCWSTR FilePath;
|
|
UINT cIcons; // Return value of the first icon group extracted (should be 1 if no error)
|
|
UINT cTotalIcons; // Return value of total icon groups in file
|
|
BOOL bhIconValid; // Whether or not the returned icon handle is not NULL.
|
|
} IconTests[] =
|
|
{
|
|
/* Executables with just one icon group */
|
|
{L"notepad.exe", 1, 1, TRUE},
|
|
{L"%SystemRoot%\\System32\\cmd.exe", 1, 1, TRUE},
|
|
|
|
/* Executable without icon groups */
|
|
{L"%SystemRoot%\\System32\\autochk.exe", 0, 0, FALSE},
|
|
|
|
/* Existing file (shell32 has 233 icon groups in ReactOS only) */
|
|
{L"%SystemRoot%\\System32\\shell32.dll", 1, 233, TRUE},
|
|
|
|
/* Non-existing files */
|
|
{L"%SystemRoot%\\non-existent-file.sdf", 0xFFFFFFFF, 0, FALSE},
|
|
|
|
/* Executable with 18 icon groups */
|
|
{L"%SystemRoot%\\explorer.exe", 1, 18, TRUE},
|
|
|
|
/* Icon group file containing 6 icons */
|
|
{L"%temp%\\sysicon.ico", 1, 1, TRUE},
|
|
|
|
/* Icon group file containing one PNG icon and one normal icon */
|
|
{L"%temp%\\ROS.ico", 1, 1, TRUE},
|
|
|
|
/* Executable file with bad 'Icon Group' but good 'Icons'.
|
|
* Windows explorer shows the program's icon correctly in WinXP/Win2K3
|
|
* but Windows 7 shows only a default icon. This is analogous
|
|
* to EXE's generated by older Watcom C/C++ versions. */
|
|
{L"%temp%\\cpimg2e.exe", 1, 1, TRUE},
|
|
};
|
|
|
|
static struct
|
|
{
|
|
PCWSTR FileName;
|
|
INT ResourceId;
|
|
} IconFiles[] =
|
|
{
|
|
{L"%temp%\\ROS.ico", IDR_ICONS_PNG},
|
|
{L"%temp%\\sysicon.ico", IDR_ICONS_NORMAL},
|
|
{L"%temp%\\cpimg2e.exe", IDR_EXE_NORMAL}
|
|
};
|
|
|
|
void TestPairExtraction(void);
|
|
|
|
START_TEST(PrivateExtractIcons)
|
|
{
|
|
HICON ahIcon;
|
|
UINT i, aIconId, cIcons, cIcoTotal;
|
|
WCHAR PathBuffer[MAX_PATH];
|
|
UINT Shell32WinIcoCount = IsWindowsVistaOrGreater() ? 326 : 239; /* 239 on W2K3SP2, 326 on Win10 */
|
|
|
|
/* Extract icons */
|
|
for (i = 0; i < _countof(IconFiles); ++i)
|
|
{
|
|
ExpandEnvironmentStringsW(IconFiles[i].FileName, PathBuffer, _countof(PathBuffer));
|
|
|
|
if (!ResourceToFile(IconFiles[i].ResourceId, PathBuffer))
|
|
goto Cleanup;
|
|
}
|
|
|
|
TestPairExtraction();
|
|
|
|
for (i = 0; i < _countof(IconTests); ++i)
|
|
{
|
|
/* Get total number of icon groups in file.
|
|
* None of the hard numbers in the function matter since we have
|
|
* two NULLs for the Icon Handle and Count to be set. */
|
|
cIcoTotal = PrivateExtractIconsW(IconTests[i].FilePath, 0, 16, 16, NULL, NULL, 0, 0);
|
|
ok((i == 3 ?
|
|
cIcoTotal > 232 && cIcoTotal <= Shell32WinIcoCount : /* shell32 case: ROS has 233, Windows has >= 239 icon groups. */
|
|
cIcoTotal == IconTests[i].cTotalIcons),
|
|
"PrivateExtractIconsW(%u): "
|
|
"got %u, expected %u\n", i, cIcoTotal, IconTests[i].cTotalIcons);
|
|
|
|
/* Always test extraction of the FIRST icon (index 0) */
|
|
ahIcon = (HICON)UlongToHandle(0xdeadbeef);
|
|
aIconId = 0xdeadbeef;
|
|
cIcons = PrivateExtractIconsW(IconTests[i].FilePath, 0, 16, 16, &ahIcon, &aIconId, 1, 0);
|
|
ok(cIcons == IconTests[i].cIcons, "PrivateExtractIconsW(%u): got %u, expected %u\n", i, cIcons, IconTests[i].cIcons);
|
|
ok(ahIcon != (HICON)UlongToHandle(0xdeadbeef), "PrivateExtractIconsW(%u): icon not set\n", i);
|
|
ok((IconTests[i].bhIconValid && ahIcon) || (!IconTests[i].bhIconValid && !ahIcon),
|
|
"PrivateExtractIconsW(%u): icon expected to be %s, but got 0x%p\n",
|
|
i, IconTests[i].bhIconValid ? "valid" : "not valid", ahIcon);
|
|
if (cIcons == 0xFFFFFFFF)
|
|
{
|
|
ok(aIconId == 0xdeadbeef,
|
|
"PrivateExtractIconsW(%u): id should not be set to 0x%x\n",
|
|
i, aIconId);
|
|
}
|
|
else
|
|
{
|
|
ok(aIconId != 0xdeadbeef, "PrivateExtractIconsW(%u): id not set\n", i);
|
|
}
|
|
if (ahIcon && ahIcon != (HICON)UlongToHandle(0xdeadbeef))
|
|
DestroyIcon(ahIcon);
|
|
}
|
|
|
|
Cleanup:
|
|
for (i = 0; i < _countof(IconFiles); ++i)
|
|
{
|
|
ExpandEnvironmentStringsW(IconFiles[i].FileName, PathBuffer, _countof(PathBuffer));
|
|
DeleteFileW(PathBuffer);
|
|
}
|
|
}
|
|
|
|
static const struct tagPAIRSTESTS
|
|
{
|
|
BYTE InCount;
|
|
BYTE UseHigh; // Extract a pair (high and low word sizes)
|
|
BYTE Library;
|
|
BYTE ReturnNT5;
|
|
BYTE CountNT5;
|
|
BYTE ReturnNT6;
|
|
BYTE CountNT6;
|
|
} g_pairs[] =
|
|
{
|
|
{ 0, 0, 0, 1, 1, 1, 1 },
|
|
{ 0, 0, 1, 0, 0, 0, 0 },
|
|
{ 0, 1, 0, 1, 2, 1, 2 },
|
|
{ 0, 1, 1, 0, 0, 0, 0 },
|
|
{ 1, 0, 0, 1, 1, 1, 1 },
|
|
{ 1, 0, 1, 1, 1, 1, 1 },
|
|
{ 1, 1, 0, 1, 2, 1, 2 },
|
|
{ 1, 1, 1, 2, 2, 0, 0 },
|
|
{ 2, 0, 0, 1, 1, 1, 1 },
|
|
{ 2, 0, 1, 2, 2, 2, 2 },
|
|
{ 2, 1, 0, 1, 2, 1, 2 },
|
|
{ 2, 1, 1, 2, 2, 2, 2 }, // This is the only way to extract a pair from a PE on NT6!
|
|
{ 3, 0, 0, 1, 1, 1, 1 },
|
|
{ 3, 0, 1, 3, 3, 3, 3 },
|
|
{ 3, 1, 0, 1, 2, 1, 2 },
|
|
{ 3, 1, 1, 4, 4, 0, 0 },
|
|
{ 4, 0, 0, 1, 1, 1, 1 },
|
|
{ 4, 0, 1, 4, 4, 4, 4 },
|
|
{ 4, 1, 0, 1, 2, 1, 2 },
|
|
{ 4, 1, 1, 4, 4, 4, 4 }
|
|
};
|
|
|
|
void TestPairExtraction(void)
|
|
{
|
|
const HICON hInvalidIcon = (HICON)(INT_PTR)-2;
|
|
const BOOL IsNT6 = IsWindowsVistaOrGreater();
|
|
for (UINT i = 0; i < _countof(g_pairs); ++i)
|
|
{
|
|
UINT j, Count, ExpectedCount;
|
|
int RetVal, ExpectedRet;
|
|
UINT IcoSize = MAKELONG(32, g_pairs[i].UseHigh ? 16 : 0);
|
|
PCWSTR pszPath = g_pairs[i].Library ? L"%SystemRoot%\\system32\\shell32.dll" : L"%temp%\\sysicon.ico";
|
|
HICON hIcons[8];
|
|
for (j = 0; j < _countof(hIcons); ++j)
|
|
hIcons[j] = hInvalidIcon;
|
|
|
|
RetVal = PrivateExtractIconsW(pszPath, 0, IcoSize, IcoSize, hIcons, NULL, g_pairs[i].InCount, 0);
|
|
for (j = 0, Count = 0; j < _countof(hIcons); ++j)
|
|
{
|
|
if (hIcons[j] != hInvalidIcon && IsValidIcon(hIcons[j]))
|
|
{
|
|
DestroyIcon(hIcons[j]);
|
|
++Count;
|
|
}
|
|
}
|
|
|
|
ExpectedRet = !IsNT6 ? g_pairs[i].ReturnNT5 : g_pairs[i].ReturnNT6;
|
|
ExpectedCount = !IsNT6 ? g_pairs[i].CountNT5 : g_pairs[i].CountNT6;
|
|
ok(RetVal == ExpectedRet, "Test %u: RetVal must be %d but got %d\n", i, ExpectedRet, RetVal);
|
|
ok(Count == ExpectedCount, "Test %u: Count must be %u but got %u\n", i, ExpectedCount, Count);
|
|
}
|
|
}
|