星期一, 九月 11, 2006

004 - Hello, WINX! - 续

我们再来看看用MFC、WTL、WINX来实现的SDI窗口风格的最简单的Hello程序。

// -----------------------------------------
// MFC的Hello程序

class CMainFrame : public CFrameWnd
{
public:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;

cs.dwExStyle &= ~WS_EX_CLIENTEDGE;
cs.lpszClass = AfxRegisterWndClass(
CS_HREDRAWCS_VREDRAWCS_DBLCLKS,
::LoadCursor(NULL, IDC_ARROW),
HBRUSH(COLOR_WINDOW+1),
NULL);

return TRUE;
}

protected:
afx_msg void OnPaint()
{
CPaintDC dc(this);
dc.TextOut(1, 1, _T("Hello, MFC!"));
}
DECLARE_MESSAGE_MAP()
};

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
ON_WM_PAINT()
END_MESSAGE_MAP()

class CHelloMfc2App : public CWinApp
{
public:
virtual BOOL InitInstance()
{
CMainFrame* pFrame = new CMainFrame;
m_pMainWnd = pFrame;

pFrame->Create(NULL, _T("Hello"));
pFrame->ShowWindow(SW_SHOW);

return TRUE;
}
};

// -----------------------------------------
// WTL的Hello程序

class CHelloMainFrame : public CFrameWindowImpl<CHelloMainFrame>
{
public:
BEGIN_MSG_MAP(CHelloMainFrame)
MESSAGE_HANDLER(WM_PAINT, OnPaint)
CHAIN_MSG_MAP(CFrameWindowImpl<CHelloMainFrame>)
END_MSG_MAP()

LRESULT OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
CPaintDC dc(m_hWnd);
dc.TextOut(1, 1, _T("Hello, WTL!"));
return 0;
}
};

WTL::CAppModule _Module;

int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
_Module.Init(NULL, hInstance);
{
CMessageLoop theLoop;
_Module.AddMessageLoop(&theLoop);

CHelloMainFrame wndMain;
wndMain.Create(NULL, NULL, _T("Hello"));
wndMain.ShowWindow(nCmdShow);

theLoop.Run();
}
_Module.Term();
return 0;
}

// -----------------------------------------
// WINX的Hello程序

class CHelloMainFrame : public winx::MainFrame<CHelloMainFrame>
{
WINX_CLASS("CHelloMainFrame");
public:
void OnPaint(HWND hWnd)
{
winx::PaintDC dc(hWnd);
dc.TextOut(1, 1, _T("Hello, WINX!"));
}
};

winx::CAppModule _Module;

int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
CAppModuleInit module;

CHelloMainFrame::RegisterClass();
CHelloMainFrame wndMain;
wndMain.Create(NULL, _T("Hello"));

return module.Run();
}
// -----------------------------------------

如果你了解Windows SDK编程,你肯定知道一个典型的Windows窗口程序(SDI),通常包含以下三个步骤:

1)注册窗口类。
2)创建窗口。
3)消息循环:分派并在窗口过程处理相应的消息。

我们看到,MFC把注册窗口类的过程隐含在PreCreateWindow,并尽量弱化窗口类概念。这表现在MFC的AfxRegisterWndClass甚至不允许用户主动指定窗口类的名字。WTL进一步弱化了窗口类概念,用户甚至根本就不需要知道RegisterClass(注册窗口类)这回事。

WINX采取了相反的策略,强调窗口类的概念,并认为用户理解窗口类是重要的。具体表现在:

1)用户需要用WINX_CLASS指定窗口类的名字。
2)用户需要在创建窗口类的第一份实例前,主动RegisterClass

这看似麻烦,但其实它是WINX强调可视化编程的关键,这一点我们在后续文章中将详细解释。

最让你惊异的,也许是WINX没有MessageMap。是的,WINX不需要你指定如何分派消息。并且,你将发现,几乎所有的MFC中的消息,WINX中均有对应,并且两者的消息处理函数原型极其相似,基本都是多了一个HWND hWnd参数。例如MFC的void OnPaint(),到WINX中为void OnPaint(HWND hWnd); MFC中的void OnLButtonDown(UINT uFlags, CPoint pt),到WINX为void OnLButtonDown(HWND hWnd, UINT uFlags, winx::CPoint pt); 等等。关于WINX中的消息分派机制,我们后续将进一步介绍。

最后需要提醒的是,WINX目前没有提供自己的消息循环,直接取自WTL。这个例子你看到WINX的WinMain代码比WTL简洁,但这只是假象。WINX只是对WTL的WinMain进行了一定的包装,没有实质性改进。WTL完全可以提供同样简洁的代码。

没有评论: