SetWindowLongPtr调用失败但GetLastError与errno均为0的问题排查
解决SetWindowLongPtr返回0但无错误码的调试问题
核心错误:错误的调用成功判断逻辑
你当前判断SetWindowLongPtr失败的方式完全错误。该函数的返回值是之前存储在GWLP_USERDATA中的值,如果之前没有设置过,返回0是正常情况,不代表调用失败。正确的判断逻辑应该是:调用函数后,若GetLastError()返回非0值,才说明调用失败。你代码里把返回值当作BOOL处理是完全错误的,因为返回值是LONG_PTR类型,不是布尔值。
64位平台的指针截断问题
你用PtrToUlong(pSimpleText_)转换指针,在64位系统下会导致指针被截断(Ulong是32位类型),这会导致后续GetWindowLongPtr拿到无效的指针值,进而引发访问违规。正确的做法是直接将指针转换为LONG_PTR类型,因为SetWindowLongPtr的第三个参数就是LONG_PTR:
LONG_PTR prevValue = ::SetWindowLongPtr( hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pSimpleText_) ); // 判断失败的正确方式 if (prevValue == 0 && GetLastError() != 0) { // 真正的失败处理逻辑 }
关于WM_CREATE未触发的问题
WM_NCCREATE返回1(TRUE)后,系统会正常发送WM_CREATE消息,你没捕获到可能是调试断点设置有误,或者窗口创建流程中其他环节出了问题,但这不是当前崩溃的核心原因。
UIPI权限问题可以排除
你提到的UIPI权限限制是针对跨进程操作的,同一个进程内的窗口和线程不存在权限高低的问题,所以这个因素和你的问题无关。
修复后的WndProc关键部分示例
LRESULT CALLBACK SimpleText::WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { if (message == WM_NCCREATE) { LPCREATESTRUCT pcs = reinterpret_cast<LPCREATESTRUCT>(lParam); SimpleText* pSimpleText_ = reinterpret_cast<SimpleText*>(pcs->lpCreateParams); SetLastError(0); LONG_PTR prevValue = ::SetWindowLongPtr( hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pSimpleText_) ); // 正确的失败判断:只有当返回0且GetLastError非0时才是失败 if (prevValue == 0 && GetLastError() != 0) { DWORD dwError = GetLastError(); // 这里处理真正的错误 } return TRUE; // 返回TRUE让系统继续发送WM_CREATE等消息 } SimpleText* pSimpleText = reinterpret_cast<SimpleText*>( ::GetWindowLongPtr(hwnd, GWLP_USERDATA)); if (pSimpleText) { switch (message) { case WM_SIZE: { UINT width = LOWORD(lParam); UINT height = HIWORD(lParam); if(pSimpleText->pRT_ != nullptr) pSimpleText->OnResize(width, height); break; } // 其他消息处理... } } return DefWindowProc(hwnd, message, wParam, lParam); }
额外建议
- 始终在64位项目中使用
LONG_PTR/WPARAM/LPARAM这类宽度自适应的类型存储指针,避免截断问题。 - 查阅Windows API文档时,务必注意函数的返回值类型和错误判断方式,不要想当然地把返回值当作布尔值。
内容的提问来源于stack exchange,提问作者Emre Tekmen
相关产品推荐
相关产品推荐

