Base class: HWND_vpapa
This class provides a WndProc that adds a this pointer and calls a virtual function on
an object. It provides the mechanisms for subclassing an HWND.
See the User’s Guide for more discussion.
constructor, public
The constructor is unsurprising.
destructor, virtual, public
The destructor will unhook the class, to ensure that subsequent messages don’t get sent to a nonexistant object. The WinProc itself is a thunk that’s a member of this class, so the WinProc function pointer becomes invalid! Normally, the window owns this object so it won’t be destructed until after the window is destroyed, but usage can vary and the situation could be complex, so this is there just to be safe.
public
This calls the WndProc that the window had before it was subclassed by
a call to hook, or calls DefWndProc if there wasn’t
one.
This calls the -W form of the Win32 CallWindowProc or DefWindowProc.
This assumes that the current WndProc calling this is itself a Unicode form; that is, it is being sent
Unicode-style messages. This is correct if called from handle_message,
because hook installed it using the -W form of SetWindowLong.
public
This returns the original WndProc that was displaced by hook.
See also: call_old_wndproc
public
This returns the generated callback function that is a thunk to turn a WNDPROC or
WNDPROC_2 signature into a call to
handle_message on this instance.
This is the value that hook will use as the WndProc to install. If you want to create a "window class" or dialog box using this function directly, then follow these guidelines to correctly attach this instance with the HWND.
You can call set_window_handle at first opportunity to complete the process, but the hook will automatically set it when it processes the first message, so it is guarenteed to be set by the time handle_message is called.
Note that you need to specify the WndProc when registering the "window class" (wndclass), and then all
windows created will use the same WndProc. Unless the wndclass was designed for only a single window,
this is not suitable for this class, since you must use a different instance of message_tap for
each window created. So, you may want to call hook anyway, even in
cases when you designed the wndclass, and use a generic (dummy) WndProc in the wndclass. That is,
don’t try and avoid calling hook just because you are not subclassing an existing
window class.
For dialog boxes, on the other hand, you specify the DlgProc when you create the specific dialog box.
This mechanism works well in this case. However, you do not want to call DefWindowProc,
so should never call the base handle_message from your class’s override! Recall that a
Dialog Proc returns TRUE/FALSE (most of the time) to specify whether the message was handled. Your
handle_message should do this when used as a Dialog Proc. So use
Dialog_message_tap, which is
designed specifically for this and takes care of these details and others.
It is an error to call this function after calling set_window_handle (including implicitly setting the window handle upon getting the first message). This catches errors from duplicate use of the same instance.
public, virtual
This function is called by the WndProc of the window to which it is attached.
The sMSG structure (short MSG, since it is a subset (base class) of the
MSG structure) is used to pass the hwnd, message,
wParam, and lParam. Passing a structure rather than four parameters
is better design, and passing by reference is more efficient than re-pushing all the parameters with all the
forwarding going on.
The handling of WM_NCDESTROY, etc. as it relates to keeping up with this class
is performed higher up in the plumbing before it calls this virtual function. So, you are not compelled to chain
back to this base class implementation from your own class’s override. Actually, you can’t, due to technical
limitations1 on the mix-in techniques. So the way you
should end the derived class’s implementation of this function is with return call_old_wndproc(msg);
or return ratwin::window::DefWindowProc<wchar_t>(msg);
Likewise, this function does not deal with the pre-translation step. See hook_handler for a description of how these are handled invisibly to you.
Override this to do whatever you want, using the normal Win32 concepts of writing a WndProc. This is a Unicode
WndProc, in that it should receive Unicode versions of messages. This is because the hook
function used the -W form of SetWindowLong to install the thunk.
Overriding this virtual function in a derived class (or mix-in) is the main point of using the message_tap
class.
public
This function associates this object with the specified Window. Call this after calling Win32
CreateWindow or otherwise obtaining an HWND to a valid Window.
This function will “subclass” the window, pointing the WndProc back to this instance’s handle_message function and remembering the old WndProc.
It is an error to call this more than once.
See also: set_window_handle, unhook
private
This function is the invisible plumbing that allows handle_message to not worry about internal handling and concentrate on the outward functionality.
This is where processing really begins, and it will decide whether to do something very special (unhook on destroy), call pre_translate_message, or call handle_message.
It also catches all exceptions, so they may propagate out of handle_message or pre_translate_message
without problems, and calls the report_error function.
protected, data
This contains the message code number that is seen as the “last message”, and to unhook when it
is processed. It is set at construction time to WM_NCDESTROY, but it may be changed
if necessary.
public, virtual
This virtual function is called after the window and object are put
together. It fills the role of WM_CREATE or WM_INITDIALOG, which can’t
be used because the call to hook is made after the window has
been created.
Note that if you directly supply a message_tap as a WndProc, then
on_attach is called much earlier than WM_CREATE, so your
handle_message function will in this case
receive WM_CREATE. But if a window is created,
then hook is called, then handle_message
will never get a WM_CREATE because it was issued long before this class became involved.
So, if this function is used to interact with the Window, not just complete its own data setup, it needs to be aware of when it might be invoked. For other uses, it needs only count on the fact that it’s called at first oppertunity once the window handle and object are put together.
public, virtual
This is called when the Tomahawk pre_translate_message
message is processed. It basically does the same thing that you could do yourself by handling a
WM_TOMAHAWK message from within your handle_message
function, but it’s such a common case, and needed for the Dialog_message_tap
class, that it’s already separated out for you.
This should be implemented by derived classes, for those windows that need some kind of message transformation done before dispatching. Specifically, the window that is a modeless dialog box, and any window that uses an Accelerator Table.
For regular windows, call the Win32 primitive TranslateAccelerator here.
For modeless dialog boxes, call the Win32 primitive IsDialogMessage
(that is what Dialog_message_tap’s override does).
For either, return 1 if the translate call returned true, or return 2 if the translate call returned
false.
More generally, the return codes for this function are:
TranslateAccelerator or Win32 IsDialogMessage produce true.
The caller will see this value and know not to call Win32 DispatchMessage etc.TranslateAccelerator
or Win32 IsDialogMessage produce false. The caller will see this
value and stop searching for something to pre-translate the message,
and will continue with the other steps in the message pump (including
Win32 DispatchMessage).This base implementation always returns 0 and does nothing.
This is called by simple_message_pump::pre_translate.
public
This uses a simple and cheap test to verify that the this pointer is indeed pointing to a
non-destructed object of (or derived from) class message_tap.
This is used to trap Windows messages sent after the object is destructed, and to verify that untyped data (such as a generic lParam received in a message) correctly contains a pointer to an object as expected.
The test is not 100% reliable, as random memory could mimic the signature by coincedence, but is handy for spotting bugs and usage errors during development.
public
You are not expected to unhook a window explicitly, but to leave it hooked until the window is destroyed.
You may call this function to unhook the window, but it will be called automatically in the destructor or when
the HWND is closed.
To properly coordinate destroying the object, you must stop sending messages to it once the object
is destroyed! So, part of the shutdown is to attempt to unhook the window proc. If nothing else had hooked
the window after this class, then it restores the old pointer. Otherwise, (if force is
true) it supplies a DefWindowProc, breaking the chain.
It returns true if it gracefully restored the window to its prehooked state,
false if it had to be blunt and cut the chain (when force is true)
or failed (when force is false).
This is automatically called when a WM_NCDESTROY message is handled, which is
supposedly the last message processed. But who knows? Even if Microsoft’s docs are correct, what’s to stop
other code from sending messages directly? This unhooking hardens the code against this case. Also, derived
classes can change this behavior by changing the value in LastMessage.
A future version might go to greater lengths to ensure it really is called last, even with other activity going on.
See also: unhook_when_possible, ~message_tap
public
Calling this function sets a flag, which instructs the class to unhook itself as soon as it is able, after all objects that subclassed the window after this object have restored their WndProc pointers.
This does not change the fact that the object will be forcably unhooked when
WM_NCDESTROY is seen, as described under unhook.
See also: unhook, ~message_tap
Can’t call message_tap::handle_message:
In order for the derived class to automatically hook up the sibling that uses the function (message_tap
calls it) with the sibling that provides it (message_parliament defines it), only one sibling can define it.
Even making it pure virtual in message_tap isn’t enough—it cannot be defined in message_tap
at all. Without this careful arrangement, the derived class would have to implement the function too, with
a single line that calls the one in message_parliament. By defining it in one sibling only, the compiler realizes
that it is providing the meaning for all the other siblings that only call it.