Window消息循环中*wm->actStkSize意外变为66的问题求助
问题:未手动修改的
*wm->actStkSize值在DispatchMessage后莫名变为66 我在Window_manager.c文件中从未手动修改*wm->actStkSize的值,但在RunMessageLoop函数调用DispatchMessage(&msg)后,该值从0变为66,完全不清楚原因。调用GetMessageW时传入wm->hwnd也无法改变这一现象。
相关代码
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 WNDCLASSW wc = {}; wc.lpfnWndProc = WindowProc; wc.hInstance = hInstance; wc.lpszClassName = L"MyWindowClass"; if (RegisterClassW(&wc) == 0) { 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) { 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)); } else { wm = (WindowManager *)GetWindowLongPtr(hwnd, GWLP_USERDATA); } 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; 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)); 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); (*wm->actBfrSize)++; if (*wm->actBfrSize == SIZE_OF_BUFFER) { printf("Stoooooooooop!!!"); } else { 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)); break;} case WM_COMMAND: { printf("from WM_COMMAND: %d %d\n", *(wm->actBfrSize), *(wm->actStkSize)); } default: { 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) { if (wm->logFile != NULL) { fclose(wm->logFile); } }
程序输出
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
问题原因与解决方案
原因分析
问题出在InitWindowManager函数中的局部变量生命周期:
- 函数内定义的
Document doc和Page pg是栈上的局部变量,当InitWindowManager执行完毕返回后,这些变量占用的栈内存会被系统回收并可能被后续函数调用(比如消息循环相关的系统函数)覆盖。 wm->actStkSize指向的是pg.rawStkSize的地址,也就是这块已经失效的栈内存地址,后续任何对栈内存的操作都会导致该地址的值被意外修改,这就是为什么*wm->actStkSize会莫名变成66。
解决方案
有两种常见修复方式:
动态分配内存:将
Document和Page改为堆内存分配,确保它们的生命周期覆盖整个程序运行过程:void InitWindowManager(WindowManager *wm) { // ... 其他初始化代码 ... Document* doc = (Document*)malloc(sizeof(Document)); Page* pg = (Page*)malloc(sizeof(Page)); 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->actBfrSize = &pg->rawBfrSize; wm->actStkSize = &pg->rawStkSize; // ... 其他初始化代码 ... }注意:需要在
CleanupWindowManager中添加对应的内存释放逻辑,避免内存泄漏。调整变量作用域:将
Document和Page作为WindowManager结构体的成员变量,或者放在全局作用域,确保它们的生命周期不早于wm变量。
内容的提问来源于stack exchange,提问作者flotschi
相关产品推荐
相关产品推荐

