The mis-adventures of a new Game Developer.
Daily 10/29/03
Published on October 29, 2003 By Mudflap In Software Development

WTL Madness

I'm in the middle of a little downtime right now. I'm waiting for feedback on the map editor and Cari's getting the GalCiv2 codebase integrated with our demo stuff. Scott is well on his way with Political Machine so I'm stuck here with nothing to do Well not really, but nothing that's immediately pressing right now. I've decided to use this time to learn as much as I can about WTL.

Ian introduced me to WTL a couple of weeks ago. For those who don't know what it is already, WTL is a stand in replacement for MFC. It's based on ATL so it's template heavy. Cool stuff if you like it. I learned to like templates at my last job. There are ports of you more common MFC utility classes (CPoint, CString, etc..).

There are numerous resources for the WTL. Right now it's unsupported by M$ so the community has come together to support it.
Yahoo! Groups - wtl
The Code Project - Free Source Code and Tutorials
IDevResource.com - WTL (Windows Template Library)
WTL Programming (CodeGuru)

The best tutorials I've found are on CodeProject. I'm not going to bore you with a tutorial. You can find that somewhere else.

I did find a couple of snippets really interesting though. I haven't gone through them yet to make them useful, but here's what I'm talking about.

Self Referencing Templates:
This is a trick I learned about at my last job. It's are really cool trick to know. You can reference your type in a template definition.

template <class T>
class A
{
};

class B : public A<B>
{
};
 

There are a lot of uses for this trick. WTL uses it exstensively. It's really neat.

Message Maps:
You can derive classes that are just message maps and manually chain them together. This is one part I'm really interested in. I'm not sure if this will work, but check out this situation:


Here's the logic for a left click in the map editor. Currently, there's one function that handles all this.

void LeftClick()
{
   if(addingStars)
   {
      // Add Stars
   }
   else if(addingPlanets)
   {
      // Add Planets
   }
   else if(addingShps)
   {
      // Add Ships
   }
}

That function can get pretty big and ugly pretty fast. With the WTL, I think we can make this more modular using mixin message maps.

class AddStarMessageMap
{
   BEGIN_MSG_MAP(AddStarMessageMap)
      MSG_WM_LBUTTONDOWN(OnLButtonDown)
   END_MSG_MAP()
};

class AddPlanetMessageMap
{
   BEGIN_MSG_MAP(AddPlanetMessageMap)
      MSG_WM_LBUTTONDOWN(OnLButtonDown)
   END_MSG_MAP()
};

class AddShipMessageMap
{
   BEGIN_MSG_MAP(AddShipMessageMap)
      MSG_WM_LBUTTONDOWN(OnLButtonDown)
   END_MSG_MAP()
};

class EditorView
{
   BEGIN_MSG_MAP(EditorView)
      CHAIN_MSG_MAP(AddStarMessageMap)
      CHAIN_MSG_MAP(AddPlanetMessageMap)
      CHAIN_MSG_MAP(AddShipMessageMap)
      MSG_WM_LBUTTONDOWN(OnLButtonDown)
   END_MSG_MAP()
};

Message Cracks:
atlcrack.h provides you with pre-defined MFC style message maps. Standard WTL messages are handeld through a message handler like:
MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
LRESULT OnLButtonDown(UINT, WPARAM, LPARAM, BOOL&);

atlcrack gives you shortcuts:
MSG_WM_LBUTTONDOWN(OnLButtonDown)
LRESULT OnLButtonDown(UINT, CPoint);

 

Anyways, that's my hope. I'd better get crackin' on it. I'll let you know how it goes.

There are a few gotchas that I noticed.

  1. You can't use the cracked messages (atlcrack.h) on CMessageMap derived classes. The macro only works for CWindowImpl classes. Bummer. I have to crack them myself.
  2. I had to tie the message maps to the window implementation to share data. That means that I couldn't easily re-use them with another class. I'm sure I could come up with a different way that makes the message maps more modular, but I'd have to think about it more. Using the self referencing templates was cool even if it did make me feel dirty writing "pThis->". Ugh.

    LRESULT OnLButtonDown(UINT, WPARAM, LPARAM, BOOL&)
    {
       T* pThis = static_cast<T*>(this);
       bHandled = pThis->GetMode() == ID_MODE_STAR;
       if(bHandled)
       {
          // Do star stuff
       }
       return 0;
    }
     
  3. You can't chain the WM_PAINT message. The first CPaintDC created does the painting. Anything after that doesn't paint anymore. To get around it, I manually call the OnPaint functions for each of the derived message maps. Not a biggy.

It works. I managed to create a little app with 3 separate message maps. I'm not sure if it was useful other than as an excersize. I'll have to use it more to get more familiar with WTL. I only scratched the surface. There's way more you can do and I probably will do in the future.

 


Comments
on Oct 29, 2003
I'll be thankful once the World Trade League replaces the WTO completely!