Winapi 渲染到设备上下文时的资源管理(CDC/HDC)

Winapi 渲染到设备上下文时的资源管理(CDC/HDC),winapi,mfc,gdi,Winapi,Mfc,Gdi,我有一些关于在MFC中绘制笔划的问题。假设预先声明了类CStroke。示例代码如下所示 BOOL CStroke::DrawStroke(CDC* pDC) { CPen penStroke; if ( !penStroke.CreatePen(PS_SOLID, m_nPenWidth, m_color) ) return FALSE; CPen *pOldPen = pDC->SelectObject(&penStroke); p

我有一些关于在MFC中绘制笔划的问题。假设预先声明了类CStroke。示例代码如下所示

BOOL CStroke::DrawStroke(CDC* pDC)
{
    CPen penStroke;
    if ( !penStroke.CreatePen(PS_SOLID, m_nPenWidth, m_color) )
        return FALSE;
    CPen *pOldPen = pDC->SelectObject(&penStroke);
    pDC->MoveTo(m_pointArray[0]);

    for( int i = 0; i < m_pointArray.GetSize(); i++ )
    {
        pDC->LineTo(m_pointArray[i]);
    }

    pDC->SelectObject(pOldPen);
    return TRUE;
}
boolcstroke::DrawStroke(CDC*pDC)
{
CPen-penStroke;
如果(!penStroke.CreatePen(PS_实体、m_nPenWidth、m_颜色))
返回FALSE;
CPen*pOldPen=pDC->SelectObject(&penStroke);
pDC->MoveTo(m_pointArray[0]);
对于(int i=0;iLineTo(m_pointArray[i]);
}
pDC->选择对象(pOldPen);
返回TRUE;
}
我的问题是:

  • 为什么我需要波尔德本
  • 为什么我最终需要使用
    pDC->SelectObject(pOldPen)
    来选择pOldPen 简短答复:

  • 为什么我需要
    pOldPen

    因为你欠打电话的人的。这不是礼物

  • 为什么我最终需要使用
    pDC->SelectObject(pOldPen)
    来选择
    pOldPen

    因为在DC中选择另一个资源是从DC中选择当前资源的唯一方法


  • 当通过调用将GDI资源选择到DC中时,设备上下文代表您使用GDI资源。在任何时候,DC中每种类型(笔、画笔、位图等)都有一种被选中。但是,它不会为您管理资源。资源管理由应用程序负责

    不幸的是,上面的MFC实现隐藏了关于资源管理的一个重要细节。将代码转换为普通的WinAPI实现将使隐藏的内容更加明显:

    BOOL CStroke::DrawStroke(HDC hDC)
    {
        // Create a new pen resource
        HPEN penStroke = CreatePen(PS_SOLID, m_nPenWidth, m_color);
        if ( penStroke == NULL )
            return FALSE;
    
        // Select it into the device context
        HPEN oldPen = static_cast<HPEN>( SelectObject(hDC, &penStroke) );
    
        // Render strokes
        if ( m_pointArray.GetSize() > 0 )  // bugfix *
        {
            pDC->MoveTo(m_pointArray[0]);
    
            for( int i = 1; i < m_pointArray.GetSize(); i++ )  // bugfix **
            {
                pDC->LineTo(m_pointArray[i]);
            }
        }
    
        // Select pen out of DC
        HPEN penCreatedAbove = static_cast<HPEN>( SelectObject(hDC, oldPen) );
    
        // Clean up our resource (this is what CPen::~CPen() hides)
        DeleteObject(penCreatedAbove)
    
        return TRUE;
    }
    
    为完整起见,并将此实现与MFC代码对齐,以下是相关的MFC实现:

    CPen::CreatePen(int nPenStyle, int nWidth, COLORREF crColor)
    { return Attach(::CreatePen(nPenStyle, nWidth, crColor)); }
    
    CPen penStroke
    是一个自动变量,因此当控件离开封闭块时(即
    drawstrope
    返回时),它的析构函数运行。析构函数调用它的基类实现
    CGdiObject::DeleteObject
    ,如下所示:

    BOOL CGdiObject::DeleteObject()
    {
        if (m_hObject == NULL)
            return FALSE;
        return ::DeleteObject(Detach());
    }
    

    bugfix*不再访问空序列的第一个元素

    错误修复**第一个元素已用于
    MoveTo

    简短回答:

  • 为什么我需要
    pOldPen

    因为你欠打电话的人的。这不是礼物

  • 为什么我最终需要使用
    pDC->SelectObject(pOldPen)
    来选择
    pOldPen

    因为在DC中选择另一个资源是从DC中选择当前资源的唯一方法


  • 当通过调用将GDI资源选择到DC中时,设备上下文代表您使用GDI资源。在任何时候,DC中每种类型(笔、画笔、位图等)都有一种被选中。但是,它不会为您管理资源。资源管理由应用程序负责

    不幸的是,上面的MFC实现隐藏了关于资源管理的一个重要细节。将代码转换为普通的WinAPI实现将使隐藏的内容更加明显:

    BOOL CStroke::DrawStroke(HDC hDC)
    {
        // Create a new pen resource
        HPEN penStroke = CreatePen(PS_SOLID, m_nPenWidth, m_color);
        if ( penStroke == NULL )
            return FALSE;
    
        // Select it into the device context
        HPEN oldPen = static_cast<HPEN>( SelectObject(hDC, &penStroke) );
    
        // Render strokes
        if ( m_pointArray.GetSize() > 0 )  // bugfix *
        {
            pDC->MoveTo(m_pointArray[0]);
    
            for( int i = 1; i < m_pointArray.GetSize(); i++ )  // bugfix **
            {
                pDC->LineTo(m_pointArray[i]);
            }
        }
    
        // Select pen out of DC
        HPEN penCreatedAbove = static_cast<HPEN>( SelectObject(hDC, oldPen) );
    
        // Clean up our resource (this is what CPen::~CPen() hides)
        DeleteObject(penCreatedAbove)
    
        return TRUE;
    }
    
    为完整起见,并将此实现与MFC代码对齐,以下是相关的MFC实现:

    CPen::CreatePen(int nPenStyle, int nWidth, COLORREF crColor)
    { return Attach(::CreatePen(nPenStyle, nWidth, crColor)); }
    
    CPen penStroke
    是一个自动变量,因此当控件离开封闭块时(即
    drawstrope
    返回时),它的析构函数运行。析构函数调用它的基类实现
    CGdiObject::DeleteObject
    ,如下所示:

    BOOL CGdiObject::DeleteObject()
    {
        if (m_hObject == NULL)
            return FALSE;
        return ::DeleteObject(Detach());
    }
    

    bugfix*不再访问空序列的第一个元素


    错误修复**第一个元素已用于
    移动到

    非常简单:将笔更改回原来的状态。在绘图过程中笔是否更改了?是:-->penStroke.CreatePen(PS_SOLID,m_nPenWidth,m_color)因此,pOldPen记录penStroke替换的笔?完成后,需要将先前选择的资源重新选择到设备上下文中,以便进行适当的资源管理。考虑一个场景,其中<代码> cHe::拖拽是更复杂的渲染的一部分,并且调用<代码> DrawStroke < /CODE>的代码本身已经创建并选择了一个钢笔到设备上下文中。当
    DrawStroke
    返回时,调用代码需要能够管理其资源,因此它需要在设备上下文中选择相同的笔。非常简单:将笔更改回以前的状态。笔在绘图过程中是否更改了?是:-->penStroke.CreatePen(PS_SOLID,m_nPenWidth,m_color)因此,pOldPen记录penStroke替换的笔?完成后,需要将先前选择的资源重新选择到设备上下文中,以便进行适当的资源管理。考虑一个场景,其中<代码> cHe::拖拽是更复杂的渲染的一部分,并且调用<代码> DrawStroke < /CODE>的代码本身已经创建并选择了一个钢笔到设备上下文中。当
    drawstrope
    返回时,调用代码需要能够管理其资源,因此需要在设备上下文中选择相同的笔。