WTL Makes UI Programming a Joy--中文系列

       logo

WTL Makes UI Programming a Joy,
Part 1: The Basics

 

第一章 ATL, the Foundation of WTL

 

 

The Windows Template Library (WTL) 随着 2000 1 月的 Platform SDK 一起发布 , 作为一个 SDK 的示例代码 , ATL ( 活动模板库 ) 小组成员编写而成 , 它仅仅是基于 ATL 并封装了窗口部分的 Win32 API. 此后 , ATL 2.0 包含了一些简单的窗口封装类 , 比如 CWindow, CWindowImpl CDialogImpl. 然而 , MFC 比起来 , ATL 已有的窗口类根本不能当回事 . 即使是到了 ATL3.0 也没有提供对一些常用 UI 属性的支持 , MDI, 命令条 , DDX, 打印 , GDI, 甚至是连 MFC 中最受欢迎的 CString 类都没有 . 如果没有上述这些易用特性 , 那么 WTL 终究不能令大多数 MFC 程序员满意 . 因此 , WTL 就是 ATL 小组成员开发出来的一个窗口框架, 他们认为一个完美的窗口框架就应该是这个样子的 . Table 1 展示了 WTL MFC 相关特性的比较 .

 

 

Feature

MFC

WTL

Stand-alone library

Yes

No (built on ATL)

AppWizard support

Yes

Yes

ClassWizard support

Yes

No

Officially supported by Microsoft

Yes

No (Supported by volunteers inside MS)

Support for OLE Documents

Yes

No

Support for Views

Yes

Yes

Support for Documents

Yes

No

Basic Win32 & Common Control Wrappers

Yes

Yes

Advanced Common Control Wrappers (Flat scrollbar, IP Address, Pager Control, etc.)

No

Yes

Command Bar support (including bitmapped context menus)

No (MFC does provide dialog bars)

Yes

CString

Yes

Yes

GDI wrappers

Yes

Yes

Helper classes (CRect, Cpoint, etc.)

Yes

Yes

Property Sheets/Wizards

Yes

Yes

SDI, MDI support

Yes

Yes

Multi-SDI support

No

Yes

MRU Support

Yes

Yes

Docking Windows/Bars

Yes

No

Splitters

Yes

Yes

DDX

Yes

Yes (not as extensive as MFC)

Printing/Print Preview

Yes

Yes

Scrollable Views

Yes

Yes

Custom Draw/Owner Draw Wrapper

No

Yes

Feature

MFC

WTL

Message/Command Routing

Yes

Yes

Common Dialogs

Yes

Yes

HTML Views

Yes

Yes

Single Instance Applications

No

No

UI Updating

Yes

Yes

Template-based

No

Yes

Size of a statically linked do-nothing SDI application with toolbar, status bar, and menu

228KB +
MSVCRT.DLL (288KB)

24k (with /OPT:NOWIN98)
(+ MSVCRT.DLL if you use CString)

Size of a dynamically linked do-nothing SDI application with toolbar, status bar, and menu

24KB +
MFC42.DLL (972KB) +
MSVCRT.DLL (288KB)

N/A

Runtime Dependencies

CRT (+ MFC42.DLL, if dynamically linked)

None (CRT if you use CString)

 

起初是为了支持的 COM 控件及 OLE 属性页的一套 ATL 窗口类 , 形成了 WTL 的框架窗口基础 . ATL 提供了所有的最基本窗口应用 , 包括窗口 / 对话框创建和管理 , 窗口过程处理 , 消息路由 , 窗口子类化 / 超类化 , 消息链 . Figure1 给出了 ATL 窗口类层次架构 .

Figure 1 展示了 ATL 窗口类结构.

                Figure 1: ATL Windowing-class Hierarchy

 

为了创建直接基于 ATL 的主窗口或对话框窗口 , 需要分别从 CWindowImpl CDialogImpl 派生自己的窗口类 . Figure2 是一个 SDI 应用程序 , 向你展示了如何利用 ATL 的窗口应用支持来创建主窗口和对话框 .

 

 

                Figure 2: Simple SDI Application

 

如图所示 , SDI 窗口程序包括窗口框架 , 菜单条 , 状态条和客户区 . 它提供一个关于对话框 Aboutbox 演示如何利用 ATL 来创建对话框 . VC6 中创建一个 Win32 Application 工程 , 并添加对 ATL 窗口应用的支持 .

  ( 译者注:原作以 WTL7.1 讲解 , 现在 WTL8.0 是最新版本,下载链接:http://sourceforge.net/projects/wtl/ 支持 Vista 特性和 API, 原生支持 VS2005, 也可以在 VS2008 中使用 , 本系列中所提及的 VC6, 均可以 VS2005 中的 VC8 或者 VS2008 VC9 来代替 , 相应的设置及界面或许有些许不同 , 当然 , 建议放弃使用 VC6, 因为其对标准 C++ 的支持不是很好 , 以后对此不再提及 )

(译者再注:http://sourceforge.net/projects/wtl/ 点击“View all files” 你将看到的最新版本是WTL81, 版本号WTL8.1.9127 , 05/07/2009发布,支持VS2008)

Figure3 给出了源代码相关文件 .

 

                Figure 3: Main Source Files

//---------------------------------------------------------------------

// stdafx.h :

 

#if !defined(AFX_STDAFX_H__DE06DA2F_25B6_41BA_9B20_A17362C38C8C__INCLUDED_)

#define AFX_STDAFX_H__DE06DA2F_25B6_41BA_9B20_A17362C38C8C__INCLUDED_

 

#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000

 

#define STRICT

#ifndef _WIN32_WINNT

#define _WIN32_WINNT 0x0400

#endif

#define _ATL_APARTMENT_THREADED

 

#include <atlbase.h>

//You may derive a class from CComModule and use it if you want to override

//something, but do not change the name of _Module

 

extern CComModule _Module;

#include <atlwin.h>

 

//{{AFX_INSERT_LOCATION}}

// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

 

#endif // !defined(AFX_STDAFX_H__DE06DA2F_25B6_41BA_9B20_A17362C38C8C__INCLUDED)

 

 

//---------------------------------------------------------------------

//MainFrame.H

 

#pragma once

#ifndef _MAINFRAME_H_

#define _MAINFRAME_H_

 

#include "commctrl.H"

 

class CMainFrame : public CWindowImpl<CMainFrame,CWindow, CWinTraits<WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN , WS_EX_APPWINDOW | WS_EX_WINDOWEDGE> >

{

public:

    CMainFrame():m_hWndStatusBar(NULL),m_hBmp(NULL) {

        m_hBmp =

LoadBitmap(_Module.GetResourceInstance(),

MAKEINTRESOURCE(IDB_ATLWINDOWING));

    }

    ~CMainFrame() {

        if(m_hBmp) {

            ::DeleteObject(m_hBmp);

            m_hBmp = NULL;

        }

    }

    BEGIN_MSG_MAP(CMainFrame)

        MESSAGE_HANDLER(WM_PAINT, OnPaint)

        MESSAGE_HANDLER(WM_CREATE, OnCreate)

        MESSAGE_HANDLER(WM_SIZE, OnSize)

        MESSAGE_HANDLER(WM_CLOSE, OnClose)

        COMMAND_ID_HANDLER(ID_FILE_EXIT, OnFileExit)

        COMMAND_ID_HANDLER(ID_APP_ABOUT, OnAbout)

    END_MSG_MAP()

   

    void OnFinalMessage(HWND /*hWnd*/) {}

    LRESULT OnCreate(UINT, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {

        DefWindowProc();

        m_hWndStatusBar = ::CreateStatusWindow(WS_CHILD | WS_VISIBLE |

WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP,

_T("Ready"), m_hWnd, 1);

       

        return 0L;

    }

    LRESULT OnSize(UINT, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {

        DefWindowProc();

        ::SendMessage(m_hWndStatusBar, WM_SIZE, 0, 0);

        return 0L;

    }

    LRESULT OnPaint(UINT, WPARAM, LPARAM, BOOL&) {

           PAINTSTRUCT ps;

          HDC         hdc = BeginPaint(&ps);

       

          RECT    rect; GetClientRect(&rect);

              

        //Bitmap

        HDC hDCMem =  ::CreateCompatibleDC(hdc);

        HBITMAP hBmpOld = (HBITMAP)::SelectObject(hDCMem,m_hBmp);

       

        BITMAP bmp;

        ::GetObject(m_hBmp, sizeof(BITMAP), &bmp);

        SIZE size = { bmp.bmWidth,bmp.bmHeight };

       

        ::BitBlt(hdc, rect.left, rect.top, (size.cx), (size.cy), hDCMem,

0,0,SRCCOPY);

               

        //cleanup

        ::SelectObject(hDCMem,hBmpOld);

        ::DeleteDC(hDCMem);

        hDCMem = NULL;

 

          EndPaint(&ps);

          return 0;

}

    LRESULT OnClose(UINT,WPARAM,LPARAM, BOOL&) {

        DestroyWindow();

        PostQuitMessage(0);

        return 0L;

    }  

    LRESULT OnFileExit(WORD,WORD wID, HWND,BOOL&) {

        SendMessage(WM_CLOSE);

        return 0L;

    }

    LRESULT OnAbout(WORD, WORD wID, HWND, BOOL&) {

        CAboutDialog dlg;

        dlg.DoModal();

        return 0L;

    }

 

private:

    struct CAboutDialog : public CDialogImpl<CAboutDialog> {

        enum { IDD = IDD_ABOUT };

        BEGIN_MSG_MAP(CAboutDialog)

            COMMAND_ID_HANDLER(IDOK, OnClose)

        END_MSG_MAP()

 

        LRESULT OnClose(WORD, WORD wID, HWND, BOOL&) {

            EndDialog(wID);

            return 0L;

        }  

    };

 

    HWND        m_hWndStatusBar;

    HBITMAP     m_hBmp;

};

#endif

 

//---------------------------------------------------------------------

//AtlHelloWindowing.Cpp

 

#include "stdafx.h"

#include "resource.h"

#include "MainFrame.H"

 

CComModule _Module;

 

extern "C" int WINAPI

_tWinMain(HINSTANCE hInstance,HINSTANCE, LPTSTR lpCmdLine, int nShowCmd) {

lpCmdLine = GetCommandLine(); //this line necessary for _ATL_MIN_CRT

 

_Module.Init(0, hInstance,NULL);

 

//Load Common Controls

    INITCOMMONCONTROLSEX iccx;

    iccx.dwSize = sizeof(iccx);

    iccx.dwICC =  ICC_WIN95_CLASSES  |ICC_BAR_CLASSES ; 

    ::InitCommonControlsEx(&iccx);

   

 

    HMENU hMenu = LoadMenu(_Module.GetResourceInstance(),

MAKEINTRESOURCE(IDR_MAINFRAME));

   

    CMainFrame wndFrame;

 

    wndFrame.GetWndClassInfo().m_wc.hIcon = ::LoadIcon(_Module.GetResourceInstance(),

MAKEINTRESOURCE(IDI_FORM));

    wndFrame.GetWndClassInfo().m_wc.style = 0;//CS_HREDRAW|CS_VREDRAW;

   

    wndFrame.Create(GetDesktopWindow(), CWindow::rcDefault,

_T("ATL Windowing is cool"), 0, 0, (UINT)hMenu);

   

    wndFrame.ShowWindow(nShowCmd);

    wndFrame.UpdateWindow();

       

    MSG msg;

while (GetMessage(&msg, 0, 0, 0)) { 

        TranslateMessage(&msg);

          DispatchMessage(&msg);

    }

   

   

_Module.Term();

    return 0;

}

 

MainFrame.h , CMainFrame 有两个数据成员 , 状态条窗口句柄和一个位图句柄 , WM_CREATE 消息映射函数中 CMainFrame 通过呼叫 API 函数 ( 位于 comctl32.dll )CrateStatusWindow() 创建状态条窗口 , 并在 WM_SIZE 消息映射函数中调整状态条尺寸 . WM_PAINT 消息映射函数中显示一个 GDI 位图 . ATL 并不提供对绘图操作的支持 , 因此所有绘制操作都是调原生 Win32 API.

MESSAGE_HANDLER 宏要求你自己解密消息参数 ( 大部分消息映射函数中的消息参数 LPARAM WPARAM 具体内容得自己根据 SDK 查阅 ), ATL 通过一系列宏对 WM_COMMAND WM_NOTIFY 进行了解密。 MainFrame.h 中通过 COMMAND_ID_HANDLER 来映射菜单命令 .

最后, CAboutDialog 是继承自 CDialogImpl 的对话框 , OnAbout 消息映射函数中通过函数 DoModal () 启动 CAboutDialog .

HelloAtlWindowing.cpp , ATL 应用程序的入口点函数 _tWinMain (), _tWinMain () 中创建了一个 CMainFrame 类的实例 , 并调用其 Create (), ShowWindow () UpdateWindow () 成员函数 , 这些成员函数是对 Win32 API 函数 CreateWindow (), ShowWindow () UpdateWindow () 的包装 . 最后 , 因为这是一个窗口程序 , 所以程序通过标准的 GetMessage-DispatchMessage () 启动消息循环处理 . 如果你熟悉 Win32 程序设计 , 那么你会发现这里缺少 RegisterClass () 和窗口过程函数 WndProc (), 但是你会发现其它一些十分漂亮的东西 . 如果你熟悉 MFC , 你会十分惊讶 , ATL 并不提供诸如自动支持创建状态条 , 菜单 ( 在此先不提及工具条 ) 以及启动消息循环的细节 . 很明显 , ATL 有用但同时它在这方面走的并不远 ( 对窗口框架的处理涉及不多 ), 别忘了 , ATL 牢牢扎根于 COM . 对窗口框架的支持 只是 ATL 的一个副产品而不是它存在的最主要的目的 . ATL 并不支持 MDI , Multi-SDI , Explorer-style 应用程序 , 也不支持通用控件 , DDX , 以及 GDI , 正因为如此 , WTL 出现了 .

 

 

          The WTL Way

To be continued...

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值