为何代码触发CStatic控件非窗口断言失败?非模态对话框图片切换问题
MFC非模态对话框切换CStatic图片触发断言失败问题
问题场景
在主对话框中嵌入非模态许可证对话框,该对话框包含一个CStatic控件。初始加载默认图片时无断言失败,图片正常显示;但在鼠标事件中切换图片时,触发::IsWindow(m_hWnd)断言失败。
初始加载图片代码
void License::LoadPngPicturesFromResources(UINT defaultPictureId, UINT pictureWithHoveredLicenseId) { ASSERT(defaultPictureId); m_pictureControl = static_cast<CStatic*>(GetDlgItem(IDC_LICENSE)); ASSERT(m_pictureControl); m_pictureControl->ModifyStyle(SS_TYPEMASK, SS_BITMAP | SS_CENTERIMAGE | SS_REALSIZECONTROL); CRect rect; m_pictureControl->GetClientRect(rect); bool success = GraphicsUtils::LoadScaledPng(m_defaultPicture, defaultPictureId, rect); ASSERT(success); m_pictureControl->SetBitmap(m_defaultPicture); success = GraphicsUtils::LoadScaledPng(m_pictureWithHoveredLicense, pictureWithHoveredLicenseId, rect); ASSERT(success); }
断言失败触发位置
断言失败发生在MFC内联函数中:
_AFXWIN_INLINE HBITMAP CStatic::SetBitmap(HBITMAP hBitmap) { ASSERT(::IsWindow(m_hWnd)); return (HBITMAP)::SendMessage(m_hWnd, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hBitmap); }
鼠标事件切换图片代码
void License::OnMouseMove(UINT flags, CPoint point) { ASSERT(m_pictureControl); if (GraphicsUtils::PointIsInsideRect(point, m_licenseRect)) { if (!m_hoveredStateSet) { m_pictureControl->SetBitmap(m_pictureWithHoveredLicense); // 断言失败处 m_state = State::License; } } else { m_state = State::Default; } }
License类定义
class License : public Fragment { public: enum class State : uint8_t { Default, License }; License(CWnd* parent, UINT templateId); void SetLicenseUrl(const TString& url); void SetLicenseRect(const CRect& rect); void LoadPngPicturesFromResources(UINT defaultPictureId, UINT pictureWithHoveredLicenseId = 0); protected: DECLARE_DYNAMIC(License) DECLARE_MESSAGE_MAP() void OnLButtonUp(UINT flags, CPoint point); BOOL OnSetCursor(CWnd* wnd, UINT hitTest, UINT message); void OnMouseMove(UINT flags, CPoint point); private: CStatic* m_pictureControl = nullptr; TString m_licenseUrl; CRect m_licenseRect; CImage m_defaultPicture; CImage m_pictureWithHoveredLicense; bool m_hoveredStateSet = false; State m_state = State::Default; };
问题定位与优化方向
经排查,问题根源在于存储了GetDlgItem的返回值。GetDlgItem返回的临时CWnd指针可能在窗口生命周期内失效,后续访问时对应的窗口句柄已无效,导致IsWindow断言失败。
后续可采用DDX机制绑定控件,避免直接存储GetDlgItem返回的指针,同时可参考《Avoiding GetDlgItem》相关内容优化控件访问方式。
内容的提问来源于stack exchange,提问作者qloq
相关产品推荐
相关产品推荐

