[原创]关于CDC和CDCHandle [WTL]
今天写程序,试验ATL里面的CImage,结果是超乎寻常的令人满意。CImage比以前用的GdiPlus里面的CImage好用了很多,完全不是一个数量级的。这个结果更坚定了我使用COM和GDI而不是封装了的GDI+的决心。中途遇到个问题,就是在点击打开文档后,只是单纯地剪掉了图片大小的区域,并没有显示图片必须要拉伸窗口才能看见打开的图片……百思不得其解啊……之前好好的,我一使用WTL的DC类移植代码就出现问题了……天哪……难道我每次使用WTL都会有这样那样的问题吗……= = 是不是传说中的RP………………
没办法,排查。一个一个地查了以后发现有点地方有点猫腻,代码如下:
程序代码:
case WM_ERASEBKGND: { CDC DC((HDC)wParam); if (image.IsNull()) { CBrush OrgBrush=DC.SelectStockBrush(BLACK_BRUSH); DC.Rectangle(0,0,Win.cx,Win.cy); DC.SelectBrush(OrgBrush); } else { CRgn rb,rf; rf.CreateRectRgn(0,0,image.GetWidth(),image.GetHeight()); rb.CreateRectRgn(0,0,Win.cx,Win.cy); (rb,rf,RGN_DIFF); DC.FillRgn(rb,(HBRUSH)GetStockObject(BLACK_BRUSH)); } } break;首先WM_PAINT和图片都没有问题,因为图片毕竟能正常的显示出来。自然这里是重点检查对象了。OK,粗粗看来,似乎没有很大的问题。WM_ERASEBKGND在用背景色擦除窗口的时候发送到目标窗口。其中wParam参数为将要进行绘图的DC……慢着……DC?这个DC好像挺重要的,因为之后的WM_PAINT绘图操作使用的是同一个DC,会不会是这个的问题呢?难道WTL在台面地下做了什么让WM_PAINT抓狂的勾当?
之前看WTL的源代码(没办法啊,没有文档……只能一遍摸索一边用)对WTL独特的DC处理很好奇。WTL的DC模板声明如下:
程序代码:
template <bool t_bManaged> class CDCT { public: // Data members HDC m_hDC; // Other method... };嘿嘿,整个类只有一个成员,真是节省啊~~开始瞻仰WTL的设计者了,绝对是跟我一样的效率狂热分子,嘿嘿但是……额……那个t_bManaged是个什么东西?
然后看到DC的声明的时候就更不明白了……
typedef CDCT<false> CDCHandle; typedef CDCT<true> CDC;CDCHandle?有人听说过这种东西吗?……以前我没管,因为很懒,但是现在就是DC有重大嫌疑啊……怎么办……没办法,只好耐着性子去看CDCT的实现代码(万恶的WTL啊…………为什么没有文档……)最后翻得头昏眼花快要放弃的时候看到这么一段……
程序代码:
~CDCT() { if(t_bManaged && m_hDC != NULL) ::DeleteDC(Detach()); }这个这个……不是吧……如果t_bManaged是true的话,就会DeleteDC……嗯……DeleteDC啊……一下子反应过来了,原来是这样!这个bManaged其实是个管理参数,如果设置成true的话当对象析构的时候会自动地释放掉GDI资源,如果是false的话则只是单纯的使用,并不自动释放……这也就是CDCHandle和CDC的区别,前者只是当作一个Handle使用,而后者还肩负着自动释放资源的任务!而在wParam参数中被传进来的DC是要供WM_PAINT绘图使用的,如果被Delete掉了自然是什么都显示不出来啦,但是裁剪是正常的,刚刚好就是我遇到的情况!于是将CDC改为CDCHandle,问题解决~~
总结:遇到Bug以后不要慌张,首先排查找到最有可能出问题的地方,如果发现自己对这一领域很不了解就必须翻查文档以了解该处的工作机制,如果没有文档……嘿嘿,乖乖地去看源代码吧……
哎……这个程序还有一大堆功能没写完……看来今晚又要熬夜了…………- -|||
转载请注明地址:[url]http://hi.baidu.com/starwing/blog/item/09559b22cd04e2f0d7cae272.html[/url]