共享一份模拟MFC和WTL对Windows窗口框架代码 有兴趣者请跟帖

medie 2005-06-08 04:41:11
////////////////////////////////////////////////////////////////////////////
// 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 > 1000

class 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;

};

...全文
88 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
medie 2005-06-17
  • 打赏
  • 举报
回复
改进后的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;

};

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

目标并非是要取代MFC和WTL、而在于在一些小项目中的轻量级解决方案。
我之所以写这东西,主要是因为我将WTL类的Button派生后,如果在派生类中使用了消息映射,那么基类的消息映射就会失效,而MFC却可以,以上源代码已经解决了此问题。
everandforever 2005-06-08
  • 打赏
  • 举报
回复
要完全实现MFC,而又要摆脱那些“Afx”,你要做的事情还有很多啊。
MFC中CWND和CDIALOG的代码是很纷繁复杂的。
everandforever 2005-06-08
  • 打赏
  • 举报
回复
WM_NCCREATE, WM_CREATE 这两个消息好像无法抓到吧。
medie 2005-06-08
  • 打赏
  • 举报
回复

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

16,551

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Creator Browser
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧