CHookWnd
v1.08
Welcome to CHookWnd, a freeware MFC class to
support sub classing of any CWnd instance. The problem it fixes is that you cannot have 2
CWnd instances attached to the one HWND at the same time. This becomes a problem when you
want to derive one of your classes from 2 base classes which are both derived from CWnd
themselves. An example is, suppose you have 2 classes namely CBitmapMenuFrameWnd which is
derived from CFrameWnd and implements bitmap menus ALA Office 97 and CReBarFrameWnd which
implements command bar menus ALA IE4. When you are implementing your own CMainFrame class
you then have the problem that you can only derive from one of these classes and you must
copy the source from the other one into your class.
This class fixes this problem by sub classing the window before MFC
gets to it using a plug-in method. The code is based in part on a class developed by Paul
DiLascia namely "CSubclassWnd" for the MSJ magazine.
Features
- Simple and clean C++ interface. Just derive
your plug-in class from CHookWnd and override one virtual function to implement your
functionality.
- Multi-thread safe class.
- Unicode enabled, supports linking to MFC
statically and all code compiles cleanly at warning level 4.
Usage
- To use the class in your code include
hookwnd.cpp in your project and #include hookwnd.h in which ever of your modules needs to
make calls to the class.
- Derive your class from CHookWnd and override
the virtual function "WindowProc" just like you did when you wrote your first
Windows SDK app.
- Install the plug-in class by calling the Hook function in the class
you want to subclass.
- Your code will need to include MFC either statically or dynamically.
- You will also need to have afxmt.h in your precompiled header. The
code will warn you if you haven't this set up.
- To see the code in action have a look at the sample app which
installs 3 hooks, one to report on mouse messages, another to report on keyboard messages
and a third one just for good luck.
History
V1.0 (25 February 1999)
V1.01 (29 March 1999)
- Minor update to remove some unnecessary
comments from the code.
V1.02 (10 May 1999)
- Minor update to fix a small
bug in the demo app. No changes to the actual HookWnd code itself.
V1.03 (21 March 2003)
- Significant rework following comprehensive testing with
the Tray icon class.
- Fixed reported resource leaks caused by SetProp thanks
to BoundsChecker.
- Now includes copyright details in the source code
modules.
V1.04 (29 March 2003)
- A number of functions now use return values instead of
using VERIFY internally and not returning an error code.
- Made the Hook and UnHook methods virtual
- HWND -> CWnd mapping which uses the SetProp method now
uses ATOMs. This makes the lookup much faster.
- Made additional public methods of the class thread
safe.
- Fixed a bug in SizeOfHookChain, FirstInChain,
LastInChain and MiddleOfChain which would unnecessarily ASSERT if called for a
non hooked window
- Made destructor of the class virtual
- Fixed another SetProp resource leak in the "Remove"
method
- Addition of OnHook and OnUnHook virtual functions which
are called when a hook is being installed or removed.
V1.05 (31 March 2003)
- As pointed out by Martin Richter, the class is not
fully thread safe, quoting: The problem is that the thread executing the
WindowProc might enter the window Proc while a second thread is removing the
hook. There is only a rare chance, but the chance exists! You should write
this into your docs. As long as there is a chance to retrieve the window
property from the windows thread and to change it from a second thread in the
same time it is not threadsafe!". So basically you need to be aware of this
issue.
- Now includes the concept of auto deletion. This
allows heap allocated CHookWnds to be destroyed when the associated window is
destroyed. Again thanks to Martin Richter for this nice addition.
- Reworked the way the code handles calling the WNDPROC
hook. The code now instead the ATL mechanism of installing an assembly
language thunk. This results in much less code required to implement the hook.
From 435 lines to c. 300!
- The code also now uses the variable and method naming
convention as in the ATL implementation.
V1.06 (2 April 2003)
- First hook is now stored in a Windows property. This
avoids potential problems identifying the first hook in cases where the window
is already subclassed by a thunk such as ATL. Thanks to Martin Richter for
spotting this issue.
- Now displays a warning if code is compiled on a non X86
compiler
- Various code tidy up's following testing with trayicon
class.
- Fixed a bug where only 2 hooks in the chain of hooks
being called.
- Went back to the Hook / Unhook naming convention
- Addition of various public helper methods
V1.07 (17 April 2003)
- Fixed a level 4 unreferenced warning in
CHookWnd::WindowProc. Thanks to Frank Fesevur for reporting this.
V1.08 (1 November 2004)
- Fixed a number of warnings when the code is compiled using the Detect 64 bit portability issues in Visual Studio .Net. Please note that the code as it currently stands does not compile to native IA64 or AMD64 code yet.
API
Reference
The API consists of the following member functions of the class
CHookWnd
CHookWnd::CHookWnd
CHookWnd::~CHookWnd
CHookWnd::Subclass
CHookWnd::Unsubclass
CHookWnd::ProcessWindowMessage
CHookWnd::IsHooked
CHookWnd::FirstInChain
CHookWnd::LastInChain
CHookWnd::MiddleOfChain
CHookWnd::SizeOfHookChain
CHookWnd::CHookWnd
BOOL CHookWnd::CHookWnd();
Remarks
Standard C++ constructor.
CHookWnd::~CHookWnd
CHookWnd::~CHookWnd();
Remarks
Standard C++ destructor.
CHookWnd::Subclass
BOOL CHookWnd::Subclass(CWnd* pWnd);
BOOL CHookWnd::Subclass(HWND
hWnd);
Parameters
pWnd The CWnd instance which you want to subclass.
hWnd The HWND which you want to subclass
Remarks
Call this member function to subclass the HWND currently
sub classed
by the MFC CWnd instance "pWnd". Messages will be routed to the WindowProc
method of this instance prior to being passed of to any other installed CHookWnd's in the
chain before eventually being routed back to standard MFC message maps..
See Also
CHookWnd::UnHook
CHookWnd::Unsubclass
HWND CHookWnd::Unsubclass();
Remarks
Removes this instance from the chain of hooks which are handling the
sub classing.
See Also
CHookWnd::Hook
CHookWnd::ProcessWindowMessage
virtual BOOL ProcessWindowMessage(HWND hWnd,
UINT nMsg, WPARAM wParam, LPARAM lParam,
LRESULT& lResult);
Return Value
TRUE if the message was handled otherwise FALSE.
Parameters
hWnd Specifies
the HWND the message is for
nMsg Specifies
the Windows message to be processed.
wParam Provides
additional information used in processing the message. The parameter value depends on the
message.
lParam Provides
additional information used in processing the message. The parameter value depends on the
message
lResult The return value from the
window procedure if handled
Remarks
This is the function which you should override in your derived class
to implement your plug-in functionality. This would appear structured very similar to an
SDK window proc. For any messages which you do not handle, you should call Default for
these.
CHookWnd::IsHooked
BOOL CHookWnd::IsHooked() const;
Return Value
TRUE if this instance is currently hooking a CWnd otherwise FALSE.
Remarks
This function is used internally in CHookWnd as an assert in
functions where you first should have call Hook.
CHookWnd::FirstInChain
BOOL CHookWnd::FirstInChain() const;
Return Value
TRUE if this instance is the first in the chain of CHookWnd's
handling sub classing otherwise FALSE.
CHookWnd::LastInChain
BOOL CHookWnd::LastInChain() const;
Return Value
TRUE if this instance is the last in the chain of CHookWnd's
handling sub classing otherwise FALSE.
CHookWnd::MiddleOfChain
BOOL CHookWnd::MiddleOfChain() const;
Return Value
TRUE if this instance is the somewhere in the chain but is not the
first or last item in it.
CHookWnd::SizeOfHookChain
int CHookWnd::SizeOfHookChain() const;
Return Value
The number of CHookWnd's in the chain which is currently handling
the sub classing.
PLANNED
ENHANCEMENTS
- Implement support for installing hooks at the end and middle of the
hook chain.
- Provide a better sample app. At the moment, it's very much a test
program which tests all of the functions.
- If you have any other suggested
improvements, please let me know so that I can incorporate them into the next release.
CONTACTING
THE AUTHOR
PJ Naughter
Email: pjna@naughter.com
Web: http://www.naughter.com
1 November 2004