diff --git a/.gitattributes b/.gitattributes index 51ddc4a..90f3e68 100644 --- a/.gitattributes +++ b/.gitattributes @@ -16,4 +16,5 @@ *.jpg -text *.png -text *.gif -text +*.ico -text *.pdf -text diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d42fb6..4296f19 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,13 @@ versioned baseline. VCL style, so a project of your own that runs its tests in the VCL GUI runner needs Carbon among its custom styles (Project > Options > Application > Appearance) for it, and a `WinMain()` that applies the saved theme as `vcl\gui\rad370\ASWUnitTests_VCL_GUI.cpp` does. +- An ASWUnitTests icon, `resource\ASWUnitTests.ico`, which this repository's console and GUI + runners now have on Windows, with the PNGs it's made from and `resource\make_icon.ps1`, which + draws them. `ASWUNITTESTS_WIN32_GUI_SOURCES` includes `resource\ASWUnitTests_Icon.rc`, so a Win32 + GUI runner of your own built with CMake gets the icon too, in Explorer, its title bar and the + taskbar; to use your own, remove that script from the list (the README's "Win32 GUI Runner" shows + how) and name your icon `MAINICON`. `ASWUNITTESTS_RESOURCE_DIR` is the `resource` folder, which + `ASWUNITTESTS_WIN32_GUI_INCLUDE_DIRS` now includes. - A `TCLIParser::ParseArguments()` overload that takes the arguments as a `std::vector`, the program name first, as in `argv`. - `UTF8ToWide()` in `ASWUnitTests_Utils.h`, which converts UTF-8 to wide text (UTF-16 on Windows, diff --git a/Deploy.bat b/Deploy.bat index 6c65469..c58f69c 100644 --- a/Deploy.bat +++ b/Deploy.bat @@ -22,7 +22,7 @@ if not exist "%TARGET_DIR%\." ( ) ) -for %%D in (build cmake gui\src gui\tests rad370 src tests toTest vcl\console\rad370 vcl\gui\rad370 vcl\gui\src vcl\tests win32\gui\rad370 win32\gui\src win32\tests) do ( +for %%D in (build cmake gui\src gui\tests rad370 resource src tests toTest vcl\console\rad370 vcl\gui\rad370 vcl\gui\src vcl\tests win32\gui\rad370 win32\gui\src win32\tests) do ( if not exist "%TARGET_DIR%\%%D\." ( echo Creating %%D folder... mkdir "%TARGET_DIR%\%%D" @@ -145,6 +145,10 @@ call :CopyFile "rad370\Build_Win32_Debug.bat" "rad370\Build_Win32_Debug.bat" if errorlevel 1 exit /b 1 call :CopyFile "rad370\Build_Win32_Release.bat" "rad370\Build_Win32_Release.bat" if errorlevel 1 exit /b 1 +call :CopyFile "resource\ASWUnitTests.ico" "resource\ASWUnitTests.ico" +if errorlevel 1 exit /b 1 +call :CopyFile "resource\ASWUnitTests_Icon.rc" "resource\ASWUnitTests_Icon.rc" +if errorlevel 1 exit /b 1 call :CopyFile "src\ASWUnitTests_CLI.cpp" "src\ASWUnitTests_CLI.cpp" if errorlevel 1 exit /b 1 call :CopyFile "src\ASWUnitTests_CLI.h" "src\ASWUnitTests_CLI.h" diff --git a/README.md b/README.md index f1cef5e..a8c612a 100644 --- a/README.md +++ b/README.md @@ -466,7 +466,9 @@ files in `gui\src` (shared by the GUI runners) and `vcl\gui\src`, including a `WinMain()` modeled on `vcl\gui\rad370\ASWUnitTests_VCL_GUI.cpp`, which parses the command line, applies the saved theme and starts the main form. For the dark theme, also add RAD Studio's Carbon style to the application (Project > Options > Application > Appearance, which this repository's -project has as `Custom_Styles`); without it, Dark shows the light look. +project has as `Custom_Styles`); without it, Dark shows the light look. For the ASWUnitTests icon, +set the application's icon to `resource\ASWUnitTests.ico` there too, as this repository's project +does. ### Win32 GUI Runner @@ -485,8 +487,9 @@ and its `Build_*.bat` scripts write the executable to `win32\gui\rad370\true $(BDSLIB)\$(PLATFORM)\release\$(LANGDIR);$(ILINK_TranslatedLibraryPath) CppConsoleApplication + ..\resource\ASWUnitTests.ico System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace) true ASWUnitTests diff --git a/resource/ASWUnitTests.ico b/resource/ASWUnitTests.ico new file mode 100644 index 0000000..7904744 Binary files /dev/null and b/resource/ASWUnitTests.ico differ diff --git a/resource/ASWUnitTests_Icon.rc b/resource/ASWUnitTests_Icon.rc new file mode 100644 index 0000000..b56d59e --- /dev/null +++ b/resource/ASWUnitTests_Icon.rc @@ -0,0 +1,27 @@ +/* ************************************************************************** +ASWUnitTests_Icon.rc +Author: Anthony S. West - ASW Software + +Embeds the ASWUnitTests icon in the CMake builds of the console runner and +the Win32 GUI runner (MSVC, MinGW and Clang). The RAD Studio projects embed +the same .ico themselves (Icon_MainIcon), also as MAINICON, which is the +name the Win32 GUI runner loads it by. The .ico is found through the +include path, which has this folder. + +Copyright 2026 ASW Software + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +************************************************************************** */ + +MAINICON ICON "ASWUnitTests.ico" diff --git a/resource/icon_16.png b/resource/icon_16.png new file mode 100644 index 0000000..91adc46 Binary files /dev/null and b/resource/icon_16.png differ diff --git a/resource/icon_20.png b/resource/icon_20.png new file mode 100644 index 0000000..749d600 Binary files /dev/null and b/resource/icon_20.png differ diff --git a/resource/icon_24.png b/resource/icon_24.png new file mode 100644 index 0000000..ae92fae Binary files /dev/null and b/resource/icon_24.png differ diff --git a/resource/icon_256.png b/resource/icon_256.png new file mode 100644 index 0000000..f439c30 Binary files /dev/null and b/resource/icon_256.png differ diff --git a/resource/icon_32.png b/resource/icon_32.png new file mode 100644 index 0000000..64af3ae Binary files /dev/null and b/resource/icon_32.png differ diff --git a/resource/icon_40.png b/resource/icon_40.png new file mode 100644 index 0000000..98fd06d Binary files /dev/null and b/resource/icon_40.png differ diff --git a/resource/icon_48.png b/resource/icon_48.png new file mode 100644 index 0000000..42cd3d0 Binary files /dev/null and b/resource/icon_48.png differ diff --git a/resource/icon_64.png b/resource/icon_64.png new file mode 100644 index 0000000..8241b52 Binary files /dev/null and b/resource/icon_64.png differ diff --git a/resource/make_icon.ps1 b/resource/make_icon.ps1 new file mode 100644 index 0000000..3b9cc0b --- /dev/null +++ b/resource/make_icon.ps1 @@ -0,0 +1,138 @@ +# Draws the ASWUnitTests icon (a blue rounded badge with a green check mark and, from 32 px up, a green and red +# progress bar) at each icon size, and writes icon_.png and ASWUnitTests.ico (BMP entries below 256 px, PNG +# at 256) beside this script, replacing them; the same drawing gives the same files. ImageMagick's magick packs +# the .ico, so it must be on the PATH. Also writes a preview sheet of every size on light and dark backgrounds to +# %TEMP%\ASWUnitTests_icon_preview.png. +# Usage (Windows PowerShell): & resource\make_icon.ps1 +Add-Type -AssemblyName System.Drawing +$out = $PSScriptRoot + +$sizes = 16, 20, 24, 32, 40, 48, 64, 256 + +function C([string]$hex) { return [System.Drawing.ColorTranslator]::FromHtml($hex) } +$blueTop = C '#2D66B5' +$blueBottom = C '#173B72' +$edge = C '#0E2850' +$green = C '#4BC55E' +$greenDark = C '#2E8F3E' +$red = C '#E5484D' +$track = C '#0E2850' + +function RoundedRect([float]$x, [float]$y, [float]$w, [float]$h, [float]$r) +{ + $p = New-Object System.Drawing.Drawing2D.GraphicsPath + $d = 2 * $r + $p.AddArc($x, $y, $d, $d, 180, 90) + $p.AddArc($x + $w - $d, $y, $d, $d, 270, 90) + $p.AddArc($x + $w - $d, $y + $h - $d, $d, $d, 0, 90) + $p.AddArc($x, $y + $h - $d, $d, $d, 90, 90) + $p.CloseFigure() + return $p +} + +function Draw([int]$size) +{ + $s = $size / 256.0 + $bmp = New-Object System.Drawing.Bitmap($size, $size, [System.Drawing.Imaging.PixelFormat]::Format32bppArgb) + $g = [System.Drawing.Graphics]::FromImage($bmp) + $g.SmoothingMode = 'AntiAlias' + $g.PixelOffsetMode = 'HighQuality' + $g.Clear([System.Drawing.Color]::Transparent) + + $withBar = ($size -ge 32) + + # Badge: the full square at 16-24 px, so the check mark gets every pixel. + $margin = if ($size -lt 32) { 0 } else { [Math]::Floor(8 * $s) } + $radius = [Math]::Max(2.5, 44 * $s) + $side = $size - 2 * $margin + $badge = RoundedRect $margin $margin $side $side $radius + $bottom = $margin + $side + $brush = New-Object System.Drawing.Drawing2D.LinearGradientBrush( + (New-Object System.Drawing.PointF(0, $margin)), (New-Object System.Drawing.PointF(0, $bottom)), + $blueTop, $blueBottom) + $g.FillPath($brush, $badge) + if ($size -ge 48) + { + $pen = New-Object System.Drawing.Pen($edge, [Math]::Max(1, 4 * $s)) + $g.DrawPath($pen, $badge) + } + + # Check mark: thicker, relative to the size, when it's small. + if ($withBar) + { + $pts = @((64, 120), (108, 164), (194, 76)); $width = 36 + } + else + { + $pts = @((54, 132), (104, 182), (204, 80)); $width = 48 + } + $points = [System.Drawing.PointF[]]@($pts | ForEach-Object { New-Object System.Drawing.PointF(($_[0] * $s), ($_[1] * $s)) }) + if ($size -ge 48) + { + # A darker green rim, for definition against the blue. + $rim = New-Object System.Drawing.Pen($greenDark, (($width + 8) * $s)) + $rim.StartCap = 'Round'; $rim.EndCap = 'Round'; $rim.LineJoin = 'Round' + $g.DrawLines($rim, $points) + } + $checkPen = New-Object System.Drawing.Pen($green, ($width * $s)) + $checkPen.StartCap = 'Round'; $checkPen.EndCap = 'Round'; $checkPen.LineJoin = 'Round' + $g.DrawLines($checkPen, $points) + + # Progress bar: mostly green, ending red, as the GUI's shows passes and a failure. + if ($withBar) + { + $bx = 52 * $s; $bw = 152 * $s + $bh = [Math]::Max(3, 20 * $s); $by = 196 * $s + $br = $bh / 2 + $g.FillPath((New-Object System.Drawing.SolidBrush($track)), (RoundedRect $bx $by $bw $bh $br)) + $split = $bx + $bw * 0.72 + $g.SetClip((New-Object System.Drawing.RectangleF($bx, $by, ($split - $bx), $bh))) + $g.FillPath((New-Object System.Drawing.SolidBrush($green)), (RoundedRect $bx $by $bw $bh $br)) + $g.SetClip((New-Object System.Drawing.RectangleF($split, $by, ($bx + $bw - $split), $bh))) + $g.FillPath((New-Object System.Drawing.SolidBrush($red)), (RoundedRect $bx $by $bw $bh $br)) + $g.ResetClip() + } + + $g.Dispose() + $bmp.Save("$out\icon_$size.png", [System.Drawing.Imaging.ImageFormat]::Png) + return $bmp +} + +$images = @{} +foreach ($size in $sizes) { $images[$size] = Draw $size } + +# Preview sheet: each size at 1x on a light and a dark band, then 16-48 px magnified 6x on both, then 256 px. +$sheetW = 1400; $sheetH = 700 +$sheet = New-Object System.Drawing.Bitmap($sheetW, $sheetH) +$g = [System.Drawing.Graphics]::FromImage($sheet) +$g.Clear((C '#FFFFFF')) +$g.FillRectangle((New-Object System.Drawing.SolidBrush((C '#F3F3F3'))), 0, 0, 700, 400) +$g.FillRectangle((New-Object System.Drawing.SolidBrush((C '#202020'))), 700, 0, 700, 400) +$x = 20 +foreach ($size in 16, 20, 24, 32, 40, 48, 64) +{ + $g.DrawImageUnscaled($images[$size], $x, 20) + $g.DrawImageUnscaled($images[$size], $x + 700, 20) + $x += $size + 20 +} +$g.InterpolationMode = 'NearestNeighbor' +$g.PixelOffsetMode = 'Half' +$x = 20 +foreach ($size in 16, 20, 24, 32) +{ + $g.DrawImage($images[$size], $x, 110, $size * 6, $size * 6) + $g.DrawImage($images[$size], $x + 700, 110, $size * 6, $size * 6) + $x += $size * 6 + 16 +} +$g.InterpolationMode = 'HighQualityBicubic' +$g.DrawImage($images[256], 20, 420, 256, 256) +$g.DrawImage($images[48], 300, 420, 288, 288) +$g.FillRectangle((New-Object System.Drawing.SolidBrush((C '#202020'))), 700, 400, 700, 300) +$g.DrawImage($images[256], 720, 420, 256, 256) +$g.Dispose() +$sheet.Save("$env:TEMP\ASWUnitTests_icon_preview.png", [System.Drawing.Imaging.ImageFormat]::Png) + +$pngs = $sizes | ForEach-Object { "$out\icon_$_.png" } +& magick @pngs "$out\ASWUnitTests.ico" +& magick identify "$out\ASWUnitTests.ico" +"wrote the PNGs and ASWUnitTests.ico to $out, and the preview to $env:TEMP\ASWUnitTests_icon_preview.png" diff --git a/vcl/console/rad370/ASWUnitTests_VCL_Console.cbproj b/vcl/console/rad370/ASWUnitTests_VCL_Console.cbproj index 2b8e65c..a05e556 100644 --- a/vcl/console/rad370/ASWUnitTests_VCL_Console.cbproj +++ b/vcl/console/rad370/ASWUnitTests_VCL_Console.cbproj @@ -59,6 +59,7 @@ true $(BDSLIB)\$(PLATFORM)\release\$(LANGDIR);$(ILINK_TranslatedLibraryPath) CppConsoleApplication + ..\..\..\resource\ASWUnitTests.ico System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) rtl.lib;vcl.lib true diff --git a/vcl/gui/rad370/ASWUnitTests_VCL_GUI.cbproj b/vcl/gui/rad370/ASWUnitTests_VCL_GUI.cbproj index e9fe852..4b33a31 100644 --- a/vcl/gui/rad370/ASWUnitTests_VCL_GUI.cbproj +++ b/vcl/gui/rad370/ASWUnitTests_VCL_GUI.cbproj @@ -88,7 +88,7 @@ rtl.lib;vcl.lib <_TCHARMapping>wchar_t true - $(BDS)\bin\cbuilder_PROJECTICON.ico + ..\..\..\resource\ASWUnitTests.ico $(BDS)\bin\Artwork\Windows\UWP\cppreg_UwpDefault_44.png $(BDS)\bin\Artwork\Windows\UWP\cppreg_UwpDefault_150.png ASWUnitTests_VCL_GUI diff --git a/win32/gui/rad370/ASWUnitTests_Win32_GUI.cbproj b/win32/gui/rad370/ASWUnitTests_Win32_GUI.cbproj index d493c9d..f43e523 100644 --- a/win32/gui/rad370/ASWUnitTests_Win32_GUI.cbproj +++ b/win32/gui/rad370/ASWUnitTests_Win32_GUI.cbproj @@ -54,6 +54,7 @@ true $(BDSLIB)\$(PLATFORM)\release\$(LANGDIR);$(ILINK_TranslatedLibraryPath) CppVCLApplication + ..\..\..\resource\ASWUnitTests.ico System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace) true ASWUnitTests_Win32_GUI diff --git a/win32/gui/src/ASWUnitTests_Win32GUI_MainWindow.cpp b/win32/gui/src/ASWUnitTests_Win32GUI_MainWindow.cpp index d68854a..cb5dbd7 100644 --- a/win32/gui/src/ASWUnitTests_Win32GUI_MainWindow.cpp +++ b/win32/gui/src/ASWUnitTests_Win32GUI_MainWindow.cpp @@ -804,6 +804,8 @@ void TWin32GUIMainWindow::Create() windowClass.cbSize = sizeof(windowClass); windowClass.lpfnWndProc = &WindowProc; windowClass.hInstance = instance; + // With no small icon given, Windows takes the title bar's from the same resource, at the size it needs. + windowClass.hIcon = MainIcon(); windowClass.hCursor = LoadCursorW(nullptr, MAKEINTRESOURCEW(32512)); // IDC_ARROW windowClass.hbrBackground = reinterpret_cast(COLOR_BTNFACE + 1); windowClass.lpszClassName = MainWindowClassName; diff --git a/win32/gui/src/ASWUnitTests_Win32GUI_Sources.cmake b/win32/gui/src/ASWUnitTests_Win32GUI_Sources.cmake index ec1afa9..7eb6f4d 100644 --- a/win32/gui/src/ASWUnitTests_Win32GUI_Sources.cmake +++ b/win32/gui/src/ASWUnitTests_Win32GUI_Sources.cmake @@ -7,13 +7,21 @@ # ASWUNITTESTS_WIN32_GUI_SOURCES The framework's core sources (all # but main.cpp), the GUI runners' # shared core, this folder's units -# including WinMain, and the -# manifest: the .manifest file +# including WinMain, the +# manifest (the .manifest file # itself for MSVC, or the resource # script that embeds it for other -# compilers. +# compilers), and +# ASWUnitTests_Icon.rc, which +# embeds the ASWUnitTests icon. A +# project with an icon of its own +# removes that script from the list +# (see the usage below); the window +# shows its icon if it's named +# MAINICON. # ASWUNITTESTS_WIN32_GUI_INCLUDE_DIRS Their directories, for the include -# path. +# path (the resource compiler finds +# the icon through it). # ASWUNITTESTS_WIN32_GUI_LIBRARIES The Windows libraries it links. # ASWUNITTESTS_WIN32_GUI_LINK_OPTIONS Linker options it needs: with MSVC, # leaving the execution level to the @@ -22,6 +30,8 @@ # or later, which gives its windows # the same frame as other programs. # ASWUNITTESTS_WIN32_GUI_SOURCE_DIR This folder. +# ASWUNITTESTS_RESOURCE_DIR The repository's resource folder, +# which has the icon. # # It includes src/ASWUnitTests_Sources.cmake and # gui/src/ASWUnitTests_GUI_Sources.cmake, so their variables are also set. @@ -38,11 +48,16 @@ # target_include_directories(MyTestsGUI PRIVATE ${ASWUNITTESTS_WIN32_GUI_INCLUDE_DIRS} tests) # target_link_libraries(MyTestsGUI PRIVATE ${ASWUNITTESTS_WIN32_GUI_LIBRARIES}) # target_link_options(MyTestsGUI PRIVATE ${ASWUNITTESTS_WIN32_GUI_LINK_OPTIONS}) +# +# To use an icon of your own instead, before add_executable(): +# +# list(REMOVE_ITEM ASWUNITTESTS_WIN32_GUI_SOURCES "${ASWUNITTESTS_RESOURCE_DIR}/ASWUnitTests_Icon.rc") include("${CMAKE_CURRENT_LIST_DIR}/../../../src/ASWUnitTests_Sources.cmake") include("${CMAKE_CURRENT_LIST_DIR}/../../../gui/src/ASWUnitTests_GUI_Sources.cmake") set(ASWUNITTESTS_WIN32_GUI_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}") +get_filename_component(ASWUNITTESTS_RESOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../resource" ABSOLUTE) set(ASWUNITTESTS_WIN32_GUI_SOURCES ${ASWUNITTESTS_CORE_SOURCES} @@ -56,12 +71,14 @@ set(ASWUNITTESTS_WIN32_GUI_SOURCES "${ASWUNITTESTS_WIN32_GUI_SOURCE_DIR}/ASWUnitTests_Win32GUI_System.cpp" "${ASWUNITTESTS_WIN32_GUI_SOURCE_DIR}/ASWUnitTests_Win32GUI_TextDialog.cpp" "${ASWUNITTESTS_WIN32_GUI_SOURCE_DIR}/ASWUnitTests_Win32GUI_WinMain.cpp" + "${ASWUNITTESTS_RESOURCE_DIR}/ASWUnitTests_Icon.rc" ) set(ASWUNITTESTS_WIN32_GUI_INCLUDE_DIRS "${ASWUNITTESTS_SOURCE_DIR}" "${ASWUNITTESTS_GUI_SOURCE_DIR}" "${ASWUNITTESTS_WIN32_GUI_SOURCE_DIR}" + "${ASWUNITTESTS_RESOURCE_DIR}" ) set(ASWUNITTESTS_WIN32_GUI_LIBRARIES diff --git a/win32/gui/src/ASWUnitTests_Win32GUI_System.cpp b/win32/gui/src/ASWUnitTests_Win32GUI_System.cpp index b41dcda..1c1e7ee 100644 --- a/win32/gui/src/ASWUnitTests_Win32GUI_System.cpp +++ b/win32/gui/src/ASWUnitTests_Win32GUI_System.cpp @@ -260,6 +260,11 @@ std::string GUISettingsFolderPath() return WideToUTF8(appData) + "\\ASWUnitTests"; } //--------------------------------------------------------------------------- +HICON MainIcon() +{ + return LoadIconW(GetModuleHandleW(nullptr), L"MAINICON"); +} +//--------------------------------------------------------------------------- std::vector ProcessArguments() { return CommandLineArguments(GetCommandLineW()); diff --git a/win32/gui/src/ASWUnitTests_Win32GUI_System.h b/win32/gui/src/ASWUnitTests_Win32GUI_System.h index 43f4aa3..fb29896 100644 --- a/win32/gui/src/ASWUnitTests_Win32GUI_System.h +++ b/win32/gui/src/ASWUnitTests_Win32GUI_System.h @@ -64,6 +64,9 @@ std::string GUISelectionFilePath(); // The folder that holds the GUI runners' layout and selection files, %APPDATA%\ASWUnitTests. It may not exist // yet (see CreateFolderPath()). std::string GUISettingsFolderPath(); +// This executable's icon, its MAINICON resource (resource/ASWUnitTests_Icon.rc, or Icon_MainIcon in a RAD Studio +// project), at the standard icon size; nullptr if it has none. Shared, so it's never destroyed. +HICON MainIcon(); // This process's command-line arguments, without the program name, converted to UTF-8, for // TGUICommandLine::Parse(). std::vector ProcessArguments(); diff --git a/win32/gui/src/ASWUnitTests_Win32GUI_TextDialog.cpp b/win32/gui/src/ASWUnitTests_Win32GUI_TextDialog.cpp index 75a9799..46df46b 100644 --- a/win32/gui/src/ASWUnitTests_Win32GUI_TextDialog.cpp +++ b/win32/gui/src/ASWUnitTests_Win32GUI_TextDialog.cpp @@ -135,6 +135,10 @@ INT_PTR HandleDialogMessage(HWND dialog, UINT message, WPARAM wParam, LPARAM lPa SendMessageW(textBox, EM_SETLIMITTEXT, 0, 0); SetWindowTextW(textBox, state->Text.c_str()); + // Shown before the main window exists (e.g. for --help), it has a taskbar button of its own. + if (GetWindow(dialog, GW_OWNER) == nullptr) + SendMessageW(dialog, WM_SETICON, ICON_BIG, reinterpret_cast(MainIcon())); + SizeAndCenterDialog(dialog); ApplyDPI(dialog); diff --git a/win32/tests/Test_ASWUnitTests_Win32GUI_System.cpp b/win32/tests/Test_ASWUnitTests_Win32GUI_System.cpp index 42ba17a..514e842 100644 --- a/win32/tests/Test_ASWUnitTests_Win32GUI_System.cpp +++ b/win32/tests/Test_ASWUnitTests_Win32GUI_System.cpp @@ -120,6 +120,8 @@ TTest_ASWUnitTests_Win32GUI_System::TTest_ASWUnitTests_Win32GUI_System() "GUILayoutFilePath_IsPerExeUnderAppData"); RegisterTest(&TTest_ASWUnitTests_Win32GUI_System::Test_GUISelectionFilePath_IsBesideTheLayoutFile, "GUISelectionFilePath_IsBesideTheLayoutFile"); + RegisterTest(&TTest_ASWUnitTests_Win32GUI_System::Test_MainIcon_IsThisExecutablesSharedIcon, + "MainIcon_IsThisExecutablesSharedIcon"); RegisterTest(&TTest_ASWUnitTests_Win32GUI_System::Test_ReadFileBytes_ReadsWhatWriteFileBytesWrote, "ReadFileBytes_ReadsWhatWriteFileBytesWrote"); RegisterTest(&TTest_ASWUnitTests_Win32GUI_System::Test_ReadFileBytes_ThrowsForAMissingFile, @@ -313,6 +315,17 @@ void TTest_ASWUnitTests_Win32GUI_System::Test_GUISelectionFilePath_IsBesideTheLa "the layout file's path with a .selection extension"); } //--------------------------------------------------------------------------- +void TTest_ASWUnitTests_Win32GUI_System::Test_MainIcon_IsThisExecutablesSharedIcon() +{ + // Act: every runner that compiles this test embeds the ASWUnitTests icon. + HICON const icon = MainIcon(); + HICON const again = MainIcon(); + + // Assert + CheckTrue(icon != nullptr, __func__, __LINE__, "this executable has a MAINICON resource"); + CheckTrue(again == icon, __func__, __LINE__, "the same, shared, icon each time"); +} +//--------------------------------------------------------------------------- void TTest_ASWUnitTests_Win32GUI_System::Test_ReadFileBytes_ReadsWhatWriteFileBytesWrote() { // Arrange: a file name with a character outside every ANSI code page but UTF-8's (U+4E2D), and bytes a diff --git a/win32/tests/Test_ASWUnitTests_Win32GUI_System.h b/win32/tests/Test_ASWUnitTests_Win32GUI_System.h index 37ef5f1..f2e0185 100644 --- a/win32/tests/Test_ASWUnitTests_Win32GUI_System.h +++ b/win32/tests/Test_ASWUnitTests_Win32GUI_System.h @@ -61,6 +61,7 @@ class TTest_ASWUnitTests_Win32GUI_System : public TTestGroupBase void Test_FileExists_IsTrueOnlyForAFile(); void Test_GUILayoutFilePath_IsPerExeUnderAppData(); void Test_GUISelectionFilePath_IsBesideTheLayoutFile(); + void Test_MainIcon_IsThisExecutablesSharedIcon(); void Test_ReadFileBytes_ReadsWhatWriteFileBytesWrote(); void Test_ReadFileBytes_ThrowsForAMissingFile(); void Test_RemoveFile_DeletesOnlyAnExistingFile();