Patchou's Cabana

The personal blog of Patchou

The Messenger Plus! Story

If somebody had told me, back in May 2001, that the software I had started to create would later on be used by millions of people across the globe, I would never have believed it. At the time of writing, the software now called Messenger Plus! Live is used by no less than 60 million people, is officially translated into 21 languages and is downloaded and installed more than 300 thousand times a day. Not bad for a little freeware :-) .

MSN Messenger – Plus! Extension 1.00

I had just turned 20 and I was enjoying my days living in Canada, working as a full time software developer for a Montreal based company. For a reason I can’t remember anymore, I was getting a free edition of the Visual C++ Developers Journal every month, by regular mail. Some times I would read it, sometimes I wouldn’t, but one particular article triggered my interest this day: “Hook, Line, and Sinker” by Dino Esposito.

Visual C++ Developers Journal

The article was about something called “Win32 hooks”. Although they were told to be “old” and “faithful”, I had just never heard about them before and what I read in those 6 pages amazed me: Windows allowed applications to “hook” onto other programs and modify their runtime behaviour without the need for low level patching or disassembly. I was so surprised that I spent my afternoon and the following days testing those techniques myself. Although the article used Notepad as an example, it was too limited to give the hooks a good try so I thought about using one of the latest applications I had recently installed on my computer: MSN Messenger 3.6. At that time, Messenger was far from being the popular software it is today but I had given up on ICQ and had found in MSN Messenger a simplicity of use that most other instant messaging clients were lacking.

Because of my background with IRC Log Viewer, one of the first options I tried to add in Messenger was chat logging. I’m still not sure why but Microsoft waited many years before adding that feature in the client itself, despite the fact that most people considered it to be a necessity for any proper instant messaging software. Messenger was still very basic at that point and adding text logging turned out to be easier that I had thought. Seeing I was on to something, I decided to package the whole thing and worked on a setup for public distribution.

Messenger Plus! 1.00 with MSN Messenger 3.6From what I can see in my archives (I still have all the versions of Messenger Plus! I have ever released), Version 1.00 Beta 1 was created on May 6th 2001 and the final release of Version 1.00 was released only two weeks later, on May 19th. The original web site and icons were all “un-original creations” from the software developer that I am, as you can see in this screenshot of the very first public release :) . The name itself was equally un-inspired: “MSN Messenger – Plus! Extension”, changed to “Messenger – Plus! Extension” 3 months later for trademark reasons. Being the first add-on ever released for MSN Messenger, Messenger Plus! immediately caught the attention of internet users, people started to talk about it in blogs and sent it to their friends. This quick positive response naturally motivated me to keep on working.

As I did with most of my projects before that, I spent most of my free time working on Messenger Plus!. Evenings and weekends alike, I coded more features, fixed bugs etc… by the end of the year 2001, I was already seeing some consequences: for one, I was seeing the limits of my “unlimited bandwidth” shared hosting plan. Too many visitors were suddenly coming on the server and the provider was starting to panic. Messenger Plus! itself was a freeware and was actually costing me money every month. At the same time however, it was helping me get consultancy contracts with several companies, including one of particular interest: ActiveBuddy. I was asked to create a new Messenger add-on for the company to add interactive bots into people’s contact list. It was a cool and innovative idea at the time and those bots were providing all sorts of services. We worked together for about two years on a software called the “Interactive Agent Plugin”. Although this was separate from my daily work and Messenger Plus!, I really enjoyed working with these people. They helped me finance my own add-on for a while and not many people seem to know this but the current Windows Live Agents services provided by Microsoft is actually based on their technology (ActiveBuddy was renamed Colloquis and then purchased by Microsoft).

The Messenger Plus! Community and the start of everything

The "MSN Messenger - Plus! Extension" LogoMSN Messenger 4 and 4.5 got out, Microsoft created Windows Messenger to be bundle Messenger with Windows XP, and Messenger Plus! kept on improving along the way. Once it reached version 1.42, Messenger Plus! started to suffer from its weakness: initially meant to be a small-scale project with only 9,000 lines of code, the software, its engine in particular, was under too much pressure and couldn’t be properly updated much longer. The first anniversary of Messenger Plus! was celebrated in silence as life pushed me on another path in 2002. Thankfully by that time, a group of people had already gathered around the product and were visiting the support forum regularly. Messenger Plus! lived on its own for a while, in its current state, left unchanged and supported by its users alone.

For as long as I can remember, the support forum of Messenger Plus! has been able to count on MyBB as its engine. First a sub-site of their own domain, the forum was then moved on its own server and assigned a real name as it was growing up into something resembling much more a community than the average support center. Although some people thought otherwise at times, I never had a single “employee” working there. The forum has always be constituted of people, real people, with their own opinions, point of views and ways of life. Some joined, some left, some stayed for a while… overall, if you excuse the cliché, this is how Messenger Plus! got its heart. I can’t even start to thank these people by name as there are, and have been, just too many of them. I can tell you however that the first thing they did, without my knowledge, was to keep Messenger Plus! alive and kicking for half of the year 2002.

I can remember this moment like if it was yesterday: I was coming back from work, searching for something to do, when I thought of visiting the forum that was linked to this old add-on of mine. Messenger Plus! was far from my mind at that point and I was mainly curious to see if some people were still using it. It had been a while and the reaction of the forum’s members took me by surprise: “Where have you been?!”, “Patchou is here!”, … you can’t help but wondering if people are mistaking you for somebody else with such a warm welcome. I then thought about compiling the latest usage statistics for the software and I found out something incredible: after months of being left unchecked, the stats had gone through the roof! literally, so much that my system couldn’t even count the users properly anymore. I realised it was time to continue where I had left off, and Messenger Plus! 1′s code being what it was, I decided it was the perfect occasion for a complete makeover.

Messenger Plus! 2 Logo

6 months, 5 private betas, 5 public betas and 30,000 new lines of code later, project MP2 was completed! It first took 3 months of work to create and re-think Messenger Plus! from scratch. The first private beta version was released on December 24th 2002 (Christmas Beta!, Beta Claus, Santa Plus!, …) and the next ones followed in sequence after one of the beta setups got leaked to the public. Although this issue was less than enjoyable, it helped me push the project forward even more seeing the incredible feedback this buggy half-finished version generated on many web sites. The final version got released in April 2003 and was the first one to ever be translated (officially) in other languages: 27 to be exact.

At the time, Messenger Plus! version 2 was working in Windows 95/98/Me, Windows NT4/2000/XP, with left-to-right and right-to-left languages, and in both MSN/Windows Messenger 4 and 5. It was a challenge to maintain, but one that proved to be worthwhile. More than ever before, Messenger Plus! helped me develop new skills and allowed me to deliver highly expected features to a large user base. Being a software developer since the age of 16, I couldn’t have asked for more.

Theming Rich Edit and Custom Controls

This article was originally written in 2004 and published at CodeGuru. Although the code presented here was not tested since then, it should still be working and of some usefulness to people attempting to theme the borders of their controls.

The class distributed with this article is intended to be used by any program, developed in C++, that’s using a Rich Edit control. For some reason, Microsoft never updated its Rich Edit library after the release of Windows XP to make the control theme-aware. If your program supports themes (with the use of a manifest for example) and is displaying a Rich Edit box in a window containing other controls, chances are that you already noticed how bad the Rich Edit looks compared to the other controls. I always thought that newer releases of the Rich Edit library would bring theme support but as it’s been more than 2 years already, I decided to create CRichEditThemed to take care of the problem. This little class has been designed to be incorporated in almost any Visual C++ project, painlessly, and necessitates only one function call to make your Rich Edit controls look like any other native control of Windows XP.

Demo Picture

It is surprisingly difficult to find the proper documentation for applying a theme to a non-native control. It is true that improving the look of the borders of your edit controls was probably never a top priority in your schedule, however, it doesn’t change the fact that Rich Edit controls look totally out of place in Windows XP and make any program’s GUI lose some of its appeal. Some programs solved the situation by using Rich Edit controls in windowless modes (which is complete overkill if you’re only trying to achieve theme support) while some others resorted in using weird GUI tricks that completely break down when users are not using the native theme of Windows XP. I searched a lot for some proper indication about adding real theme support to a control and the only thing I found was replies such as “use DrawThemeEdge”, which, if you’ve been considering the problem for more than 10 minutes, is not very helpful (and wrong anyway). The CRichEditThemed class presented here solves this one and only problem and adds genuine theme support to any Rich Edit controls. I tried to comment the code as much as possible for those who want to understand how it works, and made the usage as simple as possible for those who don’t have more than 5 minutes to spend on the issue.

Comments, suggestions and bug reports are always appreciated. I’m not used to sharing code in this manner, however, I do think that nowadays, no programmer should have to be bothered improving the look of a Rich Edit control, we all have more important problems to take care of. As you will see, the class could also be easily modified to support other kinds of controls (including custom controls and ActiveX) which should make this article a good read for anybody interested in using the Windows XP theme library for its own purpose. This class is here to be used, shared and redistributed.

Download the files here.

Using the Class

The CRichEditThemed class was designed from the ground to to be as simple of use as possible. You won’ need to control the lifetime of a new object, you won’t need to relay window messages and you won’t need to include another library (such as MFC or ATL) in your project to make the class work (with the exception of STL which is a standard C++ library, included with any major C++ compiler, and is not supposed to create any conflict with the rest of your program). The class uses TCHAR to ensure Unicode compatibility and is totally backward compatible (meaning that it will stay silent when used in older versions of Windows or in an environment where themes are nor enabled). Here are the files that will be automatically included in your project by RichEditThemed.h :

#include <tchar.h>      //Used for ANSI/Unicode compatibility
#include <map>          //Used internally by the class
#include <uxtheme.h>    //Used to access the UxTheme library
#include <tmschema.h>   //Definitions used by some of the UxTheme library functions

In addition, you must ensure that your Platform SDK is up to date and that _WIN32_WINNT is defined to at least 0×0501. If it isn’t, the compiler won’t give access to the UxTheme API and you will get a compilation error. This can be done by adding a preprocessor definition in the settings of your projects or by adding the proper #define statement before the first inclusion of windows.h in your project.

//stdafx.h
#define _WIN32_WINNT 0x0501
#include <windows.h>

Every theme-specific function is imported at runtime which means that your EXE/DLL won’t have any additional external dependency caused by CRichEditThemed. The only files you must include in your project are RichEditThemed.cpp and RichEditThemed.h. The class has only one public function which creates a new object in memory and attaches the specified Rich Edit control to the newly created object. Everything else, including destruction and memory management, is taken care of internally by the class.

public static bool CRichEditThemed::Attach(HWND hRichEdit);

The CRichEditThemed::Attach() function must be called during the creation of the Rich Edit control’s parent window, before the control is displayed on screen for the first time. This is generally achieved by making the call while processing WM_CREATE or WM_INITDIALOG. The object is not designed to attach on a control that is already displayed on screen and usable, that’s about the only thing you will have to keep in mind. Here is a code snippet showing how to use the class:

HWND hRichEdit = GetDlgItem(m_hParent, IDC_RICHEDIT);
CRichEditThemed::Attach(hRichEdit);

After CRichEditThemed::Attach() has been called, the Rich Edit control will be subclassed by CRichEditThemed until its destruction. The control is subclassed only and always in Windows XP (or above, as long as the UxTheme.dll library can be found). The control will be subclassed even if themes are not enabled at the time of creation: this allows proper theme support in case of a theme change while the parent window is still opened. The class also takes care of redrawing the control after it has been enabled/disabled or when its style changes (to alter the border after creation for example). The class will only draw the theme if the Rich Edit control has the WS_BORDER style as it supposes that only the edges of the control are themed (which should always be the case for any “editbox” theme that makes sense).

The only known limitation concerns the use of the “Auto HScroll” style in conjunction of both “Horizontal Scroll” and “Vertical Scroll”. When both scrollbars are displayed, the intersection of the two bars is drawn automatically by the control and, as a result, it doesn’t look as good as it would look in a native themed control. As most programmers prefer not to use “Auto HScroll” with Rich Edit controls displayed in dialog boxes (it often makes the control more difficult to use), this shouldn’t be too much of a problem (sorry if it is for you, however, the control will still look much better with the class than without). Apart from that, you shouldn’t notice any difference between native edit controls and your newly transformed Rich Edit controls. If you do, it’s a bug and it will need to be reported to be fixed.

Dissecting the Class

This section is for curious people who want to know how the class works internally (or, if you’re like me, you just want to check the code yourself before you include it in your software, which is just as justified :). The explanations given here are not needed to be able to use the class, however, they should give you enough insights to be able to use the same technique for other kinds of controls. A lot of comments have been added in the code. It should be self explanatory for the most part, however, if you’re not familiar with the concept of themes and non-client areas, then this section of the article should fill the gaps. The following tutorial has been written in chronological manner and is meant to be read from beginning to end, every sub-section supposing that the previous section has been read and understood.

Personal note: subclassing is one of my favourite ways of working (which you already know if you’re a user of Messenger Plus!). Great things can be done in no time with this technique and almost anything in Windows can be shortcut to attain one’s goal. It is thanks to subclassing that CRichEditThemed doesn’t need to be instantiated the “usual way”. Once created, the object monitors the actions of the Rich Edit control it’s been attached to. As the control is guaranteed to receive a WM_DESTROY message when its parent is destroyed, we know we can count on it to destroy the attached CRichEditThemed object as well. You don’t need to be familiar with subclassing techniques to follow this tutorial, however, you do need to know what a message loop is and how Windows communicates with the many windows/controls created in its environment.

Let’s start the tutorial with the public entry point of the class. As stated previously, yhe only public method of the CRichEditThemed is CRichEditThemed::Attach() and it is responsible for doing two things: first, it tries to import the functions it will require later on from the UxTheme library. If the user is running an older version of Windows, this library will not be available and CRichEditThemed won’t attach itself to the Rich Edit control. Then, after a couple of basic verifications, a new CRichEditThemed object is created:

bool CRichEditThemed::Attach(HWND hRichEdit)
{
   if(IsWindow(hRichEdit))
   {
      //Prevent double subclassing
      if(CRichEditThemed::m_aInstances.find(hRichEdit) == CRichEditThemed::m_aInstances.end())
      {
         //If this function fails, this version of Windows doesn't support themes
         if(InitLibrary())
         {
            //Note: the object will be automatically deleted when the richedit control dies
            CRichEditThemed *obj = new CRichEditThemed(hRichEdit);
            return true;
         }
      }
   }
   return false;
}

The creation of a new object involves two very distinct operations. First, we need to subclass the Rich Edit control with a call to SetWindowLong(). Subclassing is an operation consisting on replacing the message loop procedure of a window (also called winproc) with a new custom one. The new winproc is responsible for relaying all the messages it receives to the original procedure which gives the flexibility needed to override any message or silent some of them when needed.

Subclassing

The winproc is static function so we need a way to associate the Rich Edit control with its attached CRichEditThemed objec. For that purpose, an STL map is used, taking the handle of the control as key and a pointer to the CRichEditThemed object as element. Subclassing being a subject on its own, I will not spend more time talking about it. You are encouraged to check how this part of the class is working and get yourself a good book on the Windows API if the matter interests you.

The second operation performed by the constructor consists in verifying the current state of the Rich Edit control by calling CRichEditThemed::VerifyThemedBorderState(). This function is in charge of deciding whether or not a themed border should be drawn around the Rich Edit control, it is called every time the status of the control changes.

CRichEditThemed::CRichEditThemed(HWND hRichEdit)
   : m_hRichEdit(hRichEdit), m_bThemedBorder(false)
{
   //Subclass the richedit control, this way, the caller doesn't have to relay the messages
   //by itself
   m_aInstances[hRichEdit] = this;
   m_pOriginalWndProc = (WNDPROC)SetWindowLong(hRichEdit, GWL_WNDPROC,
      (LONG)&RichEditStyledProc);

   //Check the current state of the richedit control
   ZeroMemory(&m_rcClientPos, sizeof(RECT));
   VerifyThemedBorderState();
}
  • Archive

  • Categories

  • Blogroll