////////////////////////////////////////////////////////////////////////////
// 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;};

解决方案 »

  1.   


    /////////////////////////////////////////////////////////////////////////////
    // 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_)
      

  2.   

    WM_NCCREATE, WM_CREATE 这两个消息好像无法抓到吧。
      

  3.   

    要完全实现MFC,而又要摆脱那些“Afx”,你要做的事情还有很多啊。
    MFC中CWND和CDIALOG的代码是很纷繁复杂的。
      

  4.   

    WM_NCCREATE 没试验过 
    WM_CREATE 可以的目标并非是要取代MFC和WTL、而在于在一些小项目中的轻量级解决方案。
    我之所以写这东西,主要是因为我将WTL类的Button派生后,如果在派生类中使用了消息映射,那么基类的消息映射就会失效,而MFC却可以,以上源代码已经解决了此问题。
      

  5.   

    to everandforever(Forever) 
    你说的问题的确存在,是因为创建窗口时,还没有HOOK那个DefWindowProc
    考虑到我们在响应WM_CREATE时,往往只是想作些自己的初始化操作,因此模拟了一个WM_CREATE消息。但是不能使用CREATESTRUCT结构,请参考
    http://blog.csdn.net/medie/archive/2005/06/08/390650.aspx
    同时希望一起讨论更好的解决方案。
      

  6.   

    改进后的W32Wnd代码,支持WM_CREATE消息通知,在注册窗口类时这样写
    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;};