Category Archives: C++ Dev

走近WTL--GDI篇

WTL中的GDI类的封装与MFC不同,对于这些类的详细描述,可以参见WTL for MFC Programmers, Part IX – GDI Classes, Common Dialogs, and Utility Classes.
在由MFC的GDI向WTL的GDI转换过程中,有以下几个问题需要注意的:

一、OnPaint函数的处理。
在OnPaint函数的声明中,有以下的两种方法:

1
2
3
4
5
6
BEGIN_MSG_MAP_EX(MyWnd)
....
MESSAGE_HANDLER(WM_PAINT, OnPaint)
...
END_MSG_MAP()
LRESULT OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);

或者是:

1
2
3
4
5
6
BEGIN_MSG_MAP_EX(MyWnd)
....
MSG_WM_PAINT(OnPaint)
...
END_MSG_MAP()
LRESULT OnPaint(HDC hdc)

实际上,这两种写法在使用中区别不大,第一种传入的四个参数都不会用到,第二种传入的hdc的值是NULL,所以这些参数都是不可以被OnPaint函数使用。那么在OnPaint中如何开始绘图呢?我们可以使用CPaintDC,如下:

1
2
3
4
5
6
LRESULT HexxagonWnd::OnPaint(HDC hdc)
{
    CPaintDC    pDC(m_hWnd);
    CDCHandle  dc(pDC.m_hDC);
...
}

这样,我们就可以方便的使用CDCHandle了。这篇文章也对这个问题做了一定的说明,大家可以参考一下:WTL7.0的一个BUG

二、如何创建双缓冲
在WTL中CDC类被CDCHandle取代,其中对CBitmap的一些操作也有了变化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
CRect lcrcClient;
GetClientRect(&lcrcClient);
CDCHandle MemDC; //首先定义一个显示设备对象
CBitmap MemBitmap;//定义一个位图对象
MemDC.CreateCompatibleDC(NULL);
MemBitmap.CreateCompatibleBitmap(dc,lcrcClient.Width(),lcrcClient.Height());
HBITMAP pOldBit=MemDC.SelectBitmap((HBITMAP)MemBitmap);
 
//使用MemDC绘制一些图像
....
 
dc.BitBlt(lcrcClient.left, lcrcClient.top, 
    lcrcClient.Width(), lcrcClient.Height(), 
    MemDC, lcrcClient.left, lcrcClient.top, SRCCOPY);
 
//绘图完成后的清理
MemBitmap.DeleteObject();
MemDC.DeleteDC();

三、SelectObject函数的变化
WTL的几个select函数都是直接使用对应类型的GDI对象,并且传入参数为HPEN、HBRUSH等类型,如下所示:

1
2
3
HPEN SelectPen(HPEN nPen)
HBRUSH SelectBrush(HBRUSH nBrush)
HFONT SelectFont(HFONT nFont)

一般的CPen等可以通过HPEN操作符直接从CPen转换出HPEN对象,所以保存、恢复GDI对象的代码要做如下改变:

1
2
3
4
5
CPen lcPen;
lcPen.CreatePen(PS_SOLID, 1, gColorGreen);
HPEN lcpOldPen = dc.SelectPen((HPEN)lcPen);
 
dc.SelectPen((HPEN)lcpOldPen);

当然,WTL的GDI与MFC还有一些其他的不同,大家使用时应注意。

Posted in C++ Dev | Tagged , , | Leave a comment

COM组件调试手记

程序调试是一个优秀程序员的必备品质。这几天正好在调试一个十分郁闷的大型项目,涉及COM组件,DLL调用等方面的知识,拿出来和大家分享一下吧。

一、项目环境
1.这种调试方法适用于VS2003平台。在其他如VS2005,VS2008等也应该适用,但并未测试。
2.项目的基本结构为:两个独立的工程,一个为COM接口的调用者,我们称为Master工程;另一个为COM接口的实现部分,为一个DLL,我们暂且称为ComImpl.

二、调试前提
1.必须拥有Master和ComImpl工程的源代码。
2.将由源码生成的exe、dll、pdb文件等必须要在同一文件夹下。
3.将VS2003加入到DEP保护的排除列表中,这一步十分重要,否则一旦开始调试,VS2003的IDE就会挂掉。

三、调试步骤
1.使用VS2003打开Master工程,在调用COM接口的代码处地方设置断点,启动调试。
2.等程序在调用COM接口的代码处被中断时,打开VS2003的Debug菜单下Processes对话框,attach到Dllhost.exe,关闭对话框。
3.在Master工程中打开ComImpl工程的源码,设置断点。
4.按F5或F10执行,直到ComImpl中的断点被捕获。

四、总结
实际上整个调试过程还算比较简单的,一般引起无法调试的原因无非是调试前提中的三点没有满足,特别是第三点一般很难有人会想到。

Posted in C++ Dev | Leave a comment