一个窗口从创建到销毁,有这么几个主要过程。
在winmain中
-
注册窗口类
-
创建窗口
-
进入消息循环
在wndproc中
-
处理消息
现在我们就是要挖掘出wtl中在何处处理这些东西,怎么处理的。首先:
winmain在哪里?
winmain在和工程名相同的cpp文件中。名字叫做_twinmain
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;
}
从这个函数中,看不出什么,基本上实质上的内容都被分配在别的函数中处理了。这里所说的别的函数就是Run(lpstrCmdLine, nCmdShow);这个函数是我们自己写的,就在这个_twinmain的上面。
Run的作用
int Run(LPTSTR /*lpstrCmdLine*/ = NULL, int nCmdShow = SW_SHOWDEFAULT)
{
CMessageLoop theLoop;
_Module.AddMessageLoop(&theLoop);
CMainFrame wndMain;
if(wndMain.CreateEx() == NULL)
{
ATLTRACE(_T("Main window creation failed!/n"));
return 0;
}
wndMain.ShowWindow(nCmdShow);
int nRet = theLoop.Run();
_Module.RemoveMessageLoop();
return nRet;
}
从名字MessageLoop和CreateEx就可以猜测到这个Run就是创建窗口并进入消息循环的地方。所以
winmain进行必要的初始化,主要的工作在Run中进行
Run创建窗口并进入消息循环。
窗口的创建
很容易就可以知道这么一段完成了窗口的创建
CMainFrame wndMain;
if(wndMain.CreateEx() == NULL)
{
ATLTRACE(_T("Main window creation failed!/n"));
return 0;
}
CMainFrame定义在MainFrm.h中。
class CMainFrame : public CFrameWindowImpl<CMainFrame>, public CUpdateUI<CMainFrame>, public CMessageFilter, public CIdleHandler
可见这里使用了多继承,这是一个普遍行为。主要继承于CFrameWindowImpl,而且这个是模板,提供的参数就是CMainFrame。后面可以发现,这个参数在基类中用于强制类型转换,算是向下转换。
创建调用的是wndMain.CreateEx(),这个函数在CMainFrame中找不到,自然在其基类中有。这个是CFrameWindowImpl中的CreateEx():
HWND CreateEx(HWND hWndParent = NULL, _U_RECT rect = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, LPVOID lpCreateParam = NULL)
{
TCHAR szWindowName[256];
szWindowName[0] = 0;
::LoadString(_Module.GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, 256);
HMENU hMenu=::LoadMenu(_Module.GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID));
T* pT = static_cast<T*>(this);
HWND hWnd = pT->Create(hWndParent, rect, szWindowName, dwStyle, dwExStyle, hMenu, lpCreateParam);
if(hWnd!=NULL)
m_hAccel=::LoadAccelerators(_Module.GetResourceInstance(),MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID));
return hWnd;
}
等等,我们在这里发现了一个奇异的行为。
T* pT = static_cast<T*>(this);
这是什么,强制类型转换,而且是基于模板参数的类型转换。嗯ÿ