To WTL or Not to WTL, That Is the Question

WEBINAR: On-demand webcast

How to Boost Database Development Productivity on Linux, Docker, and Kubernetes with Microsoft SQL Server 2017 REGISTER >

The WTL is an extension to the ATL, developed by the same ATL team, and shipped by Microsoft with the January 2000 Platform SDK (available for download from Microsoft), although undocumented. The WTL extends the ATL windowing classes by providing a lightweight framework for writing Win32 applications and controls, specialized views, GDI objects, and utility classes.

The WTL itself consists of a relatively lightweight 750Kb of headers, plus three sample apps, and a Visual Studio WTL AppWizard. Compare that with the 1Mb of headers and implementation files required by ATL.

To install the WTL, all you have to do is:

  • Copy the WTL directory structure from the Platform SDK to the location of your choice.
  • Add the WTL\include directory to the list of include directories in VC++.
  • Copy the file appwiz\atlapp60.awx to the Custom App Wizard directory in the VC++ installation, %VCDIR%\Common\MSDev98\Template, where %VCDIR% is the directory where VC++ 6.0 is installed.

Design features of the WTL--and incidentally, advantages over the MFC--include:
  • Mostly templated, so results in smaller code size. For example, 24Kb for a hello world SDI app versus 440Kb for the MFC statically-linked equivalent, or 24Kb+1Mb dynamically linked.
  • No interdependencies and can be freely mixed with straight SDK code.
  • Does not enforce any particular application model, especially in comparison to the MFC application framework.

The range of WTL classes covers:

  • Standard controls (editboxes, listboxes, buttons, and others)
  • Common controls (including listview, treeview, progressbar, and updown,)
  • Internet Explorer (IE) controls (rebar, flat scrollbar, date-time picker, and others)
  • Command bar, menu, and update UI classes
  • Common dialogs
  • Property sheet and page classes
  • Frame windows, MDI frame and child frames, splitters, scrolling windows
  • DC and GDI object classes (pen, brush, bitmap, etc)
  • PrintInfo and Devmode classes
  • Utility classes: includes CPoint, CRect, CSize, and CString.

The WTL AppWizard offers you SDI, MDI, Multi-threaded SDI, and Dialog-based applications. Multi-SDI is like IE or Windows Explorer, where you seem to have multiple instances open, but they are just multiple views of the same process. The views can be generic CWindowImpl-based, or based on a Form, ListBox, Edit, ListView, TreeView, RichEdit, or HTML control. You can choose whether your application has a rebar, commandbar (like Windows CE), toolbar or statusbar. Your application can host ActiveX controls and can even be a COM server.

Hello WTL

In this exercise, we'll create a WTL equivalent of the simple "Hello World" app explained in my last article (see ATL Windows).
  1. Create a new WTL AppWizard application. Call it HelloWorld. From the WTL AppWizard Step1 dialog, accept all the defaults and click the Next button. At Step 2, once again, leave all the defaults again (including Toolbar, Rebar, Command Bar, Status Bar and view window), and click the Finish button. Now, build and run the application. You will have a very normal Win32 app with a fairly regular frame and view, menu, toolbar, status bar, and about box. Although the File|Exit, View|Toolbar, View|Statusbar, and Help|About menuitems/toolbar buttons work, the rest don't. On the other hand, the menu has icons corresponding to the toolbar buttons:
  2. Now examine the code. First, note there is a standard ATL CComModule global, initialized and terminated in the _tWinMain. Examine this function, and you will see that the only other work that _tWinMain does is to initialize the common controls through a call to InitCommonControlsEx and call the global wizard-generated Run function. The Run function creates the main frame window and a CMessageLoop object, calls ShowWindow on the mainframe, and then CMessageLoop::Run on the CMessageLoop object. This in turn essentially just calls good old GetMessage and DispatchMessage.
  3. Next, look at the CMainFrame class generated by the AppWizard. All the parent classes are in WTL\ATLFrame.h or WTL\ATLApp.h. The main functionality comes from CFrameWindowImpl.
  4. CUpdateUI is connected with the UPDATE_UI_MAP, and eventually to OnViewToolBar and OnViewStatusBar functions in our derived CMainFrame class. These do the expected ShowWindow and SetCheck behaviour.

    The inheritance from CMessageFilter and CIdleHandler means that the class must implement a filter that weeds out messages before they are dispatched for example, to change the way that keystrokes are handled), and an idle handler that is called when there aren't any messages in the queue.

    Also, both the derived view class and a CComandBarCtrl object are embedded child members of the frame.

    class CMainFrame : public CFrameWindowImpl<CMainFrame>, 
    public CUpdateUI<CMainFrame>,
     public CMessageFilter, 
    public CIdleHandler
    {
    public:
     DECLARE_FRAME_WND_CLASS(NULL, IDR_MAINFRAME)
    
     CHelloWorldView m_view;
     CCommandBarCtrl m_CmdBar;
    
     BEGIN_MSG_MAP(CMainFrame)
     MESSAGE_HANDLER(WM_CREATE, OnCreate)
      COMMAND_ID_HANDLER(ID_APP_EXIT, OnFileExit)
      COMMAND_ID_HANDLER(ID_FILE_NEW, OnFileNew)
      COMMAND_ID_HANDLER(ID_VIEW_TOOLBAR, OnViewToolBar)
      COMMAND_ID_HANDLER(ID_VIEW_STATUS_BAR, OnViewStatusBar)
      COMMAND_ID_HANDLER(ID_APP_ABOUT, OnAppAbout)
      CHAIN_MSG_MAP(CUpdateUI<CMainFrame>)
      CHAIN_MSG_MAP(CFrameWindowImpl<CMainFrame>)
     END_MSG_MAP()
    
     BEGIN_UPDATE_UI_MAP(CMainFrame)
      UPDATE_ELEMENT(ID_VIEW_TOOLBAR, UPDUI_MENUPOPUP)
      UPDATE_ELEMENT(ID_VIEW_STATUS_BAR, UPDUI_MENUPOPUP)
     END_UPDATE_UI_MAP()
    };
    
  5. The only significant function in the frame class is the OnCreate handler. This initializes the CComandBarCtrl object to attach the menu and load the command bar images (the icons on the menu). In effect, the CComandBarCtrl class converts a menu described by a menu resource into a toolbarmaking it easier to associate the same command IDs and images for menuitems and toolbar buttons. The frame then goes on to create a toolbar, a rebar and a statusbar. It then initializes the view. The final step is to add the frame's message filter and idle handler to the CComModule application object. .Message filtering is a technique to route a message between windows in your application after GetMessage pulls it off your queue but before it gets processed with Translate/DispatchMessage.
  6. LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, 
    LPARAM /*lParam*/, BOOL& /*bHandled*/)
    {
     HWND hWndCmdBar = m_CmdBar.Create(m_hWnd, 
                           rcDefault, 
                           NULL, 
                           ATL_SIMPLE_CMDBAR_PANE_STYLE);
    
     m_CmdBar.AttachMenu(GetMenu());
     m_CmdBar.LoadImages(IDR_MAINFRAME);
     SetMenu(NULL);
     
     HWND hWndToolBar = CreateSimpleToolBarCtrl(m_hWnd, 
                            IDR_MAINFRAME, 
                            FALSE, 
                            ATL_SIMPLE_TOOLBAR_PANE_STYLE);
    
     CreateSimpleReBar(ATL_SIMPLE_REBAR_NOBORDER_STYLE);
     AddSimpleReBarBand(hWndCmdBar);
     AddSimpleReBarBand(hWndToolBar, NULL, TRUE);
     CreateSimpleStatusBar();
    
     m_hWndClient = m_view.Create(m_hWnd, rcDefault, NULL, 
     WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | 
     WS_CLIPCHILDREN, WS_EX_CLIENTEDGE);
    
     UIAddToolBar(hWndToolBar);
     UISetCheck(ID_VIEW_TOOLBAR, 1);
     UISetCheck(ID_VIEW_STATUS_BAR, 1);
    
     CMessageLoop* pLoop = _Module.GetMessageLoop();
     pLoop->AddMessageFilter(this);
     pLoop->AddIdleHandler(this);
    
     return 0;
    }
    
  7. The view class derive simply from CWindowImpl, and the wizard generates one message handler - for WM_PAINT - with the usual TODO comment:
  8. class CHelloWorldView: public CWindowImpl<CHelloWorldView>
    {
    public:
     DECLARE_WND_CLASS(NULL)
    
     BOOL PreTranslateMessage(MSG* pMsg)
     {
      pMsg;
      return FALSE;
     }
    
     BEGIN_MSG_MAP(CHelloWorldView)
      MESSAGE_HANDLER(WM_PAINT, OnPaint)
     END_MSG_MAP()
    
     LRESULT OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, 
     LPARAM /*lParam*/, BOOL& /*bHandled*/)
     {
      CPaintDC dc(m_hWnd);
    
      //TODO: Add your drawing code here
    
      return 0;
     }
    };
    
  9. At this point, make a trivial change. Add code to the OnPaint to TextOut the usual "Hello World" string. Build and test.

    Compare the ease of developing this WTL app as opposed to the previous ATL version. OK, some of the ease comes simply from having a wizard to do the grunt work. But don't forget all the extra goodies we've got for free - frame+view, cool menus, about box, toolbar and status bar, including show/hide functionality and Update-UI handling. Also, compare with the MFC equivalent - the MFC AppWizard will give you a menu, toolbar, statusbar and about box, but how easy is it to get toolbar button icons into a menu in the MFC? And, again, compare the sizes of the executable files, especially for a release build.

  10. Suppose we now want to emulate the ATL Scribble app from my last article...

    Well, if you right click on the view, select Add Windows Message Handler, and get a handler for WM_LBUTTONDOWN, the generated code would look like this:

  11. LRESULT OnLButtonDown(UINT uMsg, 
                          WPARAM wParam, 
                          LPARAM lParam, 
                          BOOL& bHandled)
    {
     return 0;
    }
    
    The message map entry should now look like this:
    MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
    

    Since we're using the ATL here, the wizard doesn't provide cracked messages in the way that the MFC does. "But hang on a sec," I hear you say, "Didn't your last article promise me WTL will crack messages for me?" Well, yes. In fact, WTL does supply a set of message-cracking macros, in ATLCRACK.H. If you examine this file, you'll see there is a macro for each Windows message. All you have to do is use the appropriate macro, and implement the handler with the corresponding signature. Plus, you have to use the BEGIN_MSG_MAP_EX macro instead of the usual BEGIN_MSG_MAP. The new macro provides a way for cracked handlers to retrieve the current message and specify if the message was handled or not. This is because the cracked handlers don't have the boolean argument of raw ATL handlers. Instead, BEGIN_MSG_MAP_EX defines an additional method, SetMessageHandled for the purpose.

    For example, consider the macro for WM_LBUTTONDOWN:

    #define MSG_WM_LBUTTONDOWN(func) \
     if (uMsg == WM_LBUTTONDOWN) \
     { \
      SetMsgHandled(TRUE); \
      func((UINT)wParam, CPoint(GET_X_LPARAM(lParam), \
     GET_Y_LPARAM(lParam))); \
      lResult = 0; \
      if(IsMsgHandled()) \
      return TRUE; \
     }
    

    Note that the use of CPoint requires the prior inclusion of ATLMISC.H.

  12. So, #include "atlmisc.h" and "atlcrack.h" at the top of your HelloWorldView.h, manually change your view's message map to the EX version, and add the following cracker macros and handlers. Remember, if you want to use the GDI objects such as CPen, you'll have to #include "atlgdi.h" s well as declare two CPoints m_startPoint and m_endPoint in the view and initialize in the constructor to (-1,-1).
  13. BEGIN_MSG_MAP_EX(CHelloWorldView)
     MSG_WM_LBUTTONDOWN(OnLButtonDown)
     MSG_WM_LBUTTONUP(OnLButtonUp)
     MSG_WM_MOUSEMOVE(OnMouseMove)
    END_MSG_MAP()
    
    LRESULT OnLButtonDown (UINT flags, CPoint point)
    {
     m_startPoint = point;
     return 0;
    }
    
    LRESULT OnLButtonUp (UINT flags, CPoint point)
    {
     m_startPoint.x = m_startPoint.y = -1;
     return 0;
    }
    
    LRESULT OnMouseMove (UINT flags, CPoint point)
    {
     m_endPoint = point;
    
     CClientDC dc(this->m_hWnd);
     CPen np;
     np.CreatePen(PS_SOLID, 2, RGB(255,0,0));
     HPEN op = dc.SelectPen(np.m_hPen);
    
     if (m_startPoint.x != -1 )
     {
      dc.MoveTo(m_startPoint.x, m_startPoint.y, NULL);
      dc.LineTo(m_endPoint.x, m_endPoint.y);
      m_startPoint.x = m_endPoint.x;
      m_startPoint.y = m_endPoint.y;
     }
    
     dc.SelectPen(op);
     return 0;
    }
    
  14. To add simple menu/toolbar support for changing the color of the pen as in the previous ATL article, just add a new menu, "Color" with three menu items "Red", "Green" and "Blue". Also add three corresponding toolbar buttons, and make sure they have the same IDs - this is normal behavior, after all. Code the command handlers to change a COLORREF member in the view. That's all you need to do to get the icons into the coolmenu. Remember, the coolbar is created based on the menu IDs and any corresponding toolbar buttons found. Add entries to the view's message map, and the corresponding handlers, like this:
  15. COMMAND_ID_HANDLER_EX(ID_COLOR_RED, OnColorRed)
    COMMAND_ID_HANDLER_EX(ID_COLOR_GREEN, OnColorGreen)
    COMMAND_ID_HANDLER_EX(ID_COLOR_BLUE, OnColorBlue)
    
    LRESULT OnColorRed(UINT, int, HWND)
    {
     m_color = RGB(255,0,0);
     return 0;
    }
    
    LRESULT OnColorGreen(UINT, int, HWND)
    {
     m_color = RGB(0,255,0);
     return 0;
    }
    
    LRESULT OnColorBlue(UINT, int, HWND)
    {
     m_color = RGB(0,0,255);
     return 0;
    }
    
  16. If you build at this point, you'll find that the coolmenu and toolbar display show up, but the messages don't get routed to the view class. Why is this? Well, as you may remember from Windows Programming 101, command messages originate at the frame class, so the coolmenu/toolbar command messages will be sent to the frame's message map. Since the ATL/WTL uses a somewhat different strategy for routing messages from one class to another from that used by the MFC (see my first article on ATL Windows), you'll have to add this to the frame's message map:
  17. CHAIN_MSG_MAP_MEMBER(m_view)
    

So some things are a little different from the MFC, although you can see the logical extension from the ATL. But what about the big picture? Serious developers shouldn't be too put off by a paucity of wizard support. On the other hand, coolmenus are cool, but are they really worth changing from the MFC? Well, bear in mind that WTL is just ATL++, and ATL is the serious developer's tool of choice for anything COM-related. Is this enough of a reason to use it? After all, WTL is undocumented.

The bottom line is that WTL is just a (sourcecode) extension to ATL, which brings up the question what support do you need? Internally, Microsoft has been using early versions of WTL for years because it produces such small, efficient applications, and finally both the ATL/WTL team at Microsoft and the ATL/WTL community at large (especially Developmentor: www.develop.com) are all committed to continuing support for WTL.

ATL/WTL won't replace MFC overnight, but so many projects could be produced faster, and run faster with less overhead, plus hooking into easy COM support, by choosing ATL/WTL instead of MFC. I've been using the MFC for 10 years, but the ATL/WTL combo is so compellingly seductive. If preserving our investment in older technology were the only criterion, we'd all still be writing COBOL, and admittedly some of us do, but where would you rather be?



Comments

  • URL for Library - Don't Listen to The Silent Avenger

    Posted by Legacy on 05/10/2003 12:00am

    Originally posted by: Dean Swift

    The library is NOT easily found on Microsoft's web site, the January 200 SDK is NOWHERE to be found on MS Site. Here is the URL of the library:

    http://www.microsoft.com/downloads/details.aspx?familyid=128e26ee-2112-4cf7-b28e-7727d9a1f288&languageid=f49e8428-7071-4979-8a67-3cffcb0c2524&displaylang=en

    Reply
  • URL for WTL Lib

    Posted by Legacy on 05/10/2003 12:00am

    Originally posted by: Dean Swift

    http://www.microsoft.com/downloads/details.aspx?familyid=128e26ee-2112-4cf7-b28e-7727d9a1f288&languageid=f49e8428-7071-4979-8a67-3cffcb0c2524&displaylang=en

    Reply
  • This sample and WTL 7.0

    Posted by Legacy on 03/09/2003 12:00am

    Originally posted by: WTLEvaluator

    Hi,

    I'm begginning to evaluate the WTL for using it to build light GUI front ends, so I decided to start with this into article, and I think is a good tutorial. However, I'm using VS.Net and downloaded the WTL 7.0. After the step of adding the Color menu and toolbar buttons, and compiling, the application fails with saveral ATL asserts, whenever the user clicks on the Color Menu options.

    Anyone knows how to fix this problem (I've created my HelloWorld app using the WTL7.0 wizard)??

    By, the way the downloaded source code for WTL3.0 also has the same problem.

    Thanks in advance.
    --WTLEvaluator.

    Reply
  • And why not Qt from Trolltech?

    Posted by Legacy on 01/05/2003 12:00am

    Originally posted by: Oo La La

    Simply the answer!
    
    

    Oo La La

    Reply
  • My Oppinion

    Posted by Legacy on 09/13/2002 12:00am

    Originally posted by: Markus Schiefele

    My oppinion wether to WTL or not to WTL is: Nevertheless WTL has a genious principle it would need some years of developing to make it comparable to MFC. Very much usefull are the helper-classes (CString, CBitmap, CDC ...) in developing ATL-controls like we did before.

    Reply
  • Has MFC even been around for 10 years????

    Posted by Legacy on 10/12/2001 12:00am

    Originally posted by: Rocky Dean

    Has MFC even been around for 10 years????

    Reply
  • Windows CE 3.0 dose not support WTL??

    Posted by Legacy on 08/27/2001 12:00am

    Originally posted by: object

    I'm developing app in Pocket PC (Windows CE 3.0)

    MFC is so heavy, but API is so legnthy
    So I choosed ATL windowing (Not needed for COM)
    I only want wrapperd HWND class and message map.

    ATL is good for what I want.
    But now I'm wondering WTL is available in CE 3.0.
    If WTL is supported, it would be nice i think.

    I looked up WTL header files in pocket pc libray,
    but it seems not.

    Is available WTL in CE 3.0?

    Reply
  • How can I use HTTP protocol in ATL projects

    Posted by Legacy on 06/11/2001 12:00am

    Originally posted by: sajid

    Hi,
    Can anyone tell how to use HTTP protocol in ATL project, I can use HTTP protocol in MFC projects using CHttpFile but was not able to find equivelent in ATL.
    TIA.

    sajid

    Reply
  • WTL Install, Setup, and Info

    Posted by Legacy on 05/04/2001 12:00am

    Originally posted by: Steve Maier

    Here is some info from Nenad (MS guy that writes WTL)

    In addition to the Platform SDK, WTL 3.1 is now also available on the MSDN Downloads. Just go to http://msdn.microsoft.com/downloads, and find WTL under the "Visual Studio, Tools and Languages" \ "Visual C++"
    category.

    Then I always suggest that you add the include directory to your include paths in the compiler. This will allow the compiler to find everything.

    There is a Yahoo email group on WTL
    http://groups.yahoo.com/group/wtl

    There is also a pretty good WTL section over on Code Project.
    http://www.codeproject.com/wtl/

    Hope all of this help.....

    Reply
  • What about VC5.0??

    Posted by Legacy on 04/24/2001 12:00am

    Originally posted by: Tesgane

    I just installed the WTL and Wiz and all..
    When i generate a WTL Project a can�t compile it because of 100+ Error Msg. The compiler doesn�t know for example SimpleArray or SimpleMap. Where can i get those defines from?

    Reply
  • Loading, Please Wait ...

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • As all sorts of data becomes available for storage, analysis and retrieval - so called 'Big Data' - there are potentially huge benefits, but equally huge challenges...
  • The agile organization needs knowledge to act on, quickly and effectively. Though many organizations are clamouring for "Big Data", not nearly as many know what to do with it...
  • Cloud-based integration solutions can be confusing. Adding to the confusion are the multiple ways IT departments can deliver such integration...

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date