使用 WinApi 访问 C 结构中的第一个字段后出现问题

问题描述 投票:0回答:1

最近我正在学习C语言的Win32 API,我正在遵循微软网站上的标准教程(这个)。

在尝试实现教程所教的内容时,我在访问自定义字段时遇到了问题

STATEINFO
struct,特别是每次我尝试访问不是
WindowProcess
函数中结构声明中的第一个字段时,我的程序编译没有问题,但在运行时它崩溃并出现错误 0xC000041D。作为参考,我的编译器是 MinGW,我的 IDE 是 CodeBlocks。我尝试过调试,但我无法理解这个奇怪的错误,我从未想过在第一个错误之后我无法访问任何字段。

这是我的代码的简化版本:

#include <stdlib.h>
#include <stdio.h>
#include <windows.h>

LRESULT CALLBACK WindowProcess(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

typedef struct {UINT lastMessage1; UINT lastMessage2;} STATEINFO;

STATEINFO* GetAppState(HWND hwnd);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pCmdLine, int nCmdShow) {
    // creating the window class
    const wchar_t WindowClassName[] = L"Test Window";

    WNDCLASS wc = {};
    wc.lpfnWndProc      = WindowProcess;
    wc.hInstance        = hInstance;
    wc.lpszClassName    = WindowClassName;

    RegisterClass(&wc);

    STATEINFO stateInfo = {}, *pStateInfo = &stateInfo;

    // creating the window instance
    HWND hwnd = CreateWindowEx(
        0, WindowClassName, "Window Title", WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
        NULL, NULL, hInstance, pStateInfo);
    ShowWindow(hwnd, nCmdShow);

    // starting the message loop of the window
    MSG msg = {};
    while (GetMessage(&msg, NULL, 0, 0) > 0) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}

LRESULT CALLBACK WindowProcess(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {

    STATEINFO *pStateInfo = malloc(sizeof(STATEINFO*));

    if (uMsg == WM_CREATE) {
        pStateInfo = (STATEINFO*)(*((CREATESTRUCT*)(lParam))).lpCreateParams;
        SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pStateInfo);
    } else {
        pStateInfo = GetAppState(hwnd);
    }
    switch (uMsg) {
        case WM_CLOSE: {
            DestroyWindow(hwnd);
            return 0;
        }
        case WM_DESTROY: {
            PostQuitMessage(0);
            return 0;
        }
        break;
    }
    // here is the problem:
    pStateInfo->lastMessage1 = 1; // this is fine
    pStateInfo->lastMessage2 = 1; // this is NOT fine, if this line is present the program crashes
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

STATEINFO* GetAppState(HWND hwnd)
{
    LONG_PTR ptr = GetWindowLongPtr(hwnd, GWLP_USERDATA);
    STATEINFO *pStateInfo = (STATEINFO*)(ptr);
    return pStateInfo;
}

每当我尝试写入

STATEINFO
结构中的第二个元素时,问题就会出现,也许这是与从
void*
STATEINFO*
的指针类型转换相关的某种类型的错误?我已经尝试过调试,但似乎唯一使代码崩溃的就是该行

pStateInfo->lastMessage2 = 1;

访问该字段不会导致问题,但用它解析表达式会导致问题。

我不知道为什么,并且在 Windows 教程或本网站的其他问题中找不到任何有用的调试。

如果有人有任何建议来解决这个问题,我愿意从回复中学习一切,如果需要任何其他信息,我很乐意在评论中提供更多信息。

请记住,我不是一个经验丰富的程序员,尤其是我只是想了解的 Win32 API,并且我可能会错过 C 理论的某些方面。此外,这是我在 StackOverflow 上遇到的第一个问题,所以如果您有任何关于如何提出更好问题的建议,我很乐意学习。

提前感谢大家!

c pointers winapi struct
1个回答
0
投票

问题在于如何为 STATEINFO 结构分配内存以及如何处理指针。

  1. 您为指向 STATEINFO 的指针分配内存,而不是分配 实际 STATEINFO 结构的内存。这会导致未定义 访问结构体字段时的行为。
  2. 您正确设置和检索 GWLP_USERDATA 来存储和 检索指向 STATEINFO 结构的指针?!
  3. 处理WM_CREATE消息时STATEINFO的内存并存储 使用 SetWindowLongPtr 的指针???
  4. 避免窗口销毁时内存泄漏!!!???
#include <stdlib.h>
#include <stdio.h>
#include <windows.h>

LRESULT CALLBACK WindowProcess(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

typedef struct {
    UINT lastMessage1;
    UINT lastMessage2;
} STATEINFO;

STATEINFO* GetAppState(HWND hwnd);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pCmdLine, int nCmdShow) {
    // creating the window class
    const wchar_t WindowClassName[] = L"Test Window";

    WNDCLASS wc = {};
    wc.lpfnWndProc      = WindowProcess;
    wc.hInstance        = hInstance;
    wc.lpszClassName    = WindowClassName;

    RegisterClass(&wc);

    STATEINFO stateInfo = {}, *pStateInfo = &stateInfo;

    // creating the window instance
    HWND hwnd = CreateWindowEx(
        0, WindowClassName, L"Window Title", WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
        NULL, NULL, hInstance, pStateInfo);
    ShowWindow(hwnd, nCmdShow);

    // starting the message loop of the window
    MSG msg = {};
    while (GetMessage(&msg, NULL, 0, 0) > 0) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}

LRESULT CALLBACK WindowProcess(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    STATEINFO *pStateInfo = NULL;

    if (uMsg == WM_CREATE) {
        CREATESTRUCT *pCreate = (CREATESTRUCT*)lParam;
        pStateInfo = (STATEINFO*)pCreate->lpCreateParams;
        SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pStateInfo);
    } else {
        pStateInfo = GetAppState(hwnd);
    }

    if (pStateInfo != NULL) {
        switch (uMsg) {
            case WM_CLOSE:
                DestroyWindow(hwnd);
                return 0;

            case WM_DESTROY:
                PostQuitMessage(0);
                return 0;

            default:
                // This is where you update the state info
                pStateInfo->lastMessage1 = 1; // This is fine
                pStateInfo->lastMessage2 = 1; // This should now be fine
                break;
        }
    }

    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

STATEINFO* GetAppState(HWND hwnd) {
    return (STATEINFO*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
}
© www.soinside.com 2019 - 2024. All rights reserved.