Click here to Skip to main content
Click here to Skip to main content
Go to top

WTL wrappers for WinMain's CodeMax syntax highlighting edit control

, 28 May 2001
Rate this:
Please Sign up or sign in to vote.
An article on the CodeMax editing control.

Sample Image

Introduction

When I first started writing this article, I had planned only to illustrate how to use the CodeMax syntax editing control wrappers I had created. I quickly found though, that I would also need to explain what it was I was doing in the demo application itself. So, instead of simply releasing the set of wrappers and a demo program, I decided to write a small article on the CodeMax wrappers, meanwhile expanding on some of the things I discovered while writing an MDI application using the Windows Template Library (WTL).

Let me start by telling you a little about how the sample code is laid out. If you've ever used the WTL wizard, you are familiar with the fact that it shoves all of the application's code into a set of header files. While I like to put my components into a single header file, to simplify integration, I hate to work with application code that is set-up in this manner. So, the first thing I did was split the code up into its respective source and header files. This gives a much cleaner implementation, and in my opinion, it is easier to read and edit.

Unfortunately, by doing this, I destroyed any chance I might have had of using the 'Add Windows Message Handler' wizard that Visual C++ was nice enough to provide. But, I also opted to use the 'extended' message map (BEGIN_MSG_MAP_EX, etc.) that WTL implements, which is also incompatible with the above-mentioned wizard. So, in the end, it would have been useless anyway.

The CodeMax Wrappers

The wrappers that I included encapsulate almost everything CodeMax has to offer. I say, almost, because I have yet to implement a central way of updating the CodeMax control's settings (when you run the sample, you will see what I mean).

The classes are all defined in the cmaxwtl.h file, and all of the classes are declared within the cmax namespace.

  • CodeMaxLibrary - Wraps all the basic CodeMax library calls, including registration and unregistration.
  • CodeMaxControl - Wraps the CodeMax control itself.
  • CodeMaxControlNotifications - Base class that allows you to handle notification messages from the CodeMax control (reflected or not).
  • CodeMaxControlCommands - Base class that handles the standard CodeMax commands (cut, copy, paste, etc.).
  • UndoBlock - Simple undo helper, allows you to group a series of undoable commands as one.

How to use the wrappers

First, you will need to declare an instance of the CodeMaxLibrary object and initialize it.

// ...

CodeMaxLibrary cmaxlib;

if ( !cmaxlib.Initialize () ) {

    ATLTRACE ( _T ( "CodeMax initialization failed!\n" ) );
    
    return 0; // bail...

}     

// ...

While it does not really matter where you do this, it's best to do it early off in the game so as to avoid any hassles later on. I recommend you do it in your WinMain function or the Run function that the wizard declares for you.

Next, you will need to modify your 'view' or client window, and derive it from the CodeMaxControl class.

Note that you need to use DECLARE_WND_SUPERCLASS() in the class declaration. This allows you to superclass the window, and thereby create a window based on the CodeMax control with a new window procedure that you will later define.

class CCodeMaxWTLSampleView : 
      public CWindowImpl < CCodeMaxWTLSampleView, CodeMaxControl >
{  
   // ...
   
public:

   // Superclass the CodeMax control   

   DECLARE_WND_SUPERCLASS ( NULL, CodeMaxControl::GetWndClassName () )
   
   // ...

}

I have also included the CodeMaxControlNotifications class to allow you to handle the CodeMax control's notification messages. This class can be used as a base for either the view or the main frame. In the sample, I use it in the view, but there may be some good reasons to use it in the application's main frame. If you do decide to use it in the main frame of the application, be sure to forward all the child window's messages to the main frame. In the case of an MDI application, placing a call to FORWARD_NOTIFICATIONS() in your MDI child's message map will do this.

Our new view, with notification handling, would look something like this:

class CCodeMaxWTLSampleView : public CWindowImpl < CCodeMaxWTLSampleView, CodeMaxControl >,
                              public CodeMaxControlNotifications < CCodeMaxWTLSampleView >
{
   // ...
   
public:

   // Superclass the CodeMax control   

   DECLARE_WND_SUPERCLASS ( NULL, CodeMaxControl::GetWndClassName () )
   
  // ...

};

Of course, you still have to reflect the notification messages back to the view from its parent window and chain the notification class' message map in your view's message map.

Reflection

In MFC, we did not have to really worry about reflecting messages. All one needed to do was subclass a window or control, and all of its notification messages would be reflected back for you. In WTL, this is not the case, you actually have to reflect the messages back from the parent window to its child. Luckily, this is not all that difficult, since ATL provides us with a quick and simple method of doing this. All you have to do is remember to add REFLECT_NOTIFICATIONS() to your parent window's message map. The beauty of this macro is that it allows you to handle everything about a window within the class that defines it.

The following piece of code demonstrates how to reflect messages back to the child that sent them:

class CChildFrame : public CMDIChildWindowImpl < CChildFrame >
{ 
  
   // ...
   
   BEGIN_MSG_MAP_EX ( CChildFrame )
   
      // ...
      //
      // Notification handlers
      //      

      // Reflect all the WM_NOTIFY messages to the client window

      REFLECT_NOTIFICATIONS ()
      
   END_MSG_MAP ()
   
   // ...
  
};

Message Changing

One of the most powerful concepts offered for window centric programming, by ATL and WTL alike, is message changing. This allows you to divide the already flexible message-handling scheme into smaller, more manageable parts. What this enabled me to do was provide CodeMaxControlCommands, a class that handles all of Windows' standard command messages. Basic handling is provided for commands such as Cut & Paste and Undo/Redo.

To reap the benefit of this class, you can either derive your view from it, or as with the notification handler class, the main frame window. As you may have gathered, this is not all that you have to do. You must also make sure that the command messages are passed down from the main frame to the view. Remember that if you are using an MDI interface, the messages must first pass through the child frame before they arrive at the view.

The following macros will make this possible (both of which are defined in atlframe.h):

  • CHAIN_MDI_CHILD_COMMANDS()
  • CHAIN_CLIENT_COMMANDS()

The first one goes in the main frame's message map, where it simply passes control to the active MDI child window. The second picks up the control from the main frame and passes it to the child's client control (namely the view).

The main frame window:

class CMainFrame : public CMDIFrameWindowImpl < CMainFrame >, 
                   public CUpdateUI < CMainFrame >,
                   public CMessageFilter, 
                   public CIdleHandler
{ 
   
   // ...
   
   BEGIN_MSG_MAP_EX ( CMainFrame )
   
      // ...
      //
      // Chained Message maps
      //        

      // Pass all unhandled WM_COMMAND messages to the active child window
      CHAIN_MDI_CHILD_COMMANDS ()
         // other chains...
     
   END_MSG_MAP ()
   
   // ...
  
};

The child frame window:

class CChildFrame : public CMDIChildWindowImpl < CChildFrame >
{ 
   // ...
  
   BEGIN_MSG_MAP_EX ( CChildFrame )
   
      // ...
      //
      // Chained Message maps
      //
      
      // Pass all unhandled WM_COMMAND messages to the client window or 'view'

      CHAIN_CLIENT_COMMANDS ()
         // other chains...
      
      // ...
   
   END_MSG_MAP ()
   
   // ...
   
};

We are now free to handle any or all of the command messages in the view.

The final rendition of our view would look something like this:

class CCodeMaxWTLSampleView : 
      public CWindowImpl < CCodeMaxWTLSampleView, CodeMaxControl >,
      public CodeMaxControlNotifications < CCodeMaxWTLSampleView >,
      public CodeMaxControlCommands < CCodeMaxWTLSampleView > 
{  
   // ...

public:

   // Superclass the CodeMax control   
   DECLARE_WND_SUPERCLASS ( NULL, CodeMaxControl::GetWndClassName () )
   
   // View's message map
   BEGIN_MSG_MAP_EX ( CCodeMaxWTLSampleView )    
   
      // ...
      //
      // Chained Message maps
      //

      // Make sure that the notification
      // and default message handlers get a crack at the messages

      CHAIN_MSG_MAP_ALT ( CodeMaxControlNotifications < CCodeMaxWTLSampleView >, 
           CMAX_REFLECTED_NOTIFY_CODE_HANDLERS )
      CHAIN_MSG_MAP_ALT ( CodeMaxControlCommands < CCodeMaxWTLSampleView >, 
           CMAX_BASIC_COMMAND_ID_HANDLERS )
      
   END_MSG_MAP ()    
        
   // ...
}

The End

Well, that about wraps it up (pardon the pun); if I've forgotten something, please let me know. For those of you doing the MFC thing, I have full MFC versions of the wrappers as well... if you'd like them, just drop me a line; if the demand is high enough I'll post them.

Wanted

  1. Loosely tied mechanism to update the CodeMax control from outside the wrapper classes.
  2. A way to load and modify custom languages from disk. (I have included the beginnings of my attempt to do this, but be warned, it breaks so many rules, it's unreal. I am positive there is a more elegant way of doing it.)

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Ben Burnett
Student University of Lethbridge
Canada Canada
Ben was born in New Zealand and grew up in Mexico; however, he has lived in Canada for most of his adult life. He has traveled to a few places in Canada so far: British Columbia, Saskatchewan, Manitoba, Ontario and Nova Scotia, but has only ever lived in Alberta — all over Alberta. From Lethbridge to Calgary to Fort McMurray: he has seen most of what the province has to offer. He has also left the comfort of his—at the time—home country and gone abroad. In recent history he has been in China, New Zealand, the US, Central America and back to Canada (where he now resides).
 
He completed a degree at the University of Lethbridge, in Computer Science; worked for the University of Wisconsin-Madison in the Computer Sciences Department as a Systems Programmer for the Condor Research Project[^]; and is currently completing another degree at the University of Lethbridge, once again, in Computer Science.
 
Ben has been known to enjoy reading, watching movies, playing console games, and learning everything he can about computers. And, more importantly, with regards to his character: does not usually speaks about himself in the third person.

Comments and Discussions

 
QuestionRaul PinmemberMember 44252587-Sep-09 13:50 
Generalhyper link Pinmemberhero in the forest28-Oct-05 3:09 
QuestionHow to get the line number clicked by mouse? Pinmemberfreehawk27-Jan-04 23:43 
GeneralTry Scintilla!!! Pinmemberideras11-Jul-03 7:54 
GeneralRe: Try Scintilla!!! PinmemberBen Burnett11-Jul-03 8:36 
GeneralVC7 Build Errors: MIDL2096 : duplicated attribute Pinsusssoultech3-Jul-03 5:42 
GeneralRe: VC7 Build Errors: MIDL2096 : duplicated attribute Pinmemberwps884825-Nov-03 21:26 
Questionhow can i highlight .... PinsussAnonymous11-Mar-03 22:59 
GeneralUnicode Pinmemberdirkp22-Dec-02 12:52 
GeneralRe: Unicode PinmemberGil Rivlis22-Jan-03 8:19 
GeneralGet a copy of CodeMax PinmemberAlexpro9-Jun-02 7:26 
GeneralRe: Get a copy of CodeMax PinmemberAlexpro9-Jun-02 7:46 
GeneralCodeMax is retiring PinmemberUwe Keim1-Oct-01 19:20 
GeneralRe: CodeMax is retiring PinmemberBen Burnett2-Oct-01 14:19 
GeneralRe: CodeMax is retiring PinmemberFrederic Rudman22-Jan-02 6:10 
GeneralRe: CodeMax is retiring PinmemberMJ23-Jan-02 13:15 
GeneralRe: CodeMax is retiring PinmemberPhilippe Lhoste18-Mar-02 2:21 
GeneralError: File not found editx.tlb PinmemberAnonymous3-Aug-01 1:44 
GeneralRe: Error: File not found editx.tlb PinmemberAcheroy Jean7-Jun-02 1:58 
GeneralRe: Error: File not found editx.tlb Pinmemberlonedfx1-Mar-03 15:36 
GeneralError 404 PinmemberPaul Barrass30-May-01 6:48 
GeneralRe: Error 404 PinmemberBen Burnett3-Jun-01 19:24 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140926.1 | Last Updated 29 May 2001
Article Copyright 2001 by Ben Burnett
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid