?? atlapp.h文件剖析.txt
字號:
if(::IsWindow(hNtfWnd))
{
// need conditional code because types don't match in winuser.h
#ifdef _WIN64
::SetWindowLongPtr(hNtfWnd, GWLP_USERDATA, (LONG_PTR)this);
#else
::SetWindowLongPtr(hNtfWnd, GWLP_USERDATA, PtrToLong(this));
#endif
//加入該窗口句柄
bRet = m_pSettingChangeNotify->Add(hNtfWnd);
}
else
{
bRet = FALSE;
}
}
lock.Unlock();
return bRet;
}
該函數用來初始化一個存放窗口句柄的對象
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 Dialog Template嗎?
_ATL_EMPTY_DLGTEMPLATE templ;
//增加一個無模式對話框
HWND hNtfWnd = ::CreateDialogIndirect(GetModuleInstance(), &templ, NULL, pfnDlgProc);
ATLASSERT(::IsWindow(hNtfWnd));
if(::IsWindow(hNtfWnd))
{
// need conditional code because types don't match in winuser.h
#ifdef _WIN64
::SetWindowLongPtr(hNtfWnd, GWLP_USERDATA, (LONG_PTR)this);
#else
::SetWindowLongPtr(hNtfWnd, GWLP_USERDATA, PtrToLong(this));
#endif
bRet = m_pSettingChangeNotify->Add(hNtfWnd);
}
else
{
bRet = FALSE;
}
}
lock.Unlock();
return bRet;
}
//清理消息
void TermSettingChangeNotify()
{
CStaticDataInitCriticalSectionLock lock;
if(FAILED(lock.Lock()))
{
ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::TermSettingChangeNotify.\n"));
ATLASSERT(FALSE);
return;
}
if(m_pSettingChangeNotify != NULL && m_pSettingChangeNotify->GetSize() > 0)
//銷毀窗口
::DestroyWindow((*m_pSettingChangeNotify)[0]);
delete m_pSettingChangeNotify;
m_pSettingChangeNotify = NULL;
lock.Unlock();
}
BOOL AddSettingChangeNotify(HWND hWnd)
{
CStaticDataInitCriticalSectionLock lock;
if(FAILED(lock.Lock()))
{
ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::AddSettingChangeNotify.\n"));
ATLASSERT(FALSE);
return FALSE;
}
ATLASSERT(::IsWindow(hWnd));
BOOL bRet = FALSE;
if(InitSettingChangeNotify() != FALSE)
bRet = m_pSettingChangeNotify->Add(hWnd);
lock.Unlock();
return bRet;
}
BOOL RemoveSettingChangeNotify(HWND hWnd)
{
CStaticDataInitCriticalSectionLock lock;
if(FAILED(lock.Lock()))
{
ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::RemoveSettingChangeNotify.\n"));
ATLASSERT(FALSE);
return FALSE;
}
BOOL bRet = FALSE;
if(m_pSettingChangeNotify != NULL)
bRet = m_pSettingChangeNotify->Remove(hWnd);
lock.Unlock();
return bRet;
}
現在回到剛才提到的Run()函數,里面最開始就定義了一個CmessageLoop循環對象,然后通過_Module對象的AddMessageLoop成員函數加入到循環隊列里面,直到_Module調用了RemoveMessageLoop移除循環隊列,程序才結束循環,返回到WinMain函數。
在這里還有一個比較重要的類,那就是CMessageLoop,是他維持了系統的消息,維持了程序的生命周期。那么下面我們來看看這個類的定義和具體的實現方法。
CmessageLoop包含了如下一些成員函數和成員變量
成員變量
//處理消息
ATL::CSimpleArray<CMessageFilter*> m_aMsgFilter;
//處理空閑句柄
ATL::CSimpleArray<CIdleHandler*> m_aIdleHandler;
//Win32API消息結構
MSG m_msg;
成員函數(用紅色標記的函數是虛函數)
AddMessageFilter 加入一條消息過濾
RemoveMessageFilter 移除一條消息過濾
AddIdleHandler 加入一個空閑句柄
RemoveIdleHandler 移出一個空閑句柄
AddUpdateUI 為了兼容老的ATL而設計的
RemoveUpdateUI 為了兼容老的ATL而設計的
IsIdleMessage 過濾一些比如WM_MOUSEMOVE之類的消息
Run 消息循環。關鍵部分!!!
PreTranslateMessage 消息過濾
OnIdle 空閑處理
再這里我不準備對每個函數都進行詳細的分析,主要分析核心的函數Run,CmessageLoop由它來維持著系統的消息循環。
函數如下:
int Run()
{
//空閑?
BOOL bDoIdle = TRUE;
//空閑計數器
int nIdleCount = 0;
//返回標志
BOOL bRet;
//開始消息循環了哦!!!
for(;;)
{
//當bDoIdle為TRUE,并且不能從消息隊列里面取出消息了,那么開始空閑操作了!
//PM_NOREMOVE:再PeekMessage函數處理后不將消息從隊列里移除
while(bDoIdle && !::PeekMessage(&m_msg, NULL, 0, 0, PM_NOREMOVE))
{
if(!OnIdle(nIdleCount++))
bDoIdle = FALSE;
}
//從當前線程獲取一個消息
//返回-1表示出現一個錯誤
//返回 0表示提交了一個WM_QUIT,程序將要退出
//成功獲得一個消息,返回不等于0的值
bRet = ::GetMessage(&m_msg, NULL, 0, 0);
if(bRet == -1)
{
ATLTRACE2(atlTraceUI, 0, _T("::GetMessage returned -1 (error)\n"));
continue; // error, don't process
}
else if(!bRet)
{
ATLTRACE2(atlTraceUI, 0, _T("CMessageLoop::Run - exiting\n"));
break; // WM_QUIT, exit message loop
}
//如果熟悉使用c語言來寫Win32的程序員會發現,原來WinMain中的哪個處理消息循環的語句放到這里來了!!!
if(!PreTranslateMessage(&m_msg))
{
//translates virtual-key messages into character messages.
::TranslateMessage(&m_msg);
//dispatches a message to a window procedure
::DispatchMessage(&m_msg);
}
//判斷是否為空閑消息?
//排除WM_MOUSEMOVE WM_NCMOUSEMOVE WM_SYSTIMER消息
if(IsIdleMessage(&m_msg))
{
bDoIdle = TRUE;
nIdleCount = 0;
}
}
return (int)m_msg.wParam;
}
以上就是對ATLAPP.H中的幾個比較重要的類的分析,還有其他幾個類的分析我將放在以后的文章中
(待續。。。)
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -