处理WM_CREATE消息时SetWindowLongPtr为何始终返回0?
Win32编程中SetWindowLongPtr返回0的问题解析
我是Win32编程新手,在处理WM_CREATE消息的代码块中调用SetWindowLongPtr,但该函数始终返回0。程序逻辑简单,是否有遗漏的地方?
代码示例
#include <stdio.h> #include <windows.h> #ifdef _WIN64 #define SET_WINDOW_LONG_PTR SetWindowLongPtr #else #define SET_WINDOW_LONG_PTR SetWindowLong #endif LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); int main(int argc, char *argv[]) { HINSTANCE hInstance = GetModuleHandle(NULL); WNDCLASS wc = {0}; wc.lpfnWndProc = WndProc; wc.hInstance = hInstance; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.lpszClassName = L"MyWindowClass"; wc.cbClsExtra = sizeof(LONG_PTR); if (!RegisterClass(&wc)) { // Handle error... } HWND hWnd = CreateWindow(L"MyWindowClass", L"My Window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); if (!hWnd) { // Handle error... } ShowWindow(hWnd, SW_SHOWNORMAL); MSG msg = {0}; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } } LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_CREATE: LONG_PTR MYDATA = (LONG_PTR)malloc(sizeof(int)); int result = SetWindowLongPtr(hWnd, GWLP_USERDATA, MYDATA); // int result = SetWindowLongPtr (hWnd, DWLP_USER, MYDATA); //this won't work either // result is zero break; case WM_DESTROY: PostQuitMessage(0); break; } return DefWindowProc(hWnd, message, wParam, lParam); }
编译命令
gcc main.c -o test.exe -mwindows -lcomctl32
已尝试操作
- 使用DWLP_USER替代GWLP_USERDATA;
- 使用平台特定的SET_WINDOW_LONG_PTR宏替代SetWindowLongPtr;
更新信息
按照建议调用SetLastError(0)后再用GetLastError获取错误码,结果返回0,说明SetWindowLongPtr的使用似乎没有问题,但官方文档中“如果函数失败,返回值为0”的描述让人困惑。
问题解析
SetWindowLongPtr返回0不一定代表调用失败,官方文档的完整逻辑是:
- 函数成功时,返回值是指定位置的旧值;
- 函数失败时返回0,但此时
GetLastError会返回非0的错误码。
在WM_CREATE消息阶段,窗口刚创建完成,GWLP_USERDATA的初始值就是0,所以第一次调用SetWindowLongPtr设置这个值时,返回的旧值自然是0,这属于完全正常的情况,不是错误。你通过GetLastError得到0的结果,也验证了函数调用没有问题。
另外补充几个优化点:
- 代码中
wc.cbClsExtra = sizeof(LONG_PTR);是为窗口类分配额外空间,和GWLP_USERDATA(窗口实例的用户数据)无关,当前场景下可以去掉,不影响逻辑。 - 记得在窗口销毁时释放malloc的内存,避免内存泄漏,可在WM_DESTROY分支中添加:
LONG_PTR data = GetWindowLongPtr(hWnd, GWLP_USERDATA); if (data) free((void*)data);
内容的提问来源于stack exchange,提问作者jinreal
相关产品推荐
相关产品推荐

