https://git.reactos.org/?p=reactos.git;a=commitdiff;h=454a27cdff3c817ad873c…
commit 454a27cdff3c817ad873c9fa0c325c89fe243c0a
Author:     Doug Lyons <douglyons(a)douglyons.com>
AuthorDate: Mon Jul 10 14:24:41 2023 -0500
Commit:     GitHub <noreply(a)github.com>
CommitDate: Mon Jul 10 22:24:41 2023 +0300
    [USER32_APITEST] Improve user32:PrivateExtractIcons test (#5209)
    - Improve the test by examining total number of icon groups in files
      and by adding more testcases including two new icon files.
    - Add new ROS.ico file which has both a normal icon and a PNG one.
    - Add tests for explorer.exe and new ROS.ico and sysicon.ico files.
    CORE-18897
---
 .../rostests/apitests/user32/PrivateExtractIcons.c | 125 +++++++++++++++++++--
 modules/rostests/apitests/user32/ROS.ico           | Bin 0 -> 10526 bytes
 modules/rostests/apitests/user32/resource.h        |   3 +
 modules/rostests/apitests/user32/sysicon.ico       | Bin 0 -> 22486 bytes
 modules/rostests/apitests/user32/user32_apitest.rc |   3 +
 5 files changed, 120 insertions(+), 11 deletions(-)
diff --git a/modules/rostests/apitests/user32/PrivateExtractIcons.c
b/modules/rostests/apitests/user32/PrivateExtractIcons.c
index 01c43ee0c74..85edab85a16 100644
--- a/modules/rostests/apitests/user32/PrivateExtractIcons.c
+++ b/modules/rostests/apitests/user32/PrivateExtractIcons.c
@@ -3,38 +3,132 @@
  * LICENSE:         LGPLv2.1+ - See COPYING.LIB in the top level directory
  * PURPOSE:         Test for PrivateExtractIcons
  * PROGRAMMER:      Hermes Belusca-Maito
+ *                  Doug Lyons <douglyons(a)douglyons.com>
  */
 #include "precomp.h"
+#include <stdio.h>
+
+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))
+    {
+        skip("'%S' already exists. Exiting now\n", FileName);
+        return FALSE;
+    }
+
+    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 from PrivateExtractIconsW
+    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 icons */
-    {L"notepad.exe", 1, TRUE},
-    {L"%SystemRoot%\\System32\\cmd.exe", 1, TRUE},
+    /* Executables with just one icon group */
+    {L"notepad.exe", 1, 1, TRUE},
+    {L"%SystemRoot%\\System32\\cmd.exe", 1, 1, TRUE},
-    /* Executable without icon */
-    {L"%SystemRoot%\\System32\\autochk.exe", 0, FALSE},
+    /* Executable without icon groups */
+    {L"%SystemRoot%\\System32\\autochk.exe", 0, 0, FALSE},
-    /* Existing file */
-    {L"%SystemRoot%\\System32\\shell32.dll", 1, TRUE},
+    /* 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, FALSE},
+    {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},
+};
+
+static struct
+{
+    PCWSTR FileName;
+    INT ResourceId;
+} IconFiles[] =
+{
+    {L"%temp%\\ROS.ico", IDR_ICONS_PNG},
+    {L"%temp%\\sysicon.ico", IDR_ICONS_NORMAL},
 };
 START_TEST(PrivateExtractIcons)
 {
     HICON ahIcon;
-    UINT i, aIconId, cIcons;
+    UINT i, aIconId, cIcons, cIcoTotal;
+    WCHAR PathBuffer[MAX_PATH];
+
+    /* Extract icons */
+    for (i = 0; i < _countof(IconFiles); ++i)
+    {
+        ExpandEnvironmentStringsW(IconFiles[i].FileName, PathBuffer,
_countof(PathBuffer));
+
+        if (!ResourceToFile(IconFiles[i].ResourceId, PathBuffer))
+            goto Cleanup;
+    }
     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 < 240 :    /* shell32 case: ROS
has 233, W2K2SP2 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;
@@ -46,7 +140,9 @@ START_TEST(PrivateExtractIcons)
             i, IconTests[i].bhIconValid ? "valid" : "not valid",
ahIcon);
         if (cIcons == 0xFFFFFFFF)
         {
-            ok(aIconId == 0xdeadbeef, "PrivateExtractIconsW(%u): id should not be
set\n", i);
+            ok(aIconId == 0xdeadbeef,
+               "PrivateExtractIconsW(%u): id should not be set to 0x%x\n",
+               i, aIconId);
         }
         else
         {
@@ -55,4 +151,11 @@ START_TEST(PrivateExtractIcons)
         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);
+    }
 }
diff --git a/modules/rostests/apitests/user32/ROS.ico
b/modules/rostests/apitests/user32/ROS.ico
new file mode 100644
index 00000000000..587992b6eea
Binary files /dev/null and b/modules/rostests/apitests/user32/ROS.ico differ
diff --git a/modules/rostests/apitests/user32/resource.h
b/modules/rostests/apitests/user32/resource.h
index 8435d9ff725..ac91b1b51be 100644
--- a/modules/rostests/apitests/user32/resource.h
+++ b/modules/rostests/apitests/user32/resource.h
@@ -1,2 +1,5 @@
 #define IDI_TEST 1000
+
+#define IDR_ICONS_PNG 2000
+#define IDR_ICONS_NORMAL 2001
diff --git a/modules/rostests/apitests/user32/sysicon.ico
b/modules/rostests/apitests/user32/sysicon.ico
new file mode 100644
index 00000000000..2c32fdf0022
Binary files /dev/null and b/modules/rostests/apitests/user32/sysicon.ico differ
diff --git a/modules/rostests/apitests/user32/user32_apitest.rc
b/modules/rostests/apitests/user32/user32_apitest.rc
index c6da5676f18..370c3aaa721 100644
--- a/modules/rostests/apitests/user32/user32_apitest.rc
+++ b/modules/rostests/apitests/user32/user32_apitest.rc
@@ -8,6 +8,9 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
 IDI_TEST ICON "test.ico"
 TESTCURSOR CURSOR "test.cur"
+IDR_ICONS_PNG RCDATA "ROS.ico"
+IDR_ICONS_NORMAL RCDATA "sysicon.ico"
+
 TESTDIALOG DIALOG 0,0, 200,200
 CLASS "TestDialogClass"
 CAPTION  "Testdialog"