MFC 应用程序中 AFX_WM_DRAW2D 和 WM_PAINT 之间的关系

Relationship between AFX_WM_DRAW2D and WM_PAINT in MFC Application

主题中的两条消息有什么关系?正是在 AFX_WM_DRAW2D 传递到应用程序队列时。

我问是因为我遇到了最奇怪的 AFX_WM_DRAW2D 处理程序递归调用。每当我试图在 AFX_WM_DRAW2Din compatibe 渲染目标中绘制某些东西时,处理程序就会以某种方式递归调用,我很难解释。 MFC应用程序的结构是这样的:-

BEGIN_MESSAGE_MAP(CTACSIView, CView)
    // Standard printing commands
    ...
    ON_REGISTERED_MESSAGE(AFX_WM_DRAW2D, &CTACSIView::OnDraw2D)
END_MESSAGE_MAP()


afx_msg LRESULT CTACSIView::OnDraw2D(WPARAM wParam, LPARAM lParam)
{

    CHwndRenderTarget* pRenderTarget = (CHwndRenderTarget*)lParam;
    ASSERT_VALID(pRenderTarget);


    CRect clientRect;
    GetClientRect(clientRect);

    if (m_BackGroundHasChanged)
    {


        CBitmapRenderTarget compatibleRenderTarget;
        pRenderTarget->CreateCompatibleRenderTarget(compatibleRenderTarget, m_viewScreenSize);

        compatibleRenderTarget.BeginDraw();


        // 
        // ----> HERE THE RECURSIVE CALL OCCURS <----
        //
            D2D1::Matrix3x2F shiftRightTranslation = D2D1::Matrix3x2F::Translation(D2D1::SizeF(TACSI_VIEW_BATTLE_FIELD_OFFSET_X, 0));
    m_pRulerBitmapBrush_X.SetTransform(&shiftRightTranslation);

    compatibleRenderTarget.FillRectangle(rulerRectangle_X, &m_pRulerBitmapBrush_X);

MFC 在内部处理 WM_PAINT 消息(查看 CWnd::OnWndMsg 源代码)并尝试进行 D2D 绘制(调用受保护的 CWnd::DoD2DPaint() 方法)。此方法检查是否为 window(方法 CWnd::EnableD2DSupport)启用了 D2D,并为此 window 发送内部 MFC 消息 AFX_WM_DRAW2D。

因此,如果您在代码中处理 AFX_WM_DRAW2D,则 CWnd::DoD2DPaint() returns 为真,进一步处理 WM_PAINT 将被阻止。如果 AFX_WM_DRAW2D 未处理或 D2D 不受 OS 支持或未启用,则标准 WM_PAIT 算法正在运行。

P.S.: MFC 12 仅包含 D2D 1.0 支持,不包含 D2D 1.1 或 D2D 1.2! 因为 D2D 1.x 需要完整的 Direct3D 初始化作为 D2D 的地下层,因此很难在 MFC 中为它们编写通用代码。

P.P.S.: 如果你的APP执行打印throw MFC那么会调用viewer的OnDraw方法。这是因为 D2D 渲染器不支持绘制到打印机上下文。 任何打印的 D2D 应用程序都必须实现两种方法:用于打印的 OnDraw() 和用于在屏幕上绘制的旧 OS(不支持 D2D)和 AFX_WM_DRAW2D 处理。