在你开始用WTL或着在本文章的讨论区张脓消息之前Q我惌你先阅读下面的材料?/p>
你需要开发^台SDKQPlatform SDKQ。你要用WTL不能没有它,你可以?a >在线升安装开发^台SDKQ也可以下蝲全部文g后在本地安装。在使用之前要将SDK的包含文Ӟ.h头文Ӟ和库文gQ?Lib文gQ\径添加到VC的搜索目录,SDK有现成的工具完成q个工作Q这个工具位于开发^台SDKE序l的?i>Visual Studio Registration”文件夹里?/p>
你需要安?WTL。你可以从微软的|站?a >下蝲WTL?.0?/font>Q?*~辑注:WTL也可以到VC知识?a target="_blank">http://www.vckbase.com/tools下蝲) 在安装之前可以先查看?a >Introduction to WTL - Part 1”和?a >Easy installation of WTL”这两篇文章Q了解一下所要安装的文g的信息,虽然现在q些文章有些q时Q但q是可以提供很多有用的信息。有一件我认ؓ不该在本文章中提到的事是告诉VC如何搜烦WTL的包含文件\径,如果你用的VC6Q用鼠标点击 Tools\OptionsQ{?i>Directories标签,在显C\径的列表框中选择Include FilesQ然后将WTL的包含文件的存放路径d到包含文件搜索\径列表中?/p>
你需要了解MFC。很好地了解MFC有助于你理解后面提到的有关消息映射的宏q能够编辑那些标有“不要编辑(DO NOT EDITQ”的代码而不会出现问题?/p>
你需要清楚地知道如何使用Win32 API~程。如果你是直接从MFC开始学习Windows~程Q没有学qAPIU别的消息处理方式,那很不幸你会在用WTL旉到麻烦。如果不了解Windows消息中WPARAM参数和LPARAM参数的意义,应该明白需要读一些这斚w的文章(在CodeProject有大量的此类文章Q?/p>
你需要知?C++ 模板的语法,你可以到VC Forum FAQ 相关的连接寻求答案?/p>
我只是讨Z一些涵盖VC 6的特点,不过据我了解所有的E序都可以在VC 7上用。由于我不用VC 7Q我无法寚w些在VC 7中出现的问题提供帮助Q不q你q是可以攑ֿ的在此张贴你的问题,因ؓ其他的h可能会帮助你?/p>
Ҏpd文章的M介绍
WTL h两面性,实是这L。它没有MFC的界面(GUIQ类库那样功能强大,但是能够生成很小的可执行文g。如果你象我一样用MFCq行界面~程Q你会觉得MFC提供的界面控件封装用v来非常舒服,更不用说MFC内置的消息处理机制。当Ӟ如果你也象我一样不希望自己的程序仅仅因Z用了MFC的框架就增加几百K的大的话,WTL是你的选择。当Ӟ我们q要克服一些障: 从另一斚wԌWTL也有它自w的优势Q?/p>
在这一pd文章中,我将首先介绍ATL的窗口类Q毕竟WTL是构ZATL之上的一pd附加c,所以需要很好的了解ATL的窗口类。介l完ATL之后我将介绍WTL的特性以q展C它是如何界面~程变得轻而易举?/p>
对第一章的单介l?/b>
WTL是个很酷的工P在理解这一点之前需要首先介lATL。WTL是构ZATL之上的一pd附加c,如果你是个严g用MFC的程序员那么你可能没有机会接触到ATL的界面类Q所以请容忍我在开始WTL之前先罗索一些别的东西,l道来介l一下ATL是很有必要地?/p>
在本文的W一部分Q我给Z点ATL的背景知识,包括一些编写ATL代码必须知道的基本知识,快速的解释一些oZ知所措的ATL模板cd基本的ATLH口cR?/p>
ATL 背景知识
ATL ?WTL 的发展历?/b>
“活动模板库”(Active Template LibraryQ是一个很古怪的名字Q不是吗Q那些年U大的h可能q记得它最初被UCؓ“网l组件模板库”,q可能是它更准确的称|因ؓATL的目的就是ɾ~写lg对象和ActiveX控g更容易一些(ATL是在微Y开发新产品ActiveX-某某的过E中开发的Q那些ActiveX-某某现在被称为某?NETQ。由于ATL是ؓ了便于编写组件对象而存在的Q所以只提供了简单的界面c,相当于MFC的窗口类QCWndQ和对话框类QCDialogQ。幸q的是这些类非常的灵z,能够在其基础上构WTLq样的附加类?/p>
WTL现在已经是第二次修正了,最初的版本?.1Q现在的版本?QWTL的版本号之所以这样选择是ؓ了与ATL的版本匹配,所以不存在1?q样的版本号Q。WTL 3.1可以与VC 6和VC 7一起用,但是在VC 7下需要定义几个预处理标号。WTL 7向下兼容WTL 3.1Qƈ且不作Q何修改就可以与VC 7一起用,现在看来没有M理由q?.1来进行新的开发工作?br /> 即你能够毫不费力地阅读C++的模板类代码Q仍然有两g事可能会使你有些头晕Q以下面q个cȝ定义ZQ?/p>
q样作是合法的,因ؓC++的语法解释说即CMyWndcd是被部分定义Q类名CMyWnd已经被列入递归l承列表Q是可以使用的。将cd作ؓ模板cȝ参数是因为ATL要做另一件诡U的事情Q那是~译期间的虚函数调用机制?/p>
如果你想要了解它是如何工作地Q请看下面的例子Q?/p>
q句代码static_cast<T*>(this) 是H门所在。它Ҏ函数调用时的Ҏ处理指向B1cd的指针this指派为D1或D2cd的指针,因ؓ模板代码是在~译光生成的,所以只要编译器生成正确的承列表,q样指派是安全的。(如果你写成: ׃有麻? 之所以安全是因ؓthis对象只可能是指向D1或D2Q在某些情况下)cd的对象,不会是其他的东西。注意这很像C++的多态性(polymorphismQ,只是SayHi()Ҏ不是虚函数?/p>
要解释这是如何工作的Q首先看Ҏ个SayHi()函数的调用,在第一个函数调用,对象B1被指zؓD1Q所以代码被解释成: ׃D1没有重蝲PrintClassName()Q所以查看基cB1QB1有PrintClassName()Q所以B1的PrintClassName()被调用?/p>
现在看第二个函数调用SayHi()Q这一ơ对象被指派为D2cdQSayHi()被解释成Q?/p>
q一ơ,D2含有PrintClassName()ҎQ所以D2的PrintClassName()Ҏ被调用?/p>
q种技术的有利之处在于Q?/p>
节省虚函数表在这个例子中看v来无重(每个虚函数只?个字节)Q但是设想一下如果有15个基c,每个cd?0个方法,加v来就相当可观了?/p>
ATL H口c?/b>
好了Q关于ATL的背景知识已l讲的构多了Q到了该正式讲ATL的时候了。ATL在设计时接口定义和实现是严格区分开的,q在H口cȝ设计中是最明显的,q一点类gCOMQCOM的接口定义和实现是完全分开的(或者可能有多个实现Q?/p>
ATL有一个专门ؓH口设计的接口,可以做全部的H口操作Q这是CWindow。它实际上就是对HWND操作的包装类Q对几乎所有以HWND句柄为第一个参数的H口API的进行了装Q例如:SetWindowText() ?DestroyWindow()。CWindowcL一个公有成员m_hWndQ你可以直接对H口的句柄操作,CWindowq有一个操作符HWNDQ你可以讲CWindow对象传递给以HWND为参数的函数Q但q与CWnd::GetSafeHwnd()Q译者加QMFC的方法)没有M{同之处?/p>
CWindow ?MFC 的CWndcL很大的不同,创徏一个CWindow对象占用很少的资源,因ؓ只有一个数据成员,没有MFCH口中的对象链,MFC内部l持q一个对象链Q此对象铑ְHWND映射到CWnd对象。还有一点与MFC的CWndcM同的是当一个CWindow对象出了作用域Q它兌的窗口ƈ不被销毁掉Q这意味着你ƈ不需要随时记得分M所创徏的时CWindow对象?/p>
在ATLcM对窗口过E的实现是CWindowImpl。CWindowImpl 含有所有窗口实C码,例如Q窗口类的注册,H口的子cdQ消息映以及基本的WindowProc()函数Q可以看与MFC的设计有很大的不同,MFC所有的代码都放在一个CWndcM?/p>
q有两个独立的类包含对话框的实现Q它们分别是CDialogImpl ?CAxDialogImplQCDialogImpl 用于实现普通的对话框而CAxDialogImpl实现含有ActiveX控g的对话框?/p>
定义一个窗口的实现
M非对话框H口都是从CWindowImpl z的,你的新类需要包含三件事情: H口cȝ定义通过DECLARE_WND_CLASS宏或DECLARE_WND_CLASS_EX宏来实现。这辆个宏定义了一个CWndClassInfol构Q这个结构封装了WNDCLASSEXl构。DECLARE_WND_CLASS宏让你指定窗口类的类名,其他参数使用默认讄Q而DECLARE_WND_CLASS_EX宏还允许你指定窗口类的类型和H口的背景颜Ԍ你也可以用NULL作ؓcdQATL会自动ؓ你生成一个类名?/p>
让我们开始定义一个新c,在后面的章节我会逐步的完成这个类的定义?/p>
接下来是消息映射链,ATL的消息映链比MFC的简单的多,ATL的消息映链被展开为switch语句Qswitch语句正确的消息处理者ƈ调用相应的函数。用消息映链的宏是BEGIN_MSG_MAP ?END_MSG_MAPQ让我们为我们的H口d一个空的消息映链?/p>
我将在下一节展开讲如何如何添加消息处理到消息映射链。最后,我们需要ؓ我们的窗口类定义H口的特征,H口的特征就是窗口类型和扩展H口cd的联合体Q用于创建窗口时指定H口的类型。窗口类型被指定为参数模板,所以窗口的调用者不需要ؓ指定H口的正类型而烦心,下面是是同ATLcCWinTraits定义H口cd的例子: 调用者可以重载CMyWindowTraits的类型定义,但是一般情况下q是没有必要的,ATL提供了几个预先定义的Ҏ的类型,其中之一是CFrameWinTraitsQ一个非常棒的框架窗口: ATL的消息映链是对开发者不太友好的部分Q也是WTL对其改进最大的部分。类向导臛_可以让你d消息响应Q然而ATL没有消息相关的宏和象MFC那样的参数自动展开功能Q在ATL中只有三U类型的消息处理Q一个是WM_NOTIFYQ一个是WM_COMMANDQ第三类是其他窗口消息,让我们开始ؓ我们的窗口添加WM_CLOSE ?WM_DESTROY的消息相应函数?/p>
你可能注意到消息响应函数的到的是原始的WPARAM ?LPARAM|你需要自己将其展开为相应的消息所需要的参数。还有第四个参数bHandledQ这个参数在消息相应函数调用被ATL讄为TRUEQ如果在你的消息响应处理完之后需要ATL调用默认的WindowProc()处理该消息,你可以讲bHandled讄为FALSE。这与MFC不同QMFC是显C的调用基类的响应函数来实现的默认的消息处理的?/p>
让我们也d一个对WM_COMMAND消息的处理,假设我们的窗口有一个ID为IDC_ABOUT的About菜单Q?/p>
需要注意得是COMMAND_HANDLER宏已l将消息的参数展开了,同样QNOTIFY_HANDLER宏也WM_NOTIFY消息的参数展开了?/p>
高消息映射铑֒嵌入c?/b>
ATL的另一个显著不同之处就是Q何一个C++c都可以响应消息Q而MFC只是消息响应Q务分l了CWndcdCCmdTargetc,外加几个?code>PreTranslateMessage()Ҏ的类。ATL的这U特性允许我们编写所谓的“嵌入类”,为我们的H口dҎ只需该cL加到l承列表中就行了Q就q么单! 一个基本的带有消息映射铄c通常是模板类Q将zcȝcd作ؓ模板的参敎ͼq样它就可以讉KzcM的成员,比如m_hWndQCWindowcM的HWND成员Q。让我们来看一个嵌入类的例子,q个嵌入c通过响应 让我们来研究一下这个新cR首先,CPaintBkgnd有两个模板参敎ͼ使用CPaintBkgnd的派生类的名字和用来ȝ口背景的颜色。(t_ 前缀通常用来作ؓ模板cȝ模板参数的前~QCPaintBkgnd也是从CMessageMapz的,qƈ不是必须的,因ؓ所有需要响应消息的cd需使用 构造函数和析构函数都相当简单,只是创徏和销毁WindowsdQ这个画L参数t_crBrushColor军_颜色。接着是消息映链Q它响应WM_ERASEBKGND消息Q最后由响应函数OnEraseBkgnd()用构造函数创建的d填充H口的背景。在OnEraseBkgnd()中有两g事需要注意,一个是它用了一个派生的H口cȝҎQ即GetClientRect()Q,我们如何知道zcM有GetClientRect()Ҏ呢?如果zcM没有q个Ҏ我们的代码也不会有Q何抱怨,q译器认zcT是从CWindowz的。另一个是OnEraseBkgnd()没有消息参数wParam展开备上下文QDCQ。(WTL最l会解决q个问题Q我们很快就可以看到Q我保证Q?br /> 要在我们的窗口中使用q个嵌入c需要做两g事:首先Q将它加入到l承列表Q?/p>
其次Q需要CMyWindow消息传递给CPaintBkgndQ就是将光入到消息映射链,在CMyWindow的消息映链中加入CHAIN_MSG_MAP宏: MCMyWindow没有处理的消息都被传递给CPaintBkgnd。应该注意的是WM_CLOSEQWM_DESTROY和IDC_ABOUT消息不会传递,因ؓq些消息一旦被处理消息映射铄查找׃中止。用typedef是必要地Q因为宏是预处理宏,只能有一个参敎ͼ如果我们CPaintBkgnd<CMyWindow, RGB(0,0,255)>作ؓ参数传递,那个?”会佉K处理器认为我们用了多个参数?/p>
你可以在l承列表中用多个嵌入类Q每一个嵌入类使用一个CHAIN_MSG_MAP宏,q样消息映射铑ְ会将消息传递给它。这与MFC不同QMFC地CWndzcd能有一个基c,MFC自动消息传递给基类?/p>
ATLE序的结?/b>
到目前ؓ止我们已l有了一个完整地ȝ口类Q即使不完全有用Q,让我们看看如何在E序中用它。一个ATLE序包含一个CComModulecd的全局变量_ModuleQ这和MFC的程序都有一个CWinAppcd的全局变量theApp有些cMQ唯一不同的是在ATL中这个变量必d名ؓ_Module?/p>
下面是stdafx.h文g的开始部分: atlbase.h已经包含最基本的Window~程的头文gQ所以我们不需要在包含windows.hQtchar.h之类的头文g。在CPP文g中声明了_Module变量Q?/p>
CComModule含有E序的初始化和关闭函敎ͼ需要在WinMain()中显C的调用Q让我们从这里开始: Init()的第一个参数只有COM的服务程序才有用Q由于我们的EXE不含有COM对象Q我们只需NULL传递给Init()p了。ATL不提供自qWinMain()和类似MFC的消息܇Q所以我们需要创建CMyWindow对象q添加消息܇才能使我们的E序q行?br /> 上面的代码唯一需要说明的是CWindow::rcDefaultQ这是CWindow中的成员Q静态数据成员)Q数据类型是RECT。和调用CreateWindow() API时用CW_USEDEFAULT指定H口的宽度和高度一PATL使用rcDefault作ؓH口的最初大?/p>
在ATL代码内部QATL使用了一些类似汇~语a的魔法将ȝ口的句柄与相应的CMyWindow对象联系hQ在外部看来是可以毫无问题的在U程之间传递CWindow对象Q而MFC的CWnd却不能这样作?/p>
q就是我们的H口Q?/p>
我得承认q确实没有什么激动h心的地方。我们将d一个About菜单q显CZ个对话框Q主要是为它增加一些情?/p>
ATL中的对话?/b>
我们前面提到q,ATL有两个对话框c,我们的About对话框用CDialogImpl。生成一个新对话框和生成一个主H口几乎一P只有两点不同Q?br /> 现在开始ؓAbout对话框定义一个新c: ATL没有在内部实现对“OK”和“Cancel”两个按钮的响应处理Q所以我们需要自己添加这些代码,如果用户用鼠标点L题栏的关闭按钮,WM_CLOSE的响应函数就会被调用。我们还需要处理WM_INITDIALOG消息Q这h们就能够在对话框出现时正的讄键盘焦点Q下面是完整的类定义和消息响应函数?/p>
我用一个消息响应函数同时处理“OK”和“Cancel”两个按钮的WM_COMMAND消息Q因为命令响应函数的wID参数已l指明了消息是来自“OK”按钮还是来自“Cancel”按钮?/p>
昄对话框的Ҏ与MFC怼Q创Z个新对话框类的实例,然后调用DoModal()Ҏ。现在我们返回主H口Q添加一个带有About菜单的菜单用来昄我们的对话框Q这需要再d两个消息响应函数Q一个是响应 在指定对话框的父H口的方式上有些不同QMFC是通过构造函数将父窗口的指针传递给对话框而在ATL中是父H口的指针作为DoModal()Ҏ的第一个参C递给对话框的Q如果象上面的代码一h有指定父H口QATL会?code>GetActiveWindow()得到的窗口(也就是我们的L架窗口)作ؓ对话框的父窗口?/p>
对LoadMenu()Ҏ的调用展CZCComModule的另一个方法-GetResourceInstance()Q它q回你的EXE的HINSTANCE实例Q和MFC的AfxGetResourceHandle()Ҏ怼。(当然q有CComModule::GetModuleInstance()Q它相当于MFC的AfxGetInstanceHandle()。) q就是主H口和对话框的显C效果:
我会l箋讲WTL的,只是会在W二部分。我觉得既然q些文章是写l用MFC的开发者的Q所以有必要在投入WTL之前先介l一些ATL。如果你是第一ơ接触到ATLQ那现在你就可以试写一些小E序Q处理消息和使用嵌入c,你也可以试用类向导支持消息映射链,使它能够自动d消息响应。现在就开始,右键单击CMyWindow,在弹出的上下文菜单中单击?i>Add Windows Message Handler”菜单项?/p>
在第二部分,我将全面介绍基本的WTLH口cd一个更好的消息映射宏?/p>
class CMyWnd : public CWindowImpl<CMyWnd>
{
...
};
template <class T>
class B1
{
public:
void SayHi()
{
T* pT = static_cast<T*>(this); // HUH?? 我将在下面解?
pT->PrintClassName();
}
protected:
void PrintClassName() { cout << "This is B1"; }
};
class D1 : public B1<D1>
{
// No overridden functions at all
};
class D2 : public B1<D2>
{
protected:
void PrintClassName() { cout << "This is D2"; }
};
main()
{
D1 d1;
D2 d2;
d1.SayHi(); // prints "This is B1"
d2.SayHi(); // prints "This is D2"
}
class D3 : public B1<D2>
void B1<D1>::SayHi()
{
D1* pT = static_cast<D1*>(this);
pT->PrintClassName();
}
void B1<D2>::SayHi()
{
D2* pT = static_cast<D2*>(this);
pT->PrintClassName();
}
class CMyWindow : public CWindowImpl<CMyWindow>
{
public:
DECLARE_WND_CLASS(_T("My Window Class"))
};
class CMyWindow : public CWindowImpl<CMyWindow>
{
public:
DECLARE_WND_CLASS(_T("My Window Class"))
BEGIN_MSG_MAP(CMyWindow)
END_MSG_MAP()
};
typedef CWinTraits<WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,WS_EX_APPWINDOW> CMyWindowTraits;
class CMyWindow : public CWindowImpl<CMyWindow, CWindow, CMyWindowTraits>
{
public:
DECLARE_WND_CLASS(_T("My Window Class"))
BEGIN_MSG_MAP(CMyWindow)
END_MSG_MAP()
};
typedef CWinTraits<WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
填写消息映射?/b>
WS_EX_APPWINDOW | WS_EX_WINDOWEDGE> CFrameWinTraits;class CMyWindow : public CWindowImpl<CMyWindow, CWindow, CFrameWinTraits>
{
public:
DECLARE_WND_CLASS(_T("My Window Class"))
BEGIN_MSG_MAP(CMyWindow)
MESSAGE_HANDLER(WM_CLOSE, OnClose)
MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
END_MSG_MAP()
LRESULT OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
DestroyWindow();
return 0;
}
LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
PostQuitMessage(0);
return 0;
}
};
class CMyWindow : public CWindowImpl<CMyWindow, CWindow, CFrameWinTraits>
{
public:
DECLARE_WND_CLASS(_T("My Window Class"))
BEGIN_MSG_MAP(CMyWindow)
MESSAGE_HANDLER(WM_CLOSE, OnClose)
MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
COMMAND_ID_HANDLER(IDC_ABOUT, OnAbout)
END_MSG_MAP()
LRESULT OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
DestroyWindow();
return 0;
}
LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
PostQuitMessage(0);
return 0;
}
LRESULT OnAbout(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
MessageBox ( _T("Sample ATL window"), _T("About MyWindow") );
return 0;
}
};
WM_ERASEBKGND
消息来画H口的背景?/p>
template <class T, COLORREF t_crBrushColor>
class CPaintBkgnd : public CMessageMap
{
public:
CPaintBkgnd() { m_hbrBkgnd = CreateSolidBrush(t_crBrushColor); }
~CPaintBkgnd() { DeleteObject ( m_hbrBkgnd ); }
BEGIN_MSG_MAP(CPaintBkgnd)
MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd)
END_MSG_MAP()
LRESULT OnEraseBkgnd(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
T* pT = static_cast<T*>(this);
HDC dc = (HDC) wParam;
RECT rcClient;
pT->GetClientRect ( &rcClient );
FillRect ( dc, &rcClient, m_hbrBkgnd );
return 1; // we painted the background
}
protected:
HBRUSH m_hbrBkgnd;
};
BEGIN_MSG_MAP
宏就_了,所以你可能看到其他的一些嵌入类的例子代码,它们q不是从该基cL生的?/p>
class CMyWindow : public CWindowImpl<CMyWindow, CWindow, CFrameWinTraits>,
public CPaintBkgnd<CMyWindow, RGB(0,0,255)>
class CMyWindow : public CWindowImpl<CMyWindow, CWindow, CFrameWinTraits>,
public CPaintBkgnd<CMyWindow, RGB(0,0,255)>
{
...
typedef CPaintBkgnd<CMyWindow, RGB(0,0,255)> CPaintBkgndBase;
BEGIN_MSG_MAP(CMyWindow)
MESSAGE_HANDLER(WM_CLOSE, OnClose)
MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
COMMAND_HANDLER(IDC_ABOUT, OnAbout)
CHAIN_MSG_MAP(CPaintBkgndBase)
END_MSG_MAP()
...
};
// stdafx.h:
#define STRICT
#define VC_EXTRALEAN
#include <atlbase.h> // 基本的ATLc?
extern CComModule _Module; // 全局_Module
#include <atlwin.h> // ATLH口c?/span>
// main.cpp:
CComModule _Module;
// main.cpp:
CComModule _Module;
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hInstPrev,
LPSTR szCmdLine, int nCmdShow)
{
_Module.Init(NULL, hInst);
_Module.Term();
}
// main.cpp:
#include "MyWindow.h"
CComModule _Module;
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hInstPrev,
LPSTR szCmdLine, int nCmdShow)
{
_Module.Init(NULL, hInst);
CMyWindow wndMain;
MSG msg;
// Create & show our main window
if ( NULL == wndMain.Create ( NULL, CWindow::rcDefault,
_T("My First ATL Window") ))
{
// Bad news, window creation failed
return 1;
}
wndMain.ShowWindow(nCmdShow);
wndMain.UpdateWindow();
// Run the message loop
while ( GetMessage(&msg, NULL, 0, 0) > 0 )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
_Module.Term();
return msg.wParam;
}
class CAboutDlg : public CDialogImpl<CAboutDlg>
{
public:
enum { IDD = IDD_ABOUT };
BEGIN_MSG_MAP(CAboutDlg)
END_MSG_MAP()
};
class CAboutDlg : public CDialogImpl<CAboutDlg>
{
public:
enum { IDD = IDD_ABOUT };
BEGIN_MSG_MAP(CAboutDlg)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
MESSAGE_HANDLER(WM_CLOSE, OnClose)
COMMAND_ID_HANDLER(IDOK, OnOKCancel)
COMMAND_ID_HANDLER(IDCANCEL, OnOKCancel)
END_MSG_MAP()
LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
CenterWindow();
return TRUE; // let the system set the focus
}
LRESULT OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
EndDialog(IDCANCEL);
return 0;
}
LRESULT OnOKCancel(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
EndDialog(wID);
return 0;
}
};
WM_CREATE
Q另一个是响应菜单的IDC_ABOUT命o?/p>
class CMyWindow : public CWindowImpl<CMyWindow, CWindow, CFrameWinTraits>,
public CPaintBkgnd<CMyWindow,RGB(0,0,255)>
{
public:
BEGIN_MSG_MAP(CMyWindow)
MESSAGE_HANDLER(WM_CREATE, OnCreate)
COMMAND_ID_HANDLER(IDC_ABOUT, OnAbout)
// ...
CHAIN_MSG_MAP(CPaintBkgndBase)
END_MSG_MAP()
LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
HMENU hmenu = LoadMenu ( _Module.GetResourceInstance(),
MAKEINTRESOURCE(IDR_MENU1) );
SetMenu ( hmenu );
return 0;
}
LRESULT OnAbout(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
CAboutDlg dlg;
dlg.DoModal();
return 0;
}
// ...
};