Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Here is a <em>breif summary</em> of the code I use to do this in the <a href="http://www.zeusedit.com" rel="noreferrer">Zeus</a> programmer's editor:</p> <p><strong>Step 1:</strong> Define a couple of message structure to hold the Windows message details:</p> <pre><code>typedef struct { MSG msg; LRESULT lResult; } xMessage; struct xWM_COMMAND { HWND hwnd; UINT Msg; WORD ItemID; WORD NotifyCode; HWND Ctl; LRESULT lResult; }; //-- unpack a message buffer #define MSG_UNPACK(var, id, msg) x##id *var = (x##id *)(msg); </code></pre> <p><strong>Step 2:</strong> Define a base window class with a few special methods:</p> <pre><code>class xWindow { protected: //-- windows callback function static LRESULT CALLBACK wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); //-- a message dispatch method void dispatch(HWND hwnd, UINT uMessageID, WPARAM wParam, LPARAM lParam, LRESULT &amp;Result); //-- method for command message dispatching virtual void dispatchToCmdMap(xMessage *pMessage); //-- method for windows message dispatching virtual void dispatchToMsgMap(xMessage *pMessage); }; </code></pre> <p><strong>Step 3:</strong> Define a few macros to do the dispatching of the Windows messages:</p> <pre><code>#define BEGIN_MSG_MAP \ protected: \ virtual void dispatchToMsgMap(xMessage *msg)\ { \ if (msg-&gt;msg.message == WM_NULL) \ { \ return; \ } #define MSG_HANDLER(meth, wm_msg) \ else if (msg-&gt;msg.message == wm_msg) \ { \ this-&gt;meth(msg); \ return; \ } #define END_MSG_MAP(base) \ else if (msg-&gt;msg.message == WM_COMMAND) \ { \ this-&gt;dispatchToCmdMap(msg); \ return; \ } \ else if (msg-&gt;msg.message == WM_NOTIFY) \ { \ this-&gt;dispatchToNotifyMap(msg); \ return; \ } \ \ base::dispatchToMsgMap(msg); \ }; #define BEGIN_CMD_MAP \ virtual void dispatchToCmdMap(xMessage *msg)\ { \ MSG_UNPACK(Cmd, WM_COMMAND, msg); \ \ if (Cmd-&gt;ItemID == 0) \ { \ /* not allowed */ \ } #define CMD_HANDLER(meth, cmd_id) \ else if (Cmd-&gt;ItemID == cmd_id) \ { \ this-&gt;meth(Cmd-&gt;ItemID); \ } #define END_CMD_MAP(base) \ else \ { \ base::dispatchToCmdMap(msg); \ } \ }; </code></pre> <p><strong>Step 4:</strong> Define the dispatcher method:</p> <pre><code>void xWindow::dispatch(HWND, UINT uMessageID, WPARAM wParam, LPARAM lParam, LRESULT &amp;Result) { xMessage message; //-- build up a message packet message.msg.message = uMessageID; message.msg.wParam = wParam; message.msg.lParam = lParam; message.lResult = 0; //-- dispatch the message this-&gt;dispatchToMsgMap(&amp;message); } </code></pre> <p><strong>Step 5:</strong> Define the static window procedure method (<strong>NOTE:</strong> this method will need to be used as the Window procedure of the window class when the class is first registered):</p> <pre><code>LRESULT CALLBACK xWindow::wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { LRESULT lResult = 0; //-- look for the creation message if (msg == WM_NCCREATE) { CREATESTRUCT *pCreateData = (CREATESTRUCT*)lParam; //-- get the window object passed in xWindow *pWindow = (xWindow)pCreateData-&gt;lpCreateParams; if (pWindow) { //-- attach the window object to the hwnd SetWindowLong(hwnd, pWindow); //-- let the window object dispatch the message pWindow-&gt;dispatch(hwnd, msg, wParam, lParam, lResult); } else { //-- leave the message to windows lResult = DefWindowProc(hwnd, msg, wParam, lParam); } } else if (hwnd) { //-- get the object attached to the hwnd xWindow *pWindow = (xWindow *)GetWindowLong(hwnd); //-- check to see if we have an object window attached to the handle if (pWindow) { //-- let the window object dispatch the message pWindow-&gt;dispatch(hwnd, msg, wParam, lParam, lResult); } else { //-- leave the message to windows lResult = ::DefWindowProc(hwnd, msg, wParam, lParam); } } return lResult; } </code></pre> <p>Now, using this <em>base class</em> it is possible to define a new window class that will look like this:</p> <pre><code>class MyWindow : public xWindow { protected: //-- the WM_COMMAND message handlers virtual void onAdd(int); virtual void onDelete(int); //-- the WM_CLOSE message handler virtual void onClose(xMessage *pMessage); //-- the WM_SIZE message handler virtual void onSize(xMessage *pMessage); public: //-- ctor and dtor MyWindow(); virtual ~MyWindow(); BEGIN_MSG_MAP //-- command message handlers CMD_HANDLER(onAdd , IDPB_ADD ) CMD_HANDLER(onDelete, IDPB_DELETE) //-- other message handling MSG_HANDLER(onClose , WM_CLOSE) MSG_HANDLER(onSize , WM_SIZE ) END_MSG_MAP(xWindow) }; </code></pre> <p><strong>Edit: How this code works.</strong></p> <p>The secret to understanding how this code works is to remember the <em>wndProc</em> in the <em>xWindow</em> class is nothing but a <em>Win32</em> Window procedure passed to <em>RegisterClassEx</em> when the Win32 Window is registered. </p> <p>Now if you look at the <em>wndProc</em> code you will see it does a bit of setting up and checking but generally it does nothing more than send the Windows message to the <em>dispatch</em> method. </p> <p>The <em>dispatch</em> method is even simpler as it does nothing more than pack the Windows message into an <em>easy to move</em> structure and then sends it off to the <em>dispatchToMsgMap</em> method.</p> <p>Now look at the <em>MyWindow</em> class an you will see this code:</p> <pre><code>BEGIN_MSG_MAP //-- command message handlers CMD_HANDLER(onAdd , IDPB_ADD ) CMD_HANDLER(onDelete, IDPB_DELETE) //-- other message handling MSG_HANDLER(onClose , WM_CLOSE) MSG_HANDLER(onSize , WM_SIZE ) END_MSG_MAP(xWindow) </code></pre> <p>This code is just using the macros defined earlier. If you take a close look at these macros you will see the code above is in fact creating a <em>dispatchToMsgMap</em> method. This is the exact same <em>dispatchToMsgMap</em> method that was called by the <em>dispatch</em> method. </p> <p>I know this method of handling Windows messages does work as I use this exact same approach in the <a href="http://www.zeusedit.com" rel="noreferrer">Zeus for Windows</a> editor.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload