?? atlapp.h文件剖析.txt
字號(hào):
WTL源碼剖析 --- ATLAPP.H
作者:姜江
QQ:457283
E-mail:jznsmail@163.net
ATLAPP.H包含了消息循環(huán)類、接口類、和產(chǎn)生應(yīng)用程序所必需的一些基礎(chǔ)類定義。
類定義如下:
CmessageFilter類---用于消息過(guò)濾的
CidleHandler 類---用于空閑消息處理的
CmessageLoop類---用于消息循環(huán)的
CappModule 類---應(yīng)用程序基礎(chǔ)類
CserverAppModule類---用于Com服務(wù)構(gòu)架的應(yīng)用程序類
另外還有3個(gè)全局函數(shù):
AtlGetDefaultGuiFont()獲得默認(rèn)的顯示字體
AtlCreateBoldFont() 產(chǎn)生一個(gè)粗體字體
AtlInitCommonControls()初始化一些控件所需共同的DLL
WTL程序的結(jié)構(gòu)
一個(gè)窗口程序的創(chuàng)建到銷(xiāo)毀過(guò)程主要經(jīng)過(guò)如下幾個(gè)階段
1. 注冊(cè)窗口類
2. 創(chuàng)建窗口
3. 進(jìn)入消息循環(huán)
如果用C寫(xiě)過(guò)Win32窗口程序的人一定會(huì)記得如下的結(jié)構(gòu):
//窗口過(guò)程處理函數(shù)
LRESULT CALLBACK WndProc(HWND hwnd,UINT Message,WPARAM wParam,LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR szCmdLine,int iCmdShow)
{
HWND hwnd = NULL;
MSG msg;
…
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
…
//注冊(cè)窗口
if(!RegisterClass(&wndclass))
{
MessageBox(NULL,TEXT("Porgram requires Windows NT!"),szAppName,MB_ICONERROR);
return 0;
}
//創(chuàng)建窗口
hwnd = CreateWindow(szAppName,TEXT("My Application"),
WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL,
CW_USEDEFAULT,CW_USEDEFAULT,
CW_USEDEFAULT,CW_USEDEFAULT,
NULL,NULL,hInstance,NULL);
ShowWindow(hwnd,iCmdShow);
UpdateWindow(hwnd);
//進(jìn)入消息循環(huán)
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
那么你可能會(huì)問(wèn)WTL的WinMain函數(shù)再哪里?如果你通過(guò)WTL/ATL導(dǎo)向生成一個(gè)應(yīng)用程序,那么你會(huì)在跟工程名字同名的.cpp文件中發(fā)現(xiàn)如下的代碼:
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); //等下分析它的實(shí)現(xiàn) ATLASSERT(SUCCEEDED(hRes));
int nRet = Run(lpstrCmdLine, nCmdShow);//程序的關(guān)鍵分
_Module.Term();
::CoUninitialize();
return nRet;
}
從這個(gè)_tWinMain函數(shù)的定義,你可以發(fā)現(xiàn)程序的關(guān)鍵部分是我紫色標(biāo)記出來(lái)的Run()函數(shù)。這個(gè)函數(shù)是一個(gè)自定義的函數(shù),不過(guò)如果通過(guò)ATL/WTL導(dǎo)向程序,那么會(huì)自動(dòng)生成這樣一個(gè)Run()函數(shù)的,下面我們先分析一下這個(gè)自動(dòng)生成的Run函數(shù)。
int Run(LPTSTR /*lpstrCmdLine*/ = NULL, int nCmdShow = SW_SHOWDEFAULT)
{
CMessageLoop theLoop; //定義消息循環(huán)
_Module.AddMessageLoop(&theLoop); //將消息添加到消息循環(huán)
CMainFrame wndMain; //應(yīng)用程序框架類
//生成框架
if(wndMain.CreateEx() == NULL)
{
ATLTRACE(_T("Main window creation failed!\n"));
return 0;
}
//顯示框架
wndMain.ShowWindow(nCmdShow);
//運(yùn)行消息循環(huán)
int nRet = theLoop.Run();
//清除消息
_Module.RemoveMessageLoop();
return nRet;
}
通過(guò)這個(gè)Run函數(shù)我們可以看到在函數(shù)中完成了如下幾個(gè)過(guò)程:
1. 生成一個(gè)消息循環(huán)對(duì)象(theLoop)
2. 在全局的_Module中加入這個(gè)消息循環(huán)
3. 生成一個(gè)應(yīng)用程序框架對(duì)象
4. 顯示應(yīng)用程序框架
5. 開(kāi)始消息循環(huán)
6. 結(jié)束消息循環(huán)
7. 返回WinMain函數(shù),結(jié)束程序
實(shí)現(xiàn)分析
在這篇文章我不想過(guò)多的分析應(yīng)用程序框架和窗口的細(xì)節(jié),這些內(nèi)容將放在以后的幾篇文章中詳細(xì)分析,本文主要對(duì)ATLAPP.H頭文件中實(shí)現(xiàn)的一些過(guò)程進(jìn)行詳細(xì)分析。
首先從全局變量_Module開(kāi)始。
_Module維持著生成應(yīng)用程序的主線程,控制著程序的消息循環(huán)隊(duì)列,是一個(gè)CAppModule的對(duì)象。該CAppModule從ATL::CcomModule繼承。
在WTL::CappModule中定義了8個(gè)公有成員函數(shù),分別為:
AddMessageLoop()添加一個(gè)消息循環(huán),進(jìn)入消息循環(huán)隊(duì)列里。
RemoveMessageLoop()移除消息循環(huán)隊(duì)列。
GetMessageLoop()獲得消息循環(huán)。
InitSettingChangeNotify()初始化環(huán)境
AddSettingChangeNotify()添加一個(gè)窗口句柄。
RemoveSettingChangeNotify()清理環(huán)境
除了8個(gè)公有成員函數(shù)外,該類還定義了3個(gè)公有成員變量
m_dwMainThreadID負(fù)責(zé)保存該應(yīng)用程序的主線程ID
m_pMsgLoopMap負(fù)責(zé)存儲(chǔ)消息循環(huán)
m_pSettingChangeNotify負(fù)責(zé)存放窗口句柄
下面分別來(lái)分析幾個(gè)主要成員函數(shù)的實(shí)現(xiàn):
BOOL AddMessageLoop(CMessageLoop* pMsgLoop)
{
CStaticDataInitCriticalSectionLock lock;
//鎖住關(guān)鍵片斷,由于進(jìn)程同步的關(guān)系?。。? if(FAILED(lock.Lock()))
{
ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::AddMessageLoop.\n"));
ATLASSERT(FALSE);
return FALSE;
}
ATLASSERT(pMsgLoop != NULL);
ATLASSERT(m_pMsgLoopMap->Lookup(::GetCurrentThreadId()) == NULL); // not in map yet
BOOL bRet = m_pMsgLoopMap->Add(::GetCurrentThreadId(), pMsgLoop);
lock.Unlock();
return bRet;
}
關(guān)鍵部分我用紅色的字體標(biāo)記出來(lái)了,意思是什么?通過(guò)當(dāng)前線程的Id來(lái)標(biāo)示一個(gè)消息循環(huán),存儲(chǔ)在m_pMsgLoopMap中。
BOOL RemoveMessageLoop()
{
CStaticDataInitCriticalSectionLock lock;
if(FAILED(lock.Lock()))
{
ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::RemoveMessageLoop.\n"));
ATLASSERT(FALSE);
return FALSE;
}
BOOL bRet = m_pMsgLoopMap->Remove(::GetCurrentThreadId());
lock.Unlock();
return bRet;
}
關(guān)鍵部分同樣通過(guò)紅色字體標(biāo)記出來(lái),嗯,沒(méi)錯(cuò)正如AddMessageLoop函數(shù)一樣,該函數(shù)也是通過(guò)線程Id來(lái)尋找消息循環(huán)移除對(duì)象的。
CMessageLoop* GetMessageLoop(DWORD dwThreadID = ::GetCurrentThreadId()) const
{
CStaticDataInitCriticalSectionLock lock;
if(FAILED(lock.Lock()))
{
ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::GetMessageLoop.\n"));
ATLASSERT(FALSE);
return NULL;
}
CMessageLoop* pLoop = m_pMsgLoopMap->Lookup(dwThreadID);
lock.Unlock();
return pLoop;
}
該函數(shù)通過(guò)線程Id在m_pMsgLoopMap消息隊(duì)列中尋找對(duì)應(yīng)的消息循環(huán),找到后返回。
BOOL InitSettingChangeNotify(DLGPROC pfnDlgProc = _SettingChangeDlgProc)
{
CStaticDataInitCriticalSectionLock lock;
if(FAILED(lock.Lock()))
{
ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::InitSettingChangeNotify.\n"));
ATLASSERT(FALSE);
return FALSE;
}
if(m_pSettingChangeNotify == NULL)
{
typedef ATL::CSimpleArray<HWND> _notifyClass;
ATLTRY(m_pSettingChangeNotify = new _notifyClass);
ATLASSERT(m_pSettingChangeNotify != NULL);
}
BOOL bRet = (m_pSettingChangeNotify != NULL);
if(bRet && m_pSettingChangeNotify->GetSize() == 0)
{
// init everything
_ATL_EMPTY_DLGTEMPLATE templ;
//增加一個(gè)無(wú)模式對(duì)話框
HWND hNtfWnd = ::CreateDialogIndirect(GetModuleInstance(), &templ, NULL, pfnDlgProc);
ATLASSERT(::IsWindow(hNtfWnd));
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -