In my Window_manager.c file I nowhere edit the Value of *wm->actStkSize
by hand (!?), however after calling DispatchMessage(&msg);
in the RunMessageLoop
function, the Value somehow changed from 0 to 66, I have absolutely no idea how.
main.c
:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
WindowManager wm;
InitWindowManager(&wm);
printf("from main: %d %d\n", *wm.actBfrSize, *wm.actStkSize);
if (CreateAndShowWindow(&wm, hInstance, nCmdShow) != 0)
{
MessageBox(NULL, L"Failed to create window.", L"Error", MB_OK | MB_ICONERROR);
return 1;
}
int result = RunMessageLoop(&wm);
CleanupWindowManager(&wm);
return result;
}
Window_manager.c
:
#include "window_manager.h"
#include <stdio.h>
#include <windows.h>
#include <windowsx.h>
#include "config.h"
#include "graphics.h"
void InitWindowManager(WindowManager *wm) {
wm->hwnd = NULL;
wm->logFile = NULL;
Document doc;
Page pg;
RawPoint** stack = (RawPoint**)malloc(sizeof(RawPoint*));
RawPoint* buffer = (RawPoint*)malloc(SIZE_OF_BUFFER * sizeof(RawPoint));
*stack = buffer;
pg.rawStk = stack;
pg.rawBfrSize = 0;
pg.rawStkSize = 0;
doc.page = &pg;
wm->document = &doc;
wm->actBuffer = buffer;
wm->actPt = buffer;
wm->actBfrSize = &pg.rawBfrSize;
wm->actStkSize = &pg.rawStkSize;
// Initialize penData attributes
wm->penData.position.x = 0;
wm->penData.position.y = 0;
wm->penData.pressure = 0.0f;
wm->penData.azimuth = 0.0f;
wm->penData.altitude = 0.0f;
wm->penData.tiltX = 0.0f;
wm->penData.tiltY = 0.0f;
wm->penData.twist = 0.0f;
wm->penData.touching = FALSE;
wm->penData.buttonPressed = FALSE;
wcscpy_s(wm->displayText, MAX_TEXT_LENGTH, L"Pointer Events: None");
wcscpy_s(wm->logFileName, MAX_TEXT_LENGTH, L"logs/pen_pressure_log.txt");
// Open the log file for writing
_wfopen_s(&wm->logFile, wm->logFileName, L"w");
}
int CreateAndShowWindow(WindowManager *wm, HINSTANCE hInstance, int nCmdShow) {
// Register window class
// Register window class
WNDCLASSW wc = {}; // Note the use of WNDCLASSW for wide strings
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = L"MyWindowClass"; // Use wide-character string
if (RegisterClassW(&wc) == 0) {
// Handle registration failure
return 1;
}
// Create window
wm->hwnd = CreateWindowExW(0, L"MyWindowClass", L"My Window Title",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
500, 300, NULL, NULL, hInstance, wm);
HWND hButton = CreateWindowExW(0, L"BUTTON", L"redraw",
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
10, 50, 100, 30,
wm->hwnd, (HMENU)1001, GetModuleHandle(NULL), NULL);
if (wm->hwnd == NULL) {
return 1;
}
ShowWindow(wm->hwnd, nCmdShow);
return 0;
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
WindowManager *wm;
if (uMsg == WM_NCCREATE) {
// Retrieve the pointer to the WindowManager from the CREATESTRUCT
CREATESTRUCT *pCreate = (CREATESTRUCT *)lParam;
wm = (WindowManager *)pCreate->lpCreateParams;
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)wm);
wm->hwnd = hwnd;
printf("from ProcIf: %d %d\n", *(wm->actBfrSize), *(wm->actStkSize));
// printf("%s",wm->displayText);
// printf("if");
} else {
wm = (WindowManager *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
// printf("from ProcElse: %d %d\n", *(wm->actBfrSize), *(wm->actStkSize));
}
// printf("from Proc: %d %d\n", *(wm->actBfrSize), *(wm->actStkSize));
// printf("WindowPrc: %i\n", *wm->actStkSize);
switch (uMsg) {
case WM_CLOSE: {
printf("from WM_CLOSE: %d %d\n", *(wm->actBfrSize), *(wm->actStkSize));
DestroyWindow(hwnd);
break;
}
case WM_DESTROY: {
printf("from WM_DESTROY: %d %d\n", *(wm->actBfrSize), *(wm->actStkSize));
PostQuitMessage(0);
break;
}
case WM_POINTERDOWN: {
printf("from WM_POINTERDOWN: %d %d\n", *(wm->actBfrSize), *(wm->actStkSize));
wm->penData.touching = TRUE; // Pen is down
break;
}
case WM_POINTERUP: {
printf("from WM_POINTERDOWN: %d %d\n", *(wm->actBfrSize), *(wm->actStkSize));
wm->penData.touching = FALSE;
break;
}
case WM_POINTERUPDATE: {
printf("from WM_POINTERUPDATE: %d %d\n", *(wm->actBfrSize), *(wm->actStkSize));
// Handle pointer events
wm->penData.position.x = GET_X_LPARAM(lParam);
wm->penData.position.y = GET_Y_LPARAM(lParam);
ScreenToClient(wm->hwnd, &wm->penData.position);
wm->actPt->coords.x = wm->penData.position.x;
wm->actPt->coords.y = wm->penData.position.y;
wm->actPt->touching = wm->penData.touching;
wm->actPt->pressure = GET_POINTERID_WPARAM(wParam) / 5551.0f;
UpdateDisplay(wm);
InvalidateRect(hwnd, NULL, TRUE); // Request a redraw of the window
(*wm->actBfrSize)++;
if (*wm->actBfrSize == SIZE_OF_BUFFER) {
printf("Stoooooooooop!!!");
}
else {
// printf("actStkSize: %i\n", *(wm->actStkSize));
wm->actPt++;
}
break;
}
case WM_SIZE: {
printf("from WM_SIZE: %d %d\n", *(wm->actBfrSize), *(wm->actStkSize));
Do Some Stuff
break;}
case WM_PAINT: {
printf("from WM_PAINT: %d %d\n", *(wm->actBfrSize), *(wm->actStkSize));
// Do some Stuff
break;}
case WM_COMMAND: {
printf("from WM_COMMAND: %d %d\n", *(wm->actBfrSize), *(wm->actStkSize));
//Do some Stuff
}
default: {
// printf("from default: %d %d\n", *(wm->actBfrSize), *(wm->actStkSize));
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
return 0;
}
int RunMessageLoop(WindowManager *wm) {
MSG msg;
while (GetMessageW(&msg, NULL, 0, 0))
{
printf("from beginLoop: %d %d\n", *(wm->actBfrSize), *(wm->actStkSize));
TranslateMessage(&msg);
printf("from midLoop: %d %d\n", *(wm->actBfrSize), *(wm->actStkSize));
DispatchMessage(&msg);
printf("from endLoop: %d %d\n", *(wm->actBfrSize), *(wm->actStkSize));
}
return (int)msg.wParam;
}
void CleanupWindowManager(WindowManager *wm) {
// Close the log file if it's open
if (wm->logFile != NULL) {
fclose(wm->logFile);
}
}
This is the output:
from main: 0 0
from ProcIf: 0 0
from WM_SIZE: 0 0
from beginLoop: 0 0
from midLoop: 0 0
from endLoop: 0 66
from beginLoop: 0 66
from midLoop: 0 66
from endLoop: 0 66
Passing wm->hwnd
when calling GetMessageW
doesn't change anything.
The doc
and pg
local variables of InitWindowManager
are being accessed via pointers after the function returns. The lifetime of the variables has already expired by that point, leading to undefined behavior.
To fix the problem, wm->document
and wm->document->page
can be pointed to dynamically allocated memory as follows:
Document* doc = malloc(sizeof(*doc));
Page* pg = malloc(sizeof(*pg));
RawPoint** stack = (RawPoint**)malloc(sizeof(RawPoint*));
RawPoint* buffer = (RawPoint*)malloc(SIZE_OF_BUFFER * sizeof(RawPoint));
*stack = buffer;
pg->rawStk = stack;
pg->rawBfrSize = 0;
pg->rawStkSize = 0;
doc->page = pg;
wm->document = doc;
wm->actBuffer = buffer;
wm->actPt = buffer;
wm->actBfrSize = &pg->rawBfrSize;
wm->actStkSize = &pg->rawStkSize;