Click here to Skip to main content
6,291,522 members and growing! (12,847 online)
Email Password   helpLost your password?
General Programming » DLLs & Assemblies » Hooks     Intermediate

A template singleton class for easy implementation of Windows hooks

By .dan.g.

Simplifying the implementation of Windows hooking through the use of a templatized manager class
VC6, VC7Win2K, WinXP, MFC, Dev
Posted:21 Mar 2003
Views:70,044
Bookmarked:40 times
Announcements
Loading...
 
Search    
Advanced Search
printPrint   Broken Article?Report       add Share
  Discuss Discuss   Recommend Article Email
16 votes for this article.
Popularity: 5.06 Rating: 4.20 out of 5
1 vote, 6.3%
1

2
2 votes, 12.5%
3
3 votes, 18.8%
4
10 votes, 62.5%
5

Introduction

I recently submitted a menu skinning article which used global Windows hooks to subclass all the menus in an application so that the standard Windows rendering of the menus could be overridden by the application.

The code for implementing the Windows hooks was fairly standard boilerplate code which I'd also used elsewhere and which I cut and pasted into the menu project.

It bugged me though that I still hadn't been able to see a solution whereby I didn't have to keep cutting and pasting the same code into new projects whenever I wanted a Windows hook.

Then, a few days ago, I read Shog9's excellent Balloon Help article about a replacement for MessageBox().

What particularly caught my eye was the use of thunking to pass a class member function as a callback to a Windows function which would normally only accept a global callback function. (I suggest you read the article if you want to know more about thunking.)

Note: the reason why this is so interesting is that many Windows global callback functions are a pain because there is often no facility to pass a user-defined piece of data (such as pointer to a class object) to allow the callback to be used in different contexts by different classes.

So here was a way to get around the global callback problem, albeit (after the excitement had died down) a rather tricky way.

You see, in this context, the thunk is effectively a piece of self-modifying code which, for someone who has always understood self-modifying code to be a big no-no, struck me as something I might want to avoid, since if it went wrong I wouldn't know how to fix it robustly.

However, due credit; it pointed me in the right direction for how to solve the global callback problem: templates.

I have to admit that I have been really tardy in getting to grips with templates. The principle issue is that without enough concrete experience of templates, I have tended to be unable to spot when they might be a useful solution to a given design problem, and without the benefit of implementing many template solutions I am unable to gain further insight into when best to use them, and so it goes on...

But once the seed had been planted, it all seemed so obvious.

By templatizing (is that a real word?) a base class, any class deriving from that base class could acquire its own set of static callback functions which would be entirely different to those of another derived class.

Granted, separate instances of the same class would still have to share a single function 'instance' but my particular experience of Windows hooks is that the classes I've written have always been singleton classes for the purpose of providing application wide hooking.

Note: if the base class was not templatized (there's that word again), then any static class functions would be the same, regardless of where you were in the class hierarchy, giving you no added benefit.

The implementation

With the design figured out, this turned out to be a fairly trivial task.

Essentially, I implemented a fairly standard singleton class and then added templates to it. (Note: as I understand it, there is no need to provide a default copy constructor if the singleton GetInstance() method is not public, but I welcome being proved wrong)

I also did the grunt work of adding the static functions for most of the Windows hooks, together with virtual equivalents that the derived class could override for the hooks it required.

Note: if you request a specific type of hook and then do not provide a handler for it, the base class will assert. This is similar to MFC's implementation of ownerdraw where CWnd::OnMeasureItem() and CWnd::OnDrawItem() assert if you forget to override them.

CHookMgr also make use of a partially implemented message tracing system which I propose to complete and then submit to CodeProject. What it does is simply take the pain out of mapping Windows message IDs to their string equivalents and extracting the WPARAMs and LPARAMs and converting whatever they represent to meaningful text.

Using the code

  • Add the following source files to your project:

    Note: in my demo project, these files are in a separate 'skinwindows' folder because they form a subset of a much larger skinning system, but there is no need for you to do the same.

    • CHookMgr (hookmgr.h/.cpp) - the templatized base manager
    • CWinClasses (winclasses.h/.cpp) - helper class for retrieving and testing window classes
    • ISMsgManager/ISMsgHandler (ismsgmanager.h/.cpp, ismsghandlers.h) - helper classes for converting MSGs to helpful string output. Note: these files can be dropped into any project where you need message trace output.
    • wclassdefines.h - convenient #defines for all window classes (and some others)
  • Derive your own hook manager class and provide overrides for whichever hook functions you need as follows:

    class CMyHookMgr : protected CHookMgr<CMyHookMgr>
    { 
       // so that the template class can see the protected c'tor
    
       friend class CHookMgr<CMyHookMgr>; 
                           
    public:
       virtual ~CMyHookMgr();
    
       static Initialize(UINT uMyFlags, ....)
       {
           // call base class Initialize to set up hooks required
    
           GetInstance().InitHooks(HM_CALLWNDPROC | HM_CBT | ...); 
           
           ... // any other initialization
    
       }
       
    protected:
       CMyHookMgr(); 
          
    protected:
       // virtual overrides
    
       virtual void OnCallWndProc(const MSG& msg);
       {
          ...
       }
       
       virtual BOOL OnCbt(int nCode, WPARAM wParam, LPARAM lParam)
       {   
          ...
       }
      
    };
  • Finally, at the appropriate point in your application startup code call:
    CMyHookMgr::Initialize(...);
  • That's it.

Copyright

The code is supplied here for you to use and abuse without restriction, except that you may not modify it and pass it off as your own.

History

  • 1.0 - Initial release

Notes

  • The sample application code is that of my menu skinning article, updated to use CHookMgr.
  • The source code is purely the 7 files noted above.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

.dan.g.


Member
.dan.g. is a former chartered structural engineer from the uk. He's been programming for 25 years since university and has been developing commercial windows software in Australia since 1998. He has a shaved head and assorted whiskers should you want to recognize him. [update] Dan has now grown his hair and removed his whiskers in an attempt to appear more normal. However he can still be recognized (in the summer months) by the aqua nail-polish he uses on his big toes. [/update]

For all his latest freeware visit http://www.abstractspoon.com/
Occupation: Software Developer (Senior)
Location: Australia Australia

Other popular DLLs & Assemblies articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 15 of 15 (Total in Forum: 15) (Refresh)FirstPrevNext
GeneralInformation Needed PinmemberExaltech8:52 28 Aug '04  
GeneralRe: Information Needed Pinmember.dan.g.20:24 7 Sep '04  
GeneralIs it possible to use instances of classes derived from templatized base classe across dlls ? PinmemberHawkeye5:42 4 Aug '04  
GeneralIs it possible to use instances of classes derived from templatized base classe across dlls ? PinmemberHawkeye5:42 4 Aug '04  
GeneralRe: Is it possible to use instances of classes derived from templatized base classe across dlls ? Pinmember.dan.g.1:54 8 Aug '04  
GeneralI want to ask a question ? Pinmembervihieu0:10 7 Apr '04  
GeneralRe: I want to ask a question ? Pinmember.dan.g.0:20 7 Apr '04  
GeneralHelp me Pinmembervihieu21:49 6 Apr '04  
GeneralRe: Help me Pinmember.dan.g.21:57 6 Apr '04  
GeneralRe: Help me Pinmembervihieu22:43 6 Apr '04  
GeneralRe: Help me PinmemberExaltech8:56 26 Aug '04  
GeneralRe: Help me Pinmember.dan.g.12:48 26 Aug '04  
GeneralRe: Help me PinmemberExaltech23:35 27 Aug '04  
GeneralSingletons, suggestions, congrats... PinmemberPaul Evans23:31 15 May '03  
GeneralRe: Singletons, suggestions, congrats... PinmemberDanG15:53 18 May '03  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 21 Mar 2003
Editor: Smitha Vijayan
Copyright 2003 by .dan.g.
Everything else Copyright © CodeProject, 1999-2009
Web16 | Advertise on the Code Project