用ATL和MFC来创建ActiveX控件应该使用哪个框架
为控件添加功能代码
MFC和ATL在功能代码的处理上是相似的。在每一个框架里,实现控件的类具有一个名为OnDraw的虚函数。你只需将你的功能代码添加到OnDraw函数里。然而,在各框架里,OnDraw函数得工作有所不同。
MFC的OnDraw在两种上下文中调用。第一个上下文发生在控件响应一个WM_PAINT消息时。此时,传递给OnDraw函数的设备上下文是实际的设备上下文。如果控件正被要求绘制它自己作为对客户调用IViewObjectEx::Draw的响应,则设备上下文或者是一个元文件设备上下文,或者是一个常规设备上下文。下面的代码说明了基于MFC的控件是怎样被绘制的:
void CMFCMsgTrafficCtrl::OnDraw(CDC* pdc, const CRect& rcBounds,
const CRect& rcInvalid)
{
// TODO: 在下面加入自己的绘图代码
pdc->FillRect(rcBounds,
CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));
ShowGraph(*pdc, const_cast<CRect&>(rcBounds), nMessagesToShow);
}
COleControl::OnDraw的签名包括一个代表控件大小的矩形和一个代表控件无效区域的矩形。当响应WM_PAINT消息时,MFC调用控件的OnDraw函数。此时,OnDraw函数接受一个实际的设备上下文来绘图。当通过IViewObject::Draw来响应一个调用时,MFC也要调用控件的OnDraw函数。MFC的实现调用COleControl::OnDrawMetafile,并且它的缺省OnDrawMetafile调用COleControl::OnDraw。当然,这暗示了控件的实时绘制是和设计时与容器一起存储的控件图元文件表示法相同。你可以让控件的实时绘制模样与设计时的绘制模样不同,这通过重载COleControl::OnDrawMetafile来实现。通过调用你的控件的InvalidateControl方法,你可以强制进行一次重绘。
ATL的绘制机制非常类似于MFC。CComControlBase::OnPaint建立一个ATL_DRAWINFO结构,包括创建一个绘图设备上下文。然后ATL调用控件的OnDrawAdvanced函数。OnDrawAdvanced生成元文件,接着调用自己控件的OnDraw方法,它使用ATL_DRAWINFO结构中的信息来了解如何在屏幕上绘图。下面是ATL_DRAWINFO结构:
[cpp] view plain copy
struct ATL_DRAWINFO
{
UINT cbSize;
DWORD dwDrawAspect;
LONG lindex;
DVTARGETDEVICE* ptd;
HDC hicTargetDev;
HDC hdcDraw;
LPCRECTL prcBounds; //在这个矩形中绘图
LPCRECTL prcWBounds; //WindowOrg and Ext if metafile
BOOL bOptimize;
BOOL bZoomed;
BOOL bRectInHimetric;
SIZEL ZoomNum; //ZoomX = ZoomNum.cx/ZoomNum.cy
SIZEL ZoomDen;
};
ATL为你填写此结构。当你正在屏幕上绘图时,你所感兴趣的最重要的域是hdcDraw 和 prcBounds。如果你对在一个元文件里绘图感兴趣,或者你需要注意缩放因子等等,那么其它域也是重要的。下面的代码显示了基于ATL的消息流控件是怎样处理绘图的:
[cpp] view plain copy
HRESULT CATLMsgTrafficCtl::OnDraw(ATL_DRAWINFO& di)
{
RECT& rc = *(RECT*)di.prcBounds;
HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255));
FillRect(di.hdcDraw, &rc, hBrush);
DeleteObject(hBrush);
Rectangle(di.hdcDraw, rc.left, rc.top, rc.right, rc.bottom);
ShowGraph(di.hdcDraw, rc, nMessagesToShow);
return S_OK;
}
注意当你使用ATL的时候,设备和GDI句柄你都必须处理。在ATL中,你调用控件的FireViewChange函数来强制控件的一次重画。