WTL程序的结构

本文介绍了WTL程序的结构,包括CComModule全局变量的使用,以及如何在WinMain()中初始化和关闭。文章详细讲解了ATL窗口类的创建,CWindow::rcDefault的作用,并对比了与MFC的差异。还展示了如何在ATL中创建和管理对话框,如CDialogImpl的使用,以及如何响应用户操作。最后,文章提到了菜单和对话框的交互实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一个WTL程序包含一个CComModule类型的全局变量_Module,这和MFC的程序都有一个CWinApp类型的全局变量theApp有些类似,唯一不同的是在ATL中这个变量必须命名为_Module。

下面是代码的开始部分:

#define STRICT

#define VC_EXTRALEAN

//#define IDD_DIALOG1 1001

#include <atlbase.h>        // 基本的ATL

CComModule _Module;  // 全局_Module

#include <atlwin.h>         // ATL窗口类

#include "resource.h"

atlbase.h已经包含最基本的Window编程的头文件所以我们不需要在包含windows.htchar.h之类的头文件。在代码中声明并且定义了_Module变量:

CComModule _Module;

CComModule含有程序的初始化和关闭函数需要在WinMain()中显示的调用让我们从这里开始

CComModule _Module;

 

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hInstPrev,

                                                                   LPSTR szCmdLine, int nCmdShow)

{

    _Module.Init(NULL, hInst);

    _Module.Term();

}

Init()的第一个参数只有COM的服务程序才有用由于我们的EXE不含有COM对象我们只需将NULL传递给Init()就行了。ATL不提供自己的WinMain()和类似MFC的消息泵,所以我们需要创建CMyWindow对象并添加消息泵才能使我们的程序运行。

 

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(
"HelloWorld") ))
    
{
        
// Bad news, window creation failed
        return 1;
    }


    wndMain.ShowWindow(nCmdShow);
    wndMain.UpdateWindow();

    
// Run the message loop
    while ( GetMessage(&msg, NULL, 00> 0 )
    
{
        TranslateMessage(
&msg);
        DispatchMessage(
&msg);
    }


    _Module.Term();
    
return msg.wParam;
}

 

上面的代码唯一需要说明的是CWindow::rcDefault这是CWindow中的成员静态数据成员),数据类型是RECT。和调用CreateWindow() API时使用CW_USEDEFAULT指定窗口的宽度和高度一样,ATL使用rcDefault作为窗口的最初大小。

在ATL代码内部,ATL使用了一些类似汇编语言的魔法将主窗口的句柄与相应的CMyWindow对象联系起来,在外部看来就是可以毫无问题的在线程之间传递CWindow对象,而MFC的CWnd却不能这样作。

这就是我们的窗口:

我们将添加一个About菜单并显示一个对话框,主要是为它增加一些情趣。

ATL中的对话框

我们前面提到过,ATL有两个对话框类,我们的About对话框使用CDialogImpl。生成一个新对话框和生成一个主窗口几乎一样,只有两点不同:

1.  窗口的基类是CDialogImpl而不是CWindowImpl

2.  你需要定义名称为IDD的公有成员用来保存对话框资源的ID

现在开始为About对话框定义一个新类:

class CAboutDlg : public CDialogImpl<CAboutDlg>

{

public:

    enum { IDD = IDD_ABOUT };

 

    BEGIN_MSG_MAP(CAboutDlg)

    END_MSG_MAP()

};

ATL没有在内部实现对OKCancel两个按钮的响应处理,所以我们需要自己添加这些代码,如果用户用鼠标点击标题栏的关闭按钮,WM_CLOSE的响应函数就会被调用。我们还需要处理WM_INITDIALOG消息,这样我们就能够在对话框出现时正确的设置键盘焦点,下面是完整的类定义和消息响应函数。

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(ID_OK, OnOKCancel)

                        COMMAND_ID_HANDLER(ID_CANCEL, 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;

            }

};

我使用一个消息响应函数同时处理OKCancel两个按钮的WM_COMMAND消息,因为命令响应函数的wID参数就已经指明了消息是来自OK按钮还是来自Cancel按钮。

显示对话框的方法与MFC相似,创建一个新对话框类的实例,然后调用DoModal()方法。现在我们返回主窗口,添加一个带有File菜单项的菜单用来显示我们的对话框,这需要再添加两个消息响应函数,一个是响应WM_CREATE,另一个是响应菜单的IDC_ABOUT命令。

class CMyWindow : public CWindowImpl<CMyWindow, CWindow, CFrameWinTraits>

{

public:

                DECLARE_WND_CLASS(_T("Demo_WTL_MainForm"))

 

            BEGIN_MSG_MAP(CMyWindow)

                        MESSAGE_HANDLER(WM_CLOSE, OnClose)

                        MESSAGE_HANDLER(WM_DESTROY, OnDestroy)

                        MESSAGE_HANDLER(WM_CREATE, OnCreate)

                        COMMAND_ID_HANDLER(ID_FILE, OnAbout)

            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;

            }

 

 

            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;

            }

};

在指定对话框的父窗口的方式上有些不同,MFC是通过构造函数将父窗口的指针传递给对话框而在ATL中是将父窗口的指针作为DoModal()方法的第一个参数传递给对话框的,如果象上面的代码一样没有指定父窗口,ATL会使用GetActiveWindow()得到的窗口(也就是我们的主框架窗口)作为对话框的父窗口。

LoadMenu()方法的调用展示了CComModule的另一个方法GetResourceInstance()它返回你的EXEHINSTANCE实例MFCAfxGetResourceHandle()方法相似。(当然还有CComModule::GetModuleInstance(),它相当于MFC的AfxGetInstanceHandle()。)

这就是主窗口和对话框的显示效果:

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值