Hier ist ein kurze Zusammenfassung des Codes, den ich dazu verwende, in der Zeus Editor für Programmierer:
Schritt 1: Definieren Sie eine Reihe von Nachrichtenstrukturen, um die Details der Windows-Nachrichten zu speichern:
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);
Schritt 2: Definieren Sie eine Basisklasse für Fenster mit einigen speziellen Methoden:
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 &Result);
//-- method for command message dispatching
virtual void dispatchToCmdMap(xMessage *pMessage);
//-- method for windows message dispatching
virtual void dispatchToMsgMap(xMessage *pMessage);
};
Schritt 3: Definieren Sie einige Makros, die das Dispatching der Windows-Nachrichten übernehmen:
#define BEGIN_MSG_MAP \
protected: \
virtual void dispatchToMsgMap(xMessage *msg)\
{ \
if (msg->msg.message == WM_NULL) \
{ \
return; \
}
#define MSG_HANDLER(meth, wm_msg) \
else if (msg->msg.message == wm_msg) \
{ \
this->meth(msg); \
return; \
}
#define END_MSG_MAP(base) \
else if (msg->msg.message == WM_COMMAND) \
{ \
this->dispatchToCmdMap(msg); \
return; \
} \
else if (msg->msg.message == WM_NOTIFY) \
{ \
this->dispatchToNotifyMap(msg); \
return; \
} \
\
base::dispatchToMsgMap(msg); \
};
#define BEGIN_CMD_MAP \
virtual void dispatchToCmdMap(xMessage *msg)\
{ \
MSG_UNPACK(Cmd, WM_COMMAND, msg); \
\
if (Cmd->ItemID == 0) \
{ \
/* not allowed */ \
}
#define CMD_HANDLER(meth, cmd_id) \
else if (Cmd->ItemID == cmd_id) \
{ \
this->meth(Cmd->ItemID); \
}
#define END_CMD_MAP(base) \
else \
{ \
base::dispatchToCmdMap(msg); \
} \
};
Schritt 4: Definieren Sie die Dispatcher-Methode:
void xWindow::dispatch(HWND, UINT uMessageID, WPARAM wParam,
LPARAM lParam, LRESULT &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->dispatchToMsgMap(&message);
}
Schritt 5: Definieren Sie die statische Fensterprozedurmethode ( HINWEIS: diese Methode muss als Window-Prozedur der Fensterklasse verwendet werden, wenn die Klasse zum ersten Mal registriert wird):
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->lpCreateParams;
if (pWindow)
{
//-- attach the window object to the hwnd
SetWindowLong(hwnd, pWindow);
//-- let the window object dispatch the message
pWindow->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->dispatch(hwnd, msg, wParam, lParam, lResult);
}
else
{
//-- leave the message to windows
lResult = ::DefWindowProc(hwnd, msg, wParam, lParam);
}
}
return lResult;
}
Nun, mit diesem Basisklasse ist es möglich, eine neue Fensterklasse zu definieren, die wie folgt aussehen wird:
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)
};
Edit: Wie dieser Code funktioniert.
Um zu verstehen, wie dieser Code funktioniert, müssen Sie sich an die wndProc en el xFenster Klasse ist nichts anderes als eine Win32 Fensterprozedur übergeben an RegisterClassEx wenn das Win32-Fenster registriert ist.
Wenn Sie sich nun die wndProc Code werden Sie sehen, dass er einige Einstellungen und Prüfungen vornimmt, aber im Allgemeinen tut er nichts weiter, als die Windows-Nachricht an die Versand Methode.
En Versand Methode ist noch einfacher, da sie nichts weiter tut, als die Windows-Nachricht in eine leicht zu bewegen Struktur und sendet sie dann an die dispatchToMsgMap método.
Sehen Sie sich nun die MeinFenster Klasse und Sie werden diesen Code sehen:
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)
Dieser Code verwendet lediglich die zuvor definierten Makros. Wenn Sie sich diese Makros genau ansehen, werden Sie feststellen, dass der obige Code tatsächlich eine dispatchToMsgMap Methode. Dies ist genau die gleiche dispatchToMsgMap Methode, die durch den Aufruf der Versand Methode.
Ich weiß, dass diese Methode zur Behandlung von Windows-Nachrichten funktioniert, da ich genau den gleichen Ansatz in der Zeus für Windows Herausgeber.