最近我正在学习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 上遇到的第一个问题,所以如果您有任何关于如何提出更好问题的建议,我很乐意学习。
提前感谢大家!
问题在于如何为 STATEINFO 结构分配内存以及如何处理指针。
#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);
}