MFC體系結構(1)
1.CWndThread類其實就是一個線程封裝類,他有兩種模式
a.工作者線程,他沒有消息循環, 用來做耗時計算,
線程函數 UINT _cdecl MyThreadProc(LPVOID param);
啟動線程
AfxBeginThread(線程的入口函數,如果函數參數, 優先級 = 0,棧大小=0,
創建後的狀態(掛起或者創建就運行)默認是運行,安全性默認NULL.)
b.UI界面線程,CWinThread派生類,他有Windows消息循環
他的使用發送和工作者則不一樣, 他是要你自定義一個類,這個類是繼承自
CWinThread。 把這個派生類坐位你 AfxBeginThread 第一個參數。
c.用戶界面線程主要是為了消息循環, 這樣才能和用戶交互,接收鼠標鍵盤消息.
2.CWinThread 主要方法 派生自線程類的UI界面線程使用
a.virtual BOOL InitInstance(); 程序實例對象初始化 返回真就執行消息循環
b.virtual int ExitInstance(); 退出應用程序實例
c.virtual int Run() 執行消息循環
d.BOOL CreateThread 使用成員方法啟動線程,和AfxBeginThread效果一樣,按需要使用.
e.DWORD SuspendThread()暫停 DWORD ResumeThread() 恢復
f.int GetThreadPriority() 獲取優先級 BOOL SetThreadPriority(int o)設置優先級
g.virtual BOOL IsldleMessage(MSG* pMsg)判斷消息是否是空閑消息 WM_TIME也會被當成空閑消息
h.virtual BOOL Onldle(LONg lCount) 處理空閑消息
i.BOOL PreTranslateMessage(MSG* pMsg) 截獲消息, 返回TRUE告訴消息循環,這個消息我已經處理了
j.BOOL ProcessMessageFilter(int code,LPMSG lpMsg) 處理消息過濾,針對一個消息數組,
比如要用戶輸入一個東西,如果他不輸入, 我們就過濾鼠標消息, 他就不能移動鼠標了
k.KRESULT ProcessWndProcException(CException*e,const MSG* pMsg);處理函數沒有捕獲線程或者命令函數拋出的異常
二、CWinApp類和CWinAppEx類
1.CWinApp類繼承自 CWinThread 他其實還就是以現場類 他實現了一些方法
a.CWinApp* AFXAPI AfxGetApp(), LPCTSTR AFXAPI AfxGetAppNAme();
b.HINSTANCE AFXAPI AfxGetInstanceHandle() 調用Win32Api要求你傳遞一個Instance句柄
在16位Windows下 這個句柄非常有用,但是到了32位 意義不大.
c.void AFXAPI AfxSetResourceHandle(HINSTANCE hInstanceResource)
在開發大型國際應用的時候,字符串資源單獨放一個動態庫裏面,通過切換動態庫的方法
就可以加載不同字符串,實現多語言的版本.
2.CWinAppEx 是CWinApp的擴展
a.CWinApp類是支持註冊表和INI文件讀寫配置文件
b.CWinAppEx 只能使用註冊表了
c.CWinApp void SetRegistryKey(LPCTSTR lpszKey) 設置註冊表的key
如果是NULL,那麽他就是從INI文件進行讀取
d.CWinAppEx 你就必須知道這個key, 如果你不想存取註冊表,
就重寫 相關的函數就行了.
3.CWinApp文檔集合框架
a.AddDocTemplate 是一個列表 應用程序支持文檔類型的集合
有多個Template就可以支持多個不同的視圖 或者擴展文件
b.GetFirstDocTemplatePosition GetNextDocTemplate 遍歷文檔模板集合
c.OpenDocumentFile 打開
d.LoadStdProfileSettings 載入了框架窗口用戶設置的配置,比如一開始是最大化的
下次打開的時候還是最大化的. 裏面會創建主窗口
e.AddToRecentFileList 打開視圖的歷史
f.RegisterShellFileTypes 註冊外殼文件的類型,擴展名文件和你關聯,Windows擴展名的文件圖標和應用程序相管理的
如果雙擊這文件,Windows會找到這個程序把他打開, 實現雙擊打開
g.UnregisterShellFileTypes
註意如果你添加多個文檔模板的時候,你選中新建會彈出一個窗口
讓用戶選擇默認新建哪一個類型文檔,作為新的模板,這個窗口很難看,
也很討厭, 如果要改變這個東西,你把OnFileNew裏面的這個
CDocManager::OnFileNew() 把這個進行重載, 改變他的行為,
也就是你點擊新建的時候,這個函數會檢測你Add的文檔, 他會遍歷DocTemplate
如果類別數量大於1個的時候,就會彈出這個窗口,參考OnFileNew裏的函數,把有用的函數拷貝出來即可
三、窗口知識
1.Win32創建一個窗口是最基本的知識,所以就不見了
2.基本的窗口風格
a.重疊窗口(WS_OVERLAPPED)
通常用於簡歷應用程序主窗口,事實上有時候就叫做主窗口,或框架窗口
b.彈出窗口(WS_POPUP)
通常以對話框和消息框的形式與用戶對話
c.子窗口(WS_CHILD)
通常用在View中,比如文本編輯器中文本顯示,也用在空間中,比如對話框
的按鈕,子窗口也稱為"控件"窗口
d.第一種和第二種不能組合,其他的任何風格都可以組合上面的風格
3.三種截獲窗口消息的方法
作用:比如Win32按鈕很難看,想給他加個圖片
想改變這個窗口的行為,就要攔截他的消息,從他本身的窗口
過程把消息截過來,在他的WM_PAINT消息中,繪制一個好看的圖片.
a.超類化,替換窗口類的窗口過程,替換沒有窗口的窗口類的
窗口過程是純粹的超類化,如果利用已有窗口找到窗口類替換類
的窗口過程稱為全局子類化,
替換系統窗口類的窗口過程之前必須先反註冊一下窗口類
b.子類化
替換已有窗口的窗口過程(MFC中只使用這種方式)
c.消息鉤子
利用Windows消息鉤子截獲窗口消息,進來使用前兩種方式
來截獲窗口消息
d.盡量不使用,防止被殺毒軟件防火墻殺死進程.帶來不必要的麻煩
e.超類化子類化功能不必消息鉤子遜色,消息鉤子的好處是攔截另外一個應用
程序的消息的時候就比較方便了,可以全局的攔截應用程序的消息循環.
但是會很消耗系統資源.
f.MFC中其實提供了類型消息鉤子的機制,
CWinThread裏就有一個消息攔截的APIPreTranslateMessage。可以把他理解成消息鉤子.
f.別的進程裏的消息結果,仍然可以用超類化或者全局子類化類結果都可以的.
如果你某些特殊的控件行為要特別定制的時候,就可以用子類化.
否則就用PreTranslateMessage進行處理,在WM_PAINT替換按鈕風格.
四、CWnd類
1.AfxRegisterClass() AfxRegisterWndClass 註冊新窗口類
2.AfxGetMainWnd() 獲取當前應用主窗口
3.創建和使用窗口
a.Create CreateEx 創建窗口
b.CreateControl 創建控件
c.FromHandle()通過窗口句柄拿到對應的CWnd對象
e.FromHandlePermanent 通過窗口句柄拿到對應的CWnd 內部會創建臨時的窗口變量
用完就自動銷毀了.
f.Attach()創建CWnd類或派生類對象,綁定參數的窗口句柄
g.Detach()解除CWnd類或派生類綁定的這個窗口句柄 這個CWnd類的HWND句柄就接觸綁定了.
h.ExecuteDlginit()執行對話框的初始化
i.PreCreateWindow()調用CreateWindow之前他會先調用PerCreateWindow
重載了之後在這之前改變窗口的風格,經常用在主框架窗口是否包含最小化按鈕這些風格等等.
甚至可以把窗口類都換掉,類名啊什麽的.
4. 子類化支持(本質就是替換已有窗口的窗口過程的方法)
子類化主要是用在從CWnd派生的空間中
a.SubClasswindow SubclassDlgItem UnsubClassWindow 反子類化
如果說界面中的很多按鈕,讓他們換成一種風格,那工作量是很龐大的,
SubClassWindow讓人頭暈,建議使用超類化來完成這些工作.
或者在APIPreTranslateMessage截獲消息的地方
子類化其實也是經常要用的一個技巧,很多時候對Win32的控件加以改變
這樣就能做成一自定義的控件.自定義控件就是子類化的方式.
本質上就是一個替換消息映射。
b.PreSubclassWindow 類似 PreCreateWindow
c.GetSafeHwnd()
e.GetStyle GetStyleEx ModifyStyle ModifyStyleEx
f.GetOwner SetOwer
MFC體系結構(1)