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

为何代码触发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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 14:34:53