在我的WindowsManager.c文件中,我没有手动编辑*wm->actStkSize的值(!?),但是在RunMessageLoop函数中调用DispatchMessage(&msg);后,值不知何故从0变成了66,我完全不知道是怎么回事.

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);
    }
}

以下是输出:

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

拨打GetMessageW时超过wm->hwnd并不会改变任何事情.

推荐答案

在函数返回后,通过指针访问InitWindowManagerdocpg局部变量.到那个时候,变量的生命周期已经到期,导致undefined behavior.

要解决该问题,可以将wm->documentwm->document->page指向动态分配的内存,如下所示:

    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;

C++相关问答推荐

问关于C中的指针和数组

librsvg rsvg_handle_get_dimensions获取像素大小与浏览器中的渲染大小没有不同

理解没有返回语句的递归C函数的行为

C/C++中的状态库

C中出现分段错误后关闭文件

为什么我一直收到分段错误?

Ruby C Api处理异常

为什么该函数不将参数值保存到数据 struct 中?

将uintptr_t添加到指针是否对称?

限制不同类型的限定符

如何在VSCode中创建和使用我自己的C库?

链接器脚本和C程序使用相同的头文件,这可能吗?

生产者消费者计数器意外输出的C代码

C++中PUTS函数的返回值

如何在C宏定义中包含双引号?

如何在C中定义指向函数的指针并将该指针赋给函数?

如何在不更改格式说明符的情况下同时支持双精度和长双精度?

在文件描述符上设置FD_CLOEXEC与将其传递给POSIX_SPOWN_FILE_ACTIONS_ADCLOSE有区别吗?

WSASocket在哪里定义?

无法将字符串文字分配给 C 中的字符数组