////////////////////////////////////////////////////////////////////////////
// W32Wnd.h
//==========================================================================
// Created by 苦丁茶 (2004-10-01)
//
// 功能: 模拟MFC和WTL对Windows窗口框架的封装,提供消息映射机制。
// 参考资料:MFC、WTL消息映射机制
// 消息映射用法举例:
// BEGIN_MESSAGE(W32Button, W32Wnd)
// ON_MESSAGE(WM_LBUTTONDOWN, OnLButtonDown)
// ON_MESSAGE(WM_LBUTTONUP, OnLButtonUP)
// ON_MESSAGE(WM_ERASEBKGND, OnEraseBkgnd)
// END_MESSAGE()
// LRESULT OnEraseBkgnd(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
// {
// return 0;
// }
// 具体用法请参考W32Button.h所实现的支持自画Button类。
//==========================================================================#if !defined(AFX_W32WND_H__INCLUDED_)
#define AFX_W32WND_H__INCLUDED_#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000class W32Wnd
{
public:
HWND m_hWnd; ~W32Wnd()
{
if (m_pSuper)
{
UnsubclassWindow();
} m_hWnd = NULL;
} W32Wnd()
: m_hWnd(NULL)
, m_pSuper(NULL)
{
} HWND Create(HWND hWndParent, RECT& rcPos, LPCTSTR lpstrWndClass, LPCTSTR szWindowName = NULL,
DWORD dwStyle = 0, DWORD dwExStyle = 0,
UINT nID = 0, LPVOID lpCreateParam = NULL)
{
HWND hWnd = ::CreateWindowEx(dwExStyle, lpstrWndClass, szWindowName,
dwStyle, rcPos.left, rcPos.top, rcPos.right - rcPos.left,
rcPos.bottom - rcPos.top, hWndParent, (HMENU)nID,
::GetModuleHandle(NULL), lpCreateParam); SubclassWindow(hWnd); return hWnd;
} BOOL SubclassWindow(HWND hWnd)
{
// assert(NULL == m_hWnd);
::SetWindowLong(hWnd, GWL_USERDATA, (LONG)this);
m_pSuper = (WNDPROC)::SetWindowLong(hWnd, GWL_WNDPROC, (LONG)((WNDPROC)W32DefWindowProc));
m_hWnd = hWnd;
return TRUE;
} HWND UnsubclassWindow()
{
if (::IsWindow(m_hWnd))
{
::SetWindowLong(m_hWnd, GWL_WNDPROC, (LONG)((WNDPROC)m_pSuper));
}
HWND hWnd = m_hWnd;
m_hWnd = NULL;
m_pSuper = NULL;
return hWnd;
} BOOL ModifyStyle(DWORD dwRemove, DWORD dwAdd, UINT nFlags = 0 )
{
DWORD dwStyle = ::GetWindowLong(m_hWnd, GWL_STYLE);
DWORD dwNewStyle = (dwStyle & ~dwRemove) | dwAdd;
if (dwStyle == dwNewStyle)
return FALSE;
::SetWindowLong(m_hWnd, GWL_STYLE, dwNewStyle);
if (nFlags != 0)
{
::SetWindowPos(hWnd, NULL, 0, 0, 0, 0,
SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | nFlags);
}
return TRUE;
}
BOOL ModifyStyleEx(DWORD dwRemove, DWORD dwAdd, UINT nFlags = 0 )
{
DWORD dwStyle = ::GetWindowLong(m_hWnd, GWL_EXSTYLE);
DWORD dwNewStyle = (dwStyle & ~dwRemove) | dwAdd;
if (dwStyle == dwNewStyle)
return FALSE;
::SetWindowLong(m_hWnd, GWL_EXSTYLE, dwNewStyle);
if (nFlags != 0)
{
::SetWindowPos(hWnd, NULL, 0, 0, 0, 0,
SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | nFlags);
}
return TRUE;
}protected:
static LRESULT W32DefWindowProc(
HWND hWnd, // handle to window
UINT Msg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
)
{
W32Wnd * pWnd = (W32Wnd *)::GetWindowLong(hWnd, GWL_USERDATA);
if (pWnd)
{
return pWnd->W32DefWindowProc(Msg, wParam, lParam);
} return 0;
} LRESULT W32DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
LRESULT lRes = 0;
BOOL bRet = ProcessWindowMessage(m_hWnd, message, wParam, lParam, lRes, 0);
if (bRet)
{
return bRet;
} return m_pSuper(m_hWnd, message, wParam, lParam);
} virtual BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID = 0)
{
return FALSE;
} WNDPROC m_pSuper;
WNDPROC m_pParentSuper;};
// W32Wnd.h
//==========================================================================
// Created by 苦丁茶 (2004-10-01)
//
// 功能: 模拟MFC和WTL对Windows窗口框架的封装,提供消息映射机制。
// 参考资料:MFC、WTL消息映射机制
// 消息映射用法举例:
// BEGIN_MESSAGE(W32Button, W32Wnd)
// ON_MESSAGE(WM_LBUTTONDOWN, OnLButtonDown)
// ON_MESSAGE(WM_LBUTTONUP, OnLButtonUP)
// ON_MESSAGE(WM_ERASEBKGND, OnEraseBkgnd)
// END_MESSAGE()
// LRESULT OnEraseBkgnd(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
// {
// return 0;
// }
// 具体用法请参考W32Button.h所实现的支持自画Button类。
//==========================================================================#if !defined(AFX_W32WND_H__INCLUDED_)
#define AFX_W32WND_H__INCLUDED_#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000class W32Wnd
{
public:
HWND m_hWnd; ~W32Wnd()
{
if (m_pSuper)
{
UnsubclassWindow();
} m_hWnd = NULL;
} W32Wnd()
: m_hWnd(NULL)
, m_pSuper(NULL)
{
} HWND Create(HWND hWndParent, RECT& rcPos, LPCTSTR lpstrWndClass, LPCTSTR szWindowName = NULL,
DWORD dwStyle = 0, DWORD dwExStyle = 0,
UINT nID = 0, LPVOID lpCreateParam = NULL)
{
HWND hWnd = ::CreateWindowEx(dwExStyle, lpstrWndClass, szWindowName,
dwStyle, rcPos.left, rcPos.top, rcPos.right - rcPos.left,
rcPos.bottom - rcPos.top, hWndParent, (HMENU)nID,
::GetModuleHandle(NULL), lpCreateParam); SubclassWindow(hWnd); return hWnd;
} BOOL SubclassWindow(HWND hWnd)
{
// assert(NULL == m_hWnd);
::SetWindowLong(hWnd, GWL_USERDATA, (LONG)this);
m_pSuper = (WNDPROC)::SetWindowLong(hWnd, GWL_WNDPROC, (LONG)((WNDPROC)W32DefWindowProc));
m_hWnd = hWnd;
return TRUE;
} HWND UnsubclassWindow()
{
if (::IsWindow(m_hWnd))
{
::SetWindowLong(m_hWnd, GWL_WNDPROC, (LONG)((WNDPROC)m_pSuper));
}
HWND hWnd = m_hWnd;
m_hWnd = NULL;
m_pSuper = NULL;
return hWnd;
} BOOL ModifyStyle(DWORD dwRemove, DWORD dwAdd, UINT nFlags = 0 )
{
DWORD dwStyle = ::GetWindowLong(m_hWnd, GWL_STYLE);
DWORD dwNewStyle = (dwStyle & ~dwRemove) | dwAdd;
if (dwStyle == dwNewStyle)
return FALSE;
::SetWindowLong(m_hWnd, GWL_STYLE, dwNewStyle);
if (nFlags != 0)
{
::SetWindowPos(hWnd, NULL, 0, 0, 0, 0,
SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | nFlags);
}
return TRUE;
}
BOOL ModifyStyleEx(DWORD dwRemove, DWORD dwAdd, UINT nFlags = 0 )
{
DWORD dwStyle = ::GetWindowLong(m_hWnd, GWL_EXSTYLE);
DWORD dwNewStyle = (dwStyle & ~dwRemove) | dwAdd;
if (dwStyle == dwNewStyle)
return FALSE;
::SetWindowLong(m_hWnd, GWL_EXSTYLE, dwNewStyle);
if (nFlags != 0)
{
::SetWindowPos(hWnd, NULL, 0, 0, 0, 0,
SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | nFlags);
}
return TRUE;
}protected:
static LRESULT W32DefWindowProc(
HWND hWnd, // handle to window
UINT Msg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
)
{
W32Wnd * pWnd = (W32Wnd *)::GetWindowLong(hWnd, GWL_USERDATA);
if (pWnd)
{
return pWnd->W32DefWindowProc(Msg, wParam, lParam);
} return 0;
} LRESULT W32DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
LRESULT lRes = 0;
BOOL bRet = ProcessWindowMessage(m_hWnd, message, wParam, lParam, lRes, 0);
if (bRet)
{
return bRet;
} return m_pSuper(m_hWnd, message, wParam, lParam);
} virtual BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID = 0)
{
return FALSE;
} WNDPROC m_pSuper;
WNDPROC m_pParentSuper;};
/////////////////////////////////////////////////////////////////////////////
// Message map
#define BEGIN_MESSAGE(theClass, baseClass) \
public: \
virtual BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID = 0) \
{ \
BOOL br = ProcessMessage(hWnd, uMsg, wParam, lParam, lResult, dwMsgMapID); \
if (!br) return baseClass::ProcessWindowMessage(hWnd, uMsg, wParam, lParam, lResult, dwMsgMapID); \
return TRUE; \
} \
BOOL ProcessMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID = 0) \
{ \
BOOL bHandled = TRUE; \
hWnd; \
uMsg; \
wParam; \
lParam; \
lResult; \
bHandled; \
switch(dwMsgMapID) \
{ \
case 0:#define ALT_MSG(msgMapID) \
break; \
case msgMapID:#define ON_MESSAGE(msg, func) \
if(uMsg == msg) \
{ \
bHandled = TRUE; \
lResult = func(uMsg, wParam, lParam, bHandled); \
if(bHandled) \
return TRUE; \
}#define ON_MESSAGE_RANGE(msgFirst, msgLast, func) \
if(uMsg >= msgFirst && uMsg <= msgLast) \
{ \
bHandled = TRUE; \
lResult = func(uMsg, wParam, lParam, bHandled); \
if(bHandled) \
return TRUE; \
}#define ON_COMMAND(id, code, func) \
if(uMsg == WM_COMMAND && id == LOWORD(wParam) && code == HIWORD(wParam)) \
{ \
bHandled = TRUE; \
lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \
if(bHandled) \
return TRUE; \
}#define ON_COMMAND_ID(id, func) \
if(uMsg == WM_COMMAND && id == LOWORD(wParam)) \
{ \
bHandled = TRUE; \
lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \
if(bHandled) \
return TRUE; \
}#define ON_COMMAND_CODE(code, func) \
if(uMsg == WM_COMMAND && code == HIWORD(wParam)) \
{ \
bHandled = TRUE; \
lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \
if(bHandled) \
return TRUE; \
}#define ON_COMMAND_RANGE(idFirst, idLast, func) \
if(uMsg == WM_COMMAND && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \
{ \
bHandled = TRUE; \
lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \
if(bHandled) \
return TRUE; \
}#define ON_NOTIFY(id, cd, func) \
if(uMsg == WM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom && cd == ((LPNMHDR)lParam)->code) \
{ \
bHandled = TRUE; \
lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \
if(bHandled) \
return TRUE; \
}#define ON_NOTIFY_IDR(id, func) \
if(uMsg == WM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom) \
{ \
bHandled = TRUE; \
lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \
if(bHandled) \
return TRUE; \
}#define ON_NOTIFY_CODE(cd, func) \
if(uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code) \
{ \
bHandled = TRUE; \
lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \
if(bHandled) \
return TRUE; \
}#define ON_NOTIFY_RANGE(idFirst, idLast, func) \
if(uMsg == WM_NOTIFY && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \
{ \
bHandled = TRUE; \
lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \
if(bHandled) \
return TRUE; \
}#define CHAIN_MSG(theChainClass) \
{ \
if(theChainClass::ProcessWindowMessage(hWnd, uMsg, wParam, lParam, lResult)) \
return TRUE; \
}#define CHAIN_MSG_MEMBER(theChainMember) \
{ \
if(theChainMember.ProcessWindowMessage(hWnd, uMsg, wParam, lParam, lResult)) \
return TRUE; \
}#define CHAIN_MSG_ALT(theChainClass, msgMapID) \
{ \
if(theChainClass::ProcessWindowMessage(hWnd, uMsg, wParam, lParam, lResult, msgMapID)) \
return TRUE; \
}#define CHAIN_MSG_ALT_MEMBER(theChainMember, msgMapID) \
{ \
if(theChainMember.ProcessWindowMessage(hWnd, uMsg, wParam, lParam, lResult, msgMapID)) \
return TRUE; \
}#define CHAIN_MSG_DYNAMIC(dynaChainID) \
{ \
if(CDynamicChain::CallChain(dynaChainID, hWnd, uMsg, wParam, lParam, lResult)) \
return TRUE; \
}#define END_MESSAGE() \
break; \
default: \
assert(FALSE); \
break; \
} \
return FALSE; \
}
#define REFLECT_NOTIFICATIONS_EX() \
{ \
bHandled = TRUE; \
lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \
}#define OWNERDRAW_NOTIFICATIONS(message, wParam, lParam) \
{ \
if (WM_DRAWITEM == message) \
::SendMessage(((LPDRAWITEMSTRUCT)lParam)->hwndItem, OCM__BASE + message, wParam, lParam); \
}
#ifdef __AFX_H__
#define ON_WM_DRAWCHILDITEM() \
{ WM_DRAWITEM, 0, 0, 0, AfxSig_vww, \
(AFX_PMSG)(AFX_PMSGW)(void (AFX_MSG_CALL CWnd::*)(UINT, UINT))&OnDrawChildItem },
//#define OWNERDRAW_NOTIFICATIONS_MFC() \
// { WM_DRAWITEM, 0, 0, 0, AfxSig_vww, \
//(AFX_PMSG)(AFX_PMSGW)(void (AFX_MSG_CALL CWnd::*)(UINT, UINT))&::OnOwnerDrawNotify },#endif // __AFX_H__#endif // !defined(AFX_W32WND_H__INCLUDED_)
MFC中CWND和CDIALOG的代码是很纷繁复杂的。
WM_CREATE 可以的目标并非是要取代MFC和WTL、而在于在一些小项目中的轻量级解决方案。
我之所以写这东西,主要是因为我将WTL类的Button派生后,如果在派生类中使用了消息映射,那么基类的消息映射就会失效,而MFC却可以,以上源代码已经解决了此问题。
你说的问题的确存在,是因为创建窗口时,还没有HOOK那个DefWindowProc
考虑到我们在响应WM_CREATE时,往往只是想作些自己的初始化操作,因此模拟了一个WM_CREATE消息。但是不能使用CREATESTRUCT结构,请参考
http://blog.csdn.net/medie/archive/2005/06/08/390650.aspx
同时希望一起讨论更好的解决方案。
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.lpfnWndProc = (WNDPROC)W32Wnd::W32DefWindowProc;
class W32Wnd
{
public:
HWND m_hWnd; ~W32Wnd()
{
if (m_pSuper)
{
UnsubclassWindow();
} if (::IsWindow(m_hWnd))
{
::DestroyWindow(m_hWnd);
} m_hWnd = NULL;
} W32Wnd()
: m_hWnd(NULL)
, m_pSuper(NULL)
{
} HWND Create(HWND hWndParent, RECT& rcPos, LPCTSTR lpstrWndClass, LPCTSTR szWindowName = NULL,
DWORD dwStyle = 0, DWORD dwExStyle = 0,
UINT nID = 0, LPVOID lpCreateParam = NULL)
{
HWND hWnd = ::CreateWindowEx(dwExStyle, lpstrWndClass, szWindowName,
dwStyle, rcPos.left, rcPos.top, rcPos.right - rcPos.left,
rcPos.bottom - rcPos.top, hWndParent, (HMENU)nID,
::GetModuleHandle(NULL), this); return hWnd;
} BOOL SubclassWindow(HWND hWnd)
{
if (m_hWnd)
return FALSE; ::SetWindowLong(hWnd, GWL_USERDATA, (LONG)this);
m_pSuper = (WNDPROC)::SetWindowLong(hWnd, GWL_WNDPROC, (LONG)((WNDPROC)W32DefWindowProc));
m_hWnd = hWnd; return TRUE;
} HWND UnsubclassWindow()
{
if (::IsWindow(m_hWnd) && m_pSuper)
{
::SetWindowLong(m_hWnd, GWL_WNDPROC, (LONG)((WNDPROC)m_pSuper));
}
HWND hWnd = m_hWnd;
m_hWnd = NULL;
m_pSuper = NULL; return hWnd;
} static BOOL ModifyStyle(HWND hWnd, int nStyleOffset, DWORD dwRemove, DWORD dwAdd, UINT nFlags = 0)
{
DWORD dwStyle = ::GetWindowLong(hWnd, nStyleOffset);
DWORD dwNewStyle = (dwStyle & ~dwRemove) | dwAdd;
if (dwStyle == dwNewStyle)
return FALSE; ::SetWindowLong(hWnd, nStyleOffset, dwNewStyle);
if (nFlags != 0)
{
::SetWindowPos(hWnd, NULL, 0, 0, 0, 0,
SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | nFlags);
}
return TRUE;
} BOOL ModifyStyle(DWORD dwRemove, DWORD dwAdd, UINT nFlags = 0 )
{
return ModifyStyle(m_hWnd, GWL_STYLE, dwRemove, dwAdd, nFlags);
}
BOOL ModifyStyleEx(DWORD dwRemove, DWORD dwAdd, UINT nFlags = 0 )
{
return ModifyStyle(m_hWnd, GWL_EXSTYLE, dwRemove, dwAdd, nFlags);
} static LRESULT CALLBACK W32DefWindowProc(
HWND hWnd, // handle to window
UINT Msg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
)
{
if (WM_CREATE == Msg)
{
LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam;
W32Wnd* pWnd = (W32Wnd*)lpcs->lpCreateParams;
::SetWindowLong(hWnd, GWL_USERDATA, (LONG)pWnd);
pWnd->m_hWnd = hWnd;
} W32Wnd * pWnd = (W32Wnd *)::GetWindowLong(hWnd, GWL_USERDATA);
if (pWnd)
{
return pWnd->W32DefWindowProc(Msg, wParam, lParam);
} return ::DefWindowProc(hWnd, Msg, wParam, lParam);;
}protected: LRESULT W32DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
LRESULT lRes = 0;
BOOL bRet = ProcessWindowMessage(m_hWnd, message, wParam, lParam, lRes, 0);
if (bRet)
{
return bRet;
} if (W32Wnd::W32DefWindowProc == m_pSuper)
return ::DefWindowProc(m_hWnd, message, wParam, lParam); if (m_pSuper)
return CallWindowProc(m_pSuper, m_hWnd, message, wParam, lParam); return ::DefWindowProc(m_hWnd, message, wParam, lParam);
} virtual BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID = 0)
{
return FALSE;
} WNDPROC m_pSuper;};