You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

处理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的结果,也验证了函数调用没有问题。

另外补充几个优化点:

  1. 代码中wc.cbClsExtra = sizeof(LONG_PTR);是为窗口类分配额外空间,和GWLP_USERDATA(窗口实例的用户数据)无关,当前场景下可以去掉,不影响逻辑。
  2. 记得在窗口销毁时释放malloc的内存,避免内存泄漏,可在WM_DESTROY分支中添加:
    LONG_PTR data = GetWindowLongPtr(hWnd, GWLP_USERDATA);
    if (data) free((void*)data);
    

内容的提问来源于stack exchange,提问作者jinreal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 20:39:19