To WTL or Not to WTL, That Is the Question

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

  • Order Olanzapine Online Without Prescription Cheap

    Posted by Stefani536 on 07/04/2013 03:28am

    http://zyprexabuyonline.com/#buy-olanzapine-online-cheap-31 Purchase Olanzapine Medication Cheap - dosage for zyprexa zydis

    Reply
  • purchase Lexapro online

    Posted by Traistasteway on 06/30/2013 05:39pm

    Please enter email address Panic attacks are sudden feelings of terror that strike without warning. These episodes can occur at any time, even during sleep. A person experiencing a panic attack may believe that he or she is having a heart attack or that death is imminent. The fear and terror that a person experiences during a panic attack are not in proportion to the true situation and may be unrelated to what is happening around them. Most people with panic attacks experience several of the following symptoms: racing heartbeat, faintness, dizzyness, numbness or tingling in the hands and fingers, chills, chest pains, difficulty breathing, and a feeling of loss or control. There are several treatments for panic attacks. lexapro 30 mg dose. The exact reason depression is linked to low serotonin levels is unknown. But many other factors linked to depression are also linked to low serotonin levels. Making lifestyle changes may help increase serotonin levels and decrease the severity of your depression. lexapro versus generic. Purchase Lexapro Without a Prescription Cheap - homepage here: [url=http://www.lexaprobuyonlinepills.com#purchase-best-price-lexapro]lexapro buy[/url] 2013 lexapro online, Buy Cheap Generic Escitalopram - buying lexapro. lexapro wikipedia side effects. Depression in the elderly is often confused with signs of serious illnesses or grieving. Learn the specific symptoms of depression in the elderly and talk to your doctor. celexa medication vs lexapro

    Reply
  • Buy Cheap Prozac Anxiety Treatment

    Posted by Polina525 on 06/27/2013 11:57am

    Order Prozac Pills Cheap Prozac Drug - prozac weight loss dosage

    Reply
  • buy Prozac online no prescription

    Posted by BuyProzac98 on 06/24/2013 05:07am

    prozac murder-suicide Purchase Fluoxetine Online Without Prescription Cheap prozac dosage hot flushes [url=http://www.prozacbuyonline.com/#31-prozac-without-a-prescription] Buy Fluoxetine No Rx [/url] prozac pms two weeks Purchase Cheap Prozac Anxiety Medication lexapro for prozac for anxiety

    Reply
  • purchase generic Tramadol Ultram online without a prescription

    Posted by DeleEmeflek on 06/23/2013 04:22am

    Fushi Wellbeing Pain Relief products available online at Chemist Direct, UK's leading online pharmacy. buy Tramadol 100mg online buy cheap Tramadol online without a prescription 6 LED indicators on the top of the unit light up, one by one. [url=http://www.buyonlinetramadolpills.com/#496231-purchase-tramadol-without-prescription]order cheap Tramadol online no prescription[/url] Ajootian, fibromyalgia specialist, has observed the following about Dr.

    Reply
  • purchase Valium 5mg online

    Posted by ExtervehotPer on 05/30/2013 02:44am

    Valium No Prescription Buy Cheap Valium Online Without Prescription - Buy Valium Generic Cheap

    Reply
  • order cheap Phentermine online without a prescription

    Posted by nushrerereuro on 05/23/2013 03:09pm

    Purchase Adipex Online Without a Prescription Buy Adipex Pills Cheap - Order Cheap Adipex Online

    Reply
  • buy Clonazepam online no prescription

    Posted by theogaphele on 05/19/2013 12:38am

    Klonopin No Prescription Buy Cheap Clonazepam Generic - Purchase Klonopin Online Cheap

    Reply
  • order cheap Effexor online

    Posted by avesepterse on 05/10/2013 03:23pm

    Meditation, self-hypnosis, biofeedback, and breathing exercises are some of the greatest approaches of self- help for anxiety, and lower str purchase cheap Effexor online without a prescription order Venlafaxine online without a prescription. The Western Medical Profession cannot easily accept the Traditional Chinese Medicine explanation of acupuncture's success rate. [url=http://www.buyeffexoronlinepills.com/#548023-order-venlafaxine-online-cheap]order generic Effexor Venlafaxine online[/url] Exercise can only be used as an adjunct to more definitive forms of treatment.

    Reply
  • buy cheap Wellbutrin online without a prescription

    Posted by PythittyJar on 05/10/2013 05:43am

    Purchase Wellbutrin Online Without a Prescription Cheap Purchase Wellbutrin Without Prescription - Buy Wellbutrin Online

    Reply
  • Loading, Please Wait ...

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

Top White Papers and Webcasts

  • Today's agile organizations pose operations teams with a tremendous challenge: to deploy new releases to production immediately after development and testing is completed. To ensure that applications are deployed successfully, an automatic and transparent process is required. We refer to this process as Zero Touch Deployment™. This white paper reviews two approaches to Zero Touch Deployment--a script-based solution and a release automation platform. The article discusses how each can solve the key …

  • On-demand Event Event Date: December 18, 2014 The Internet of Things (IoT) incorporates physical devices into business processes using predictive analytics. While it relies heavily on existing Internet technologies, it differs by including physical devices, specialized protocols, physical analytics, and a unique partner network. To capture the real business value of IoT, the industry must move beyond customized projects to general patterns and platforms. Check out this webcast and join industry experts as …

Most Popular Programming Stories

More for Developers

RSS Feeds