通过生成一个单文档举例说明。
包括一个frame,一个view,和关于窗口。
class CMainFrame : public CFrameWindowImpl<CMainFrame>, public CUpdateUI<CMainFrame>,
public CMessageFilter, public CIdleHandler
{
... ....
};
CFrameWindowImpl定义在atlframe.h里,是CWindow的派生,同时设置默认的frame属性CFrameWinTraits。在CreateEx里做了LoadAccelerators加速键的处理,同时创建了toolbar;处理了WM_SIZE消息。CUpdateUI处理menu和toobar的命令。CMessageFilter类实现了一个虚函数,作为消息过滤,也就是如果一个类(不管是否是窗口类)想实现消息过滤,继承此类即可。
class CSingleWtlView : public CWindowImpl<CSingleWtlView>
{
public:
DECLARE_WND_CLASS(NULL)
BOOL PreTranslateMessage(MSG* pMsg)
{
pMsg;
return FALSE;
}
BEGIN_MSG_MAP(CSingleWtlView)
MESSAGE_HANDLER(WM_PAINT, OnPaint)
END_MSG_MAP()
// Handler prototypes (uncomment arguments if needed):
// LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
// LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
// LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
LRESULT OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
CPaintDC dc(m_hWnd);
//TODO: Add your drawing code here
return 0;
}
};
这个视图类从窗口实现类继承,实现了PAINT消息的处理。重载了PreTranslateMessage。
class CAboutDlg : public CDialogImpl<CAboutDlg>
{
... ....
};
对话框类没什么可说的了。
关于入口函数和界面线程
CAppModule _Module;
_Module是一个全局变量,这里是CAppModule的一个实例。而CAppModule类是对应用程序的封装。它封装了诸如初始化模块等功能。一个_Module还维持一个消息循环Map。
int Run(LPTSTR /*lpstrCmdLine*/ = NULL, int nCmdShow = SW_SHOWDEFAULT)
{
CMessageLoop theLoop;
_Module.AddMessageLoop(&theLoop);
该函数创建了一个CMessageLoop实例,该实例包含了这个线程的消息循环。这些消息循环都放在模块的全局消息循环中,通过线程的ID来索引。这样,该线程的其它代码就能访问得到。
每一个应用程序维护一个消息循环队列Map,应用程序中的每个线程都通过"_Module.AddMessageLoop(&theLoop);",把该线程的消息循环加入到_Module的消息循环Map中。
CMainFrame wndMain;
创建frame
if(wndMain.CreateEx() == NULL)
{
ATLTRACE(_T("Main window creation failed!/n"));
return 0;
}
wndMain.ShowWindow(nCmdShow);
int nRet = theLoop.Run();
界面线程的消息循环,知道WM_QUIT
_Module.RemoveMessageLoop();
从全局消息链删除
return nRet;
}
程序入口函数,根据是否是UNICODE编译器会编译成不同的形式
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int nCmdShow)
{
HRESULT hRes = ::CoInitialize(NULL);
// If you are running on NT 4.0 or higher you can use the following call instead to
// make the EXE free threaded. This means that calls come in on a random RPC thread.
// HRESULT hRes = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
ATLASSERT(SUCCEEDED(hRes));
// this resolves ATL window thunking problem when Microsoft Layer for Unicode (MSLU) is used
::DefWindowProc(NULL, 0, 0, 0L);
AtlInitCommonControls(ICC_COOL_CLASSES | ICC_BAR_CLASSES); // add flags to support other controls
hRes = _Module.Init(NULL, hInstance);
ATLASSERT(SUCCEEDED(hRes));
int nRet = Run(lpstrCmdLine, nCmdShow);
_Module.Term();
::CoUninitialize();
return nRet;
}