PREFACE: Old programmer (C and C++ ca'1999... I've met Bjarne S. 'm old, but I'm a Fun Gi;))
Coming back to Windows C++ graphics programming; trying to learn GDIplus; using MS Visual Studio Community 2019, Ver 16.10.2
GOAL: Attempting to draw a a simple chess board, that scales with Window main form...
PROBLEM: Program compiles and paints initial window fine. But, when the window is resized larger in x, y, or x&y by mouse click and drag, it (appears it) only does a partial client area repaint; leaving artifacts at previous scale; painting only the new region of board at larger changed scale...
CONJECTURE: I (probably) need to force a repaint of the entire client every time(?).
FURTHER ISSUE: I cannot figure out the method to force full client repaint on my own (despite hitting PC repeatedly while supplicating BAAL, &c.).
Please Help.
Below are my code, some images of what happens when the window is resized by mouse click & drag, and the VS build and debug run output messages...
(I'm sure it's way overkill, but I like to be thorough.)
Thank You, All, in advance, for your time and assistance!
Peace - Tom
//=============================================================================================================
//<BEGIN - CODE>
#include <windows.h>
#include <gdiplus.h>
LRESULT CALLBACK WindowProcessMessages(HWND, UINT, WPARAM, LPARAM); // Main Window message processing function prototype
void drawBoard(HDC, HWND); // Prototype for function to draw a Chess Board prototype
int WINAPI WinMain(_In_ HINSTANCE currentInstance, _In_opt_ HINSTANCE previousInstance, _In_ PSTR cmdLine, _In_ INT cmdCount) {
//Initialize GDI+
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, nullptr);
const char* CLASS_NAME = "WinDrawWin32Class";
WNDCLASS wc{};
wc.hInstance = currentInstance;
wc.lpszClassName = CLASS_NAME;
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.lpfnWndProc = WindowProcessMessages;
RegisterClass(&wc);
// Craeat the App's Main Window
CreateWindow(CLASS_NAME, "WinDraw Main Window",
WS_OVERLAPPEDWINDOW | WS_VISIBLE, // Start On Top and Visible
CW_USEDEFAULT, // initial X position (default)
CW_USEDEFAULT, // initial Y position (default)
800, 600, // Width (x) & Height (y)
nullptr, nullptr, nullptr, nullptr); // Last 4 args unused
// Window Message Processing Loop
MSG msg{}; // Structure holds the windows message
while (GetMessage(&msg, nullptr, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// shut down GDI
Gdiplus::GdiplusShutdown(gdiplusToken);
return 0;
}
LRESULT CALLBACK WindowProcessMessages(HWND hwnd, UINT msg, WPARAM param, LPARAM lparam) {
HDC hdc;
PAINTSTRUCT ps;
const RECT* lprcUpdate = nullptr;
switch (msg) {
case WM_PAINT:
// Draw entities within BeginPaint and EndPaint fn calls.
hdc = BeginPaint(hwnd, &ps);
drawBoard(hdc, hwnd);
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
// Done, get out.
PostQuitMessage(0);
return 0;
default:
// Fall through to default handler
return DefWindowProc(hwnd, msg, param, lparam);
}
}
void drawBoard(HDC hdc, HWND hwnd){
Gdiplus::Graphics gf(hdc);
Gdiplus::Pen Blackpen(Gdiplus::Color(255, 0, 0, 0)); // Black pen
Gdiplus::SolidBrush Bluebrush(Gdiplus::Color(255, 0, 0, 210)); // Dark Blue brush
Gdiplus::SolidBrush Whitebrush(Gdiplus::Color(255, 255, 255, 255)); // White brush, used to clear the screen (experiment)
double pctWinFill = 0.8;
int winHeight = 600, winWidth = 800; // these are the height and width of the main window; they are determinf using a GetWindowRect function on a passed HWND
int bdULX, bdULY; // these are the upper-left corner X & Y values for the overall board (these won't change once set)
int bdEdgeSize; // This is the edge length of the overall board; since the board is square, we need onlt one variable for both length and width.
int sqULX, sqULY; // these are the upper-left corner X & Y values for each board white/black square (these will change as the board is drawn)
int sqEdgeSize; // This is the edge length of the individual squares; again, since the board is square, we need only one variable here too.
int row=1; // this is a current the row (1 origin)
int col=1; // this is a current the col (1 origin)
RECT rect; // used the querry main window for actual height and width upon resize/redraw...
// Get the main window size using the past HWND
GetWindowRect(hwnd, &rect);
winHeight = (rect.bottom-rect.top);
winWidth = (rect.right-rect.left);
// The board must be kept square; so it's size is limited by the smaller of the height and width of the main window, multiplied by the percentage fill.
bdEdgeSize = (int)(pctWinFill * winHeight); // We use the height as default because it's the smaller of the two by default (as set in main window).
if (winHeight > winWidth) { // but, we will change to using the width, if the height turns out to be larger.
bdEdgeSize = (int)(pctWinFill * winWidth); // cast as int to suppress warning as we are multiplying an int by a float and assigning to an int.
}
//Calculate the largest square size we can use, then adjust board accordignly (this is done because the %fill of screen H&W may not divide evenly by 8.)
sqEdgeSize = bdEdgeSize / 8; // Get the largest square possible (!!!MAGIC NUMBER!!! <-AGAIN, CHANGE IN DISTRIBUTION)
bdEdgeSize = 8 * sqEdgeSize; // force the board(er) to match the squaresize array perfectly
// The first square always coincides with the ULX of the board, then changes thereafter as the board gets drawn
bdULX = (winWidth - bdEdgeSize) / 2; // set the bdULX of the board
bdULY = (winHeight - bdEdgeSize) / 2; // set the bdULY
// Draw the board using squares at 1/8th scale (!!!MAGIC NUMBER!!! <-AGAIN, CHANGE IN DISTRIBUTION)
for (sqULY = bdULY, row = 1; row <= 8; sqULY += sqEdgeSize, row += 1) {
for (sqULX=bdULX, col=1; col<=8; sqULX += sqEdgeSize, col+=1) {
if((row % 2) != (col % 2)) gf.FillRectangle(&Bluebrush, sqULX, sqULY, sqEdgeSize, sqEdgeSize);
}
}
// Drwa border for edge definition
gf.DrawRectangle(&Blackpen, bdULX, bdULY, bdEdgeSize, bdEdgeSize); // >>> MAY CHANGE Use filled rectangle to providing better edge apperance ???
return;
}
//<END - CODE>
//<BEGIN - VS BUILD MESSAGES>
This is build result:
Rebuild started...
1>------ Rebuild All started: Project: WinDraw_1, Configuration: Debug Win32 ------
1>ChessBoard.cpp
1>MainWin.cpp
1>Generating Code...
1>WinDraw_1.vcxproj -> C:\Users\solar3\Desktop\C++ VS Dev\Projects\WinDraw_1\WinDraw_1\Debug\WinDraw_1.exe
==========
Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========
//<END - VS BUILD MESSAGES>
//<BEGIN - RUN SAMPLE IMAGES>
Board looks OK when first drawn:
Moving/translating window is no problem; making smaller does not update at all (I guess because partial update region is out of scope(?); not sure):

What it looks like when resized larger by mouse click and drag (note residual artifact of smaller board and partial at rescaled size):
And after multiple resizings:
If window with artifacts is minimized and then restored, it repaints properly:
//<END - RUN SAMPLE IMAGES>
//<BEGIN - DEBUG OUTPUT MESSAGES>
This is the Debug Output up to Exit:
WinDraw_1.exe' (Win32): Loaded 'C:\Users\solar3\Desktop\C++ VS Dev\Projects\WinDraw_1\WinDraw_1\Debug\WinDraw_1.exe'. Symbols loaded.
'WinDraw_1.exe' (Win32): Loaded 'C:\Windows\SysWOW64\ntdll.dll'.
'WinDraw_1.exe' (Win32): Loaded 'C:\Windows\SysWOW64\kernel32.dll'.
'WinDraw_1.exe' (Win32): Loaded 'C:\Windows\SysWOW64\KernelBase.dll'.
'WinDraw_1.exe' (Win32): Loaded 'C:\Program Files\Norton Security\NortonData\22.21.6.53\Definitions\BASHDefs\20210913.004\UMEngx86.dll'.
'WinDraw_1.exe' (Win32): Loaded 'C:\Windows\winsxs\x86_microsoft.windows.gdiplus_6595b64144ccf1df_1.1.7601.24542_none_5c0717c7a00ddc6d\GdiPlus.dll'.
'WinDraw_1.exe' (Win32): Loaded 'C:\Windows\SysWOW64\msvcrt.dll'.
'WinDraw_1.exe' (Win32): Loaded 'C:\Windows\SysWOW64\user32.dll'.
'WinDraw_1.exe' (Win32): Loaded 'C:\Windows\SysWOW64\gdi32.dll'.
'WinDraw_1.exe' (Win32): Loaded 'C:\Windows\SysWOW64\lpk.dll'.
'WinDraw_1.exe' (Win32): Loaded 'C:\Windows\SysWOW64\usp10.dll'.
'WinDraw_1.exe' (Win32): Loaded 'C:\Windows\SysWOW64\advapi32.dll'.
'WinDraw_1.exe' (Win32): Loaded 'C:\Windows\SysWOW64\sechost.dll'.
'WinDraw_1.exe' (Win32): Loaded 'C:\Windows\SysWOW64\rpcrt4.dll'.
'WinDraw_1.exe' (Win32): Loaded 'C:\Windows\SysWOW64\sspicli.dll'.
'WinDraw_1.exe' (Win32): Loaded 'C:\Windows\SysWOW64\cryptbase.dll'.
'WinDraw_1.exe' (Win32): Loaded 'C:\Windows\SysWOW64\ole32.dll'.
'WinDraw_1.exe' (Win32): Loaded 'C:\Windows\SysWOW64\vcruntime140d.dll'.
'WinDraw_1.exe' (Win32): Loaded 'C:\Windows\SysWOW64\ucrtbased.dll'.
'WinDraw_1.exe' (Win32): Loaded 'C:\Windows\SysWOW64\api-ms-win-core-localization-l1-2-0.dll'.
'WinDraw_1.exe' (Win32): Loaded 'C:\Windows\SysWOW64\api-ms-win-core-processthreads-l1-1-1.dll'.
'WinDraw_1.exe' (Win32): Loaded 'C:\Windows\SysWOW64\api-ms-win-core-file-l1-2-0.dll'.
'WinDraw_1.exe' (Win32): Loaded 'C:\Windows\SysWOW64\api-ms-win-core-timezone-l1-1-0.dll'.
'WinDraw_1.exe' (Win32): Loaded 'C:\Windows\SysWOW64\api-ms-win-core-file-l2-1-0.dll'.
'WinDraw_1.exe' (Win32): Loaded 'C:\Windows\SysWOW64\api-ms-win-core-synch-l1-2-0.dll'.
'WinDraw_1.exe' (Win32): Loaded 'C:\Windows\SysWOW64\imm32.dll'.
'WinDraw_1.exe' (Win32): Loaded 'C:\Windows\SysWOW64\msctf.dll'.
'WinDraw_1.exe' (Win32): Loaded 'C:\Windows\Jaksta\AC\x86\jaudcap.dll'.
2780) CheckProcessInRegistry: Got include list but no match was found.
2780) IsProcessAllowed(C:\Users\solar3\Desktop\C++ VS Dev\Projects\WinDraw_1\WinDraw_1\Debug\WinDraw_1.exe) (80004005)
2780) DllMain(ProcDetach) [OK]
2780) DSound_Unhook
2780) MCIWave_Unhook
2780) AudioClient_Unhook
2780) CAudioStreamMgr::Shutdown
'WinDraw_1.exe' (Win32): Unloaded 'C:\Windows\Jaksta\AC\x86\jaudcap.dll'
'WinDraw_1.exe' (Win32): Loaded 'C:\Windows\SysWOW64\uxtheme.dll'.
'WinDraw_1.exe' (Win32): Loaded 'C:\Windows\SysWOW64\dwmapi.dll'.
'WinDraw_1.exe' (Win32): Loaded 'C:\Windows\SysWOW64\ole32.dll'.
'WinDraw_1.exe' (Win32): Unloaded 'C:\Windows\SysWOW64\ole32.dll'
The thread 0x25d0 has exited with code 1 (0x1).
The thread 0x2dbc has exited with code 0 (0x0).
The program '[10112] WinDraw_1.exe' has exited with code 0 (0x0).
//<END - DEBUG OUTPUT MESSAGES>
//=============================================================================================================