小識MFC,一套設計優雅與不優雅并存的類庫----小話MFC(2)

Q1:?CPoint繼承于POINT,這樣有什么好處?

A:?繼承的一個最基本的好處當然就是減少代碼量。CPoint和POINT內部數據一樣,只是一個提供了更多的方法來操作對象。

typedef struct tagPOINT
{LONG  x;LONG  y;
} POINT, *PPOINT, NEAR *NPPOINT, FAR *LPPOINT;
class CPoint :public tagPOINT

這樣的方式,很自然,CPoint不用再單獨加入成員x,y,?而且函數參數可以很自然的實現從派生類到基類的轉換,是個不錯的設計。

Q2: CDocument, CView實現界面展示、變化以及用戶操作UI是MVC架構嗎?

A:?看起來有點像,實際并不是純正的MVC設計。CDocument的設計更多考慮了windows操作系統MDI文檔視圖,它希望提供一個MDI中每個視圖的模板原型。

CView主要實現顯示,不過對于用戶和UI的交互,MFC架構中并沒有提供框架為MVC的控制器來單獨考慮,它將控制器放入了CView, CDocument甚至CWinApp中。

這聽起來并不是一個很好的設計,但是實際上,視圖和操作視圖放在一起也并不是一個萬惡不赦的設計, 因為UI本來就改來改去,程序員還是可以接受這樣的方式。

Q3: CWnd類內部如此多的成員函數,這樣設計合理嗎?

A: CWnd主要處理一個窗口的顯示,包括窗口標題、最大化最小化、內部子控件獲取等。不過ms的設計,將此類內部加入了太多和CWnd關系不是很大的東西,導致了此類成員很多,弊端不用說了,此類不是一個優秀設計,它處理了太多不該去處理的東西,使得整個類庫設計清晰度降低;

不過,也有一定優點,很多在主框架或者view中可以直接調用它的成員函數,不用花心思再去想需要調用的函數出自哪個類。

Q4:?使用MFC向導創建的應用程序,里面的消息處理流程很復雜,如何很好地查看消息流?

A:?函數堆棧是查看它的很好方式。

如上,是一個使用MFC app wizzard創建的SDI應用程序basic_mfc.exe開始運行后的調用堆棧。

可以看出,應用程序開始運行后,會調用應用程序類的ProcessShellCommand解析命令行參數,此過程可能就進入了消息處理過程(比如,一個應用程序剛打開,默認的處理是打開一個新文檔),如下是ProcessShellCommand的部分代碼:

	case CCommandLineInfo::FileNew:if (!AfxGetApp()->OnCmdMsg(ID_FILE_NEW, 0, NULL, NULL))OnFileNew();if (m_pMainWnd == NULL)bResult = FALSE;break;// If we've been asked to open a file, call OpenDocumentFile()case CCommandLineInfo::FileOpen:if (!OpenDocumentFile(rCmdInfo.m_strFileName))bResult = FALSE;break;// If the user wanted to print, hide our main window and// fire a message to ourselves to start the printingcase CCommandLineInfo::FilePrintTo:case CCommandLineInfo::FilePrint:m_nCmdShow = SW_HIDE;ASSERT(m_pCmdInfo == NULL);if(OpenDocumentFile(rCmdInfo.m_strFileName)){m_pCmdInfo = &rCmdInfo;ENSURE_VALID(m_pMainWnd);m_pMainWnd->SendMessage(WM_COMMAND, ID_FILE_PRINT_DIRECT);m_pCmdInfo = NULL;}bResult = FALSE;break;


從上面可以看出,FileNew就是從這里進去的。OnCmdMsg函數會調用全局函數_AfxDispatchCmdMsg,它的部分代碼如下:

case AfxSigCmd_v:// normal command or control notificationASSERT(CN_COMMAND == 0);        // CN_COMMAND same as BN_CLICKEDASSERT(pExtra == NULL);(pTarget->*mmf.pfnCmd_v_v)();break;case AfxSigCmd_b:// normal command or control notificationASSERT(CN_COMMAND == 0);        // CN_COMMAND same as BN_CLICKEDASSERT(pExtra == NULL);bResult = (pTarget->*mmf.pfnCmd_b_v)();break;case AfxSigCmd_RANGE:// normal command or control notification in a rangeASSERT(CN_COMMAND == 0);        // CN_COMMAND same as BN_CLICKEDASSERT(pExtra == NULL);(pTarget->*mmf.pfnCmd_v_u)(nID);break;case AfxSigCmd_EX:// extended command (passed ID, returns bContinue)ASSERT(pExtra == NULL);bResult = (pTarget->*mmf.pfnCmd_b_u)(nID);break;case AfxSigNotify_v:{AFX_NOTIFY* pNotify = (AFX_NOTIFY*)pExtra;ENSURE(pNotify != NULL);ASSERT(pNotify->pResult != NULL);ASSERT(pNotify->pNMHDR != NULL);(pTarget->*mmf.pfnNotify_v_NMHDR_pl)(pNotify->pNMHDR, pNotify->pResult);}break;case AfxSigNotify_b:{AFX_NOTIFY* pNotify = (AFX_NOTIFY*)pExtra;ENSURE(pNotify != NULL);ASSERT(pNotify->pResult != NULL);ASSERT(pNotify->pNMHDR != NULL);bResult = (pTarget->*mmf.pfnNotify_b_NMHDR_pl)(pNotify->pNMHDR, pNotify->pResult);}break;


它其實是對不同的消息類型調用不同的默認回調函數,有的是空參數的,有的以一個整形為參數的,等等。最終的返回值表征是否已經處理,外部會根據這個返回值決定是否繼續處理下去。

如下是接下來的處理:

這里可以看到,MFC類庫內部完成了主要的消息傳遞過程,最終到達應用程序document類的OnNewDocument來完成最后的處理。

ok,當應用程序啟動后,手動點擊菜單的新建或者工具欄中的新建,調用堆棧如下:

注意,上面的調用堆棧并不完全,堆棧最底層的是在ntdll中線程啟動的代碼,這里不列出了。

不過可以看出,應用程序啟動后,對于菜單或者工具欄的操作將通過應用程序類的Run函數,它會將UI命令傳遞進去,讓適當的模塊處理,這和剛剛啟動時的調用堆棧不一致。

在這里,我們主要看看AfxInternalPumpMessage這個函數:

BOOL AFXAPI AfxInternalPumpMessage()
{_AFX_THREAD_STATE *pState = AfxGetThreadState();if (!::GetMessage(&(pState->m_msgCur), NULL, NULL, NULL)){
#ifdef _DEBUGTRACE(traceAppMsg, 1, "CWinThread::PumpMessage - Received WM_QUIT.\n");pState->m_nDisablePumpCount++; // application must die
#endif// Note: prevents calling message loop things in 'ExitInstance'// will never be decrementedreturn FALSE;}#ifdef _DEBUGif (pState->m_nDisablePumpCount != 0){TRACE(traceAppMsg, 0, "Error: CWinThread::PumpMessage called when not permitted.\n");ASSERT(FALSE);}
#endif#ifdef _DEBUG_AfxTraceMsg(_T("PumpMessage"), &(pState->m_msgCur));
#endif// process this messageif (pState->m_msgCur.message != WM_KICKIDLE && !AfxPreTranslateMessage(&(pState->m_msgCur))){::TranslateMessage(&(pState->m_msgCur));::DispatchMessage(&(pState->m_msgCur));}return TRUE;
}


可以看到,它其實主要就是GetMessage, TranslateMessage, DispatchMessage這3個函數,是windows應用程序消息處理基本過程。

后面的調用關系就不具體說了。


微風不燥,陽光正好,你就像風一樣經過這里,愿你停留的片刻溫暖舒心。

我是程序員小迷(致力于C、C++、Java、Kotlin、Android、Shell、JavaScript、TypeScript、Python等編程技術的技巧經驗分享),若作品對您有幫助,請關注、分享、點贊、收藏、在看、喜歡,您的支持是我們為您提供幫助的最大動力。

歡迎關注。助您在編程路上越走越好!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/17649.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/17649.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/17649.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【Flutter】動畫介紹隱式動畫

🔥 本文由 程序喵正在路上 原創,CSDN首發! 💖 系列專欄:Flutter學習 🌠 首發時間:2024年5月28日 🦋 歡迎關注🖱點贊👍收藏🌟留言🐾 目…

SpringMvc-restful設計風格

Restful 1、入門1.1 簡介1.2 實例 1、入門 1.1 簡介 RESTFul是什么 RESTFul是WEB服務接口的一種設計風格。 RESTFul定義了一組約束條件和規范&#xff0c;可以讓WEB服務接口更加簡潔、易于理解、易于擴展、安全可靠。 1.2 實例 web.xml <?xml version"1.0"…

5、xss-labs之level6

一、level6-----大小寫繞過 1、測試分析 測試了之前用過的payload&#xff0c;發現都不行&#xff0c;并且level4使用的Java偽協議也不行&#xff0c;可以得出<>、script、onclick都被過濾 2、構造payload 因為href被過濾&#xff0c;可以試一下大寫HREF 初試payload…

沒人愿意和我們最好的工程師一起工作

幾年前&#xff0c;有一位技術非常好的工程師&#xff08;我們叫他“喬恩”&#xff09;為我工作。 他的代碼寫得很好&#xff0c;代碼審查&#xff08;PRs&#xff09;也完成得很快。從技術角度來看&#xff0c;他是個出色的工程師。 但是我們從其他工程師那里得到了一些關于…

Python實現解碼二進制數據以匹配給定的C++結構體

要在Python中實現解碼二進制數據以匹配給定的C結構體Ytest&#xff0c;你需要了解每個字段在結構體中的偏移量&#xff08;由于結構體內存對齊&#xff0c;這些偏移量可能與字段的順序和大小不完全對應&#xff09;。不過&#xff0c;在沒有指定內存對齊的情況下&#xff0c;我…

使用nvm管理node多版本(安裝、卸載nvm,配置環境變量,更換npm淘寶鏡像)淘寶的鏡像域名更換

最近 使用nvm 管理 node 的時候發現nvm install node版本號 總是失敗。 nvm install 20.12.2Error retrieving "http://npm.taobao.org/mirrors/node/latest/SHASUMS256.txt": HTTP Status 404查看原因&#xff0c;因為淘寶的鏡像域名更換&#xff0c;由于 npm.taob…

2020職稱繼續教育--發揮好“顯著優勢”,堅持和完善生態文明制度體系,促進人與自然和諧共生

單選題&#xff08;共7題&#xff0c;每題5分&#xff09; 1、我國生態脆弱區廣布&#xff0c;適宜生存的空間不足&#xff08;&#xff09;。 B、三分之一 2、按照傳統文化的說法&#xff0c;制度體系與治理體系&#xff0c;是“體”和“用”的關系&#xff0c;強調&#xff…

BI系統:數據驅動的決策利器,引領企業走向智能化

在當今這個數據驅動的時代&#xff0c;商業智能&#xff08;BI&#xff09;系統已成為企業不可或缺的工具。BI系統不僅提高了數據處理和分析的效率&#xff0c;更重要的是&#xff0c;它能夠幫助企業做出更加明智和精準的決策。在數聚多年的從業經驗來看&#xff0c;BI系統的重…

基于直接二元搜索的片上偏振分束器設計 (Nature Photonics, 9, 6, (2015))案例復現

時間—2024.6.08 騰訊會議 智能算法驅動的光子學設計與應用

Dream

好像很多人夢寐以求的都是別人已經擁有的&#xff0c;多少人奮斗一生的目標&#xff0c;卻只是別人的起點&#xff0c;人生而自由&#xff0c;只是不在枷鎖之中&#xff0c;生活中沒有人不遺憾&#xff0c;只是沒有人喊疼&#xff0c;時間不會重來&#xff0c;已經過去了就讓它…

內存泄露問題? 怎么解決

內存泄漏在Android應用開發中是一個常見問題&#xff0c;它發生在對象不再被使用時&#xff0c;但仍然被引用&#xff0c;導致垃圾回收器無法釋放其占用的內存。這會逐漸消耗應用可用內存&#xff0c;最終可能導致應用運行緩慢、崩潰或被系統終止。以下是一些常見的內存泄漏場景…

vue3 使用vant

使用前提&#xff1a; vite創建的vue3項目 vanthttps://vant-ui.github.io/vant/#/zh-CN/home npm i vant 引入樣式&#xff1a; main.js import vant/lib/index.css vant封裝 import { showLoadingToast,closeToast,showDialog,showConfirmDialog } from vant;export func…

Typora圖床配置優化(PicGo-Core(command line) 插件 + gitee)

Typora圖床配置優化&#xff08;PicGo-Core(command line) 插件 gitee&#xff09; 前言 在日常使用Typora編寫markdown筆記時&#xff0c;經常需要插入圖片來幫助理解和整理邏輯。然而&#xff0c;由于圖片保存在本地&#xff0c;上傳到網上時經常出現圖片不見或錯誤警告的…

育菁桌面式數控機床助力教育裝備

桌面式數控機床是一種小型化的數控機床&#xff0c;它通常具有緊湊的設計和較小的體積&#xff0c;可以放置在桌面上進行操作。 這種車床結合了數控技術&#xff0c;通過計算機編程來控制機床的運動和加工過程&#xff0c;以實現高精度、高效率的工件加工。 桌面式數控車床是一…

如何部署一套高可用性的醫院信息管理系統?基于華為云、SpringBoot、Vue及Jenkins、Gitlab的CI/CD流程

目錄 一、項目背景 二、項目架構 三、項目部署流程 1、前端部署 2、后端部署 3、監控與運維 四、項目過程 一、項目背景 隨著醫療信息化程度的不斷加深&#xff0c;醫院信息管理系統的穩定性和可用性成為了醫療機構日常運營的關鍵。在這個數字化時代&am…

選擇快充時代下的理想充電器與電壓誘騙芯片PW6606

隨著科技的不斷進步&#xff0c;我們的電子設備對于充電速度和效率的要求越來越高。在快充技術迅猛發展的今天&#xff0c;了解不同類型的充電器及其對應的快充協議&#xff0c;以及如何選擇適合的電壓誘騙芯片&#xff0c;對于提升充電體驗和保障設備安全顯得尤為重要。 一、快…

生信網絡學院|05月31日《SOLIDWORKS Manage 產品周期管理》

課程主題&#xff1a;SOLIDWORKS Manage 產品周期管理 課程時間&#xff1a;2024年05月31日 14:00-14:30 主講人&#xff1a;付艦 生信科技 PLM實施顧問 1、SOLIDWORKS Manage介紹 2、周期流程管理 3、產品項目管理 4、項目會議管理 5、項目問題管理 安裝騰訊會議客戶端…

Android 13 VSYNC重學習

Android 13 VSYNC重學習 引言 學無止境&#xff0c;一個字干就完事&#xff01; 源碼參考基于Android 13 aosp&#xff01; 一. Android VSync模塊開胃菜 在開始正式的分析之前&#xff0c;我們先簡單對Android的Vsync模塊簡單介紹下,如下圖所示&#xff0c;其中: HW_VSync是…

【Java面試】一、Redis篇(上)

文章目錄 0、準備1、緩存穿透&#xff1a;不存在的key2、緩存擊穿&#xff1a;熱點key過期3、緩存雪崩&#xff1a;大批key同時過期4、雙寫一致性4.1 要求高一致性4.2 允許一定的一致延遲 5、面試 0、準備 Redis相關概覽&#xff1a; 以簡歷上所列的項目為切入點&#xff0c;展…

Steamdeck使用Windows系統游玩雪地奔馳時閃退問題解決方法

我非常喜歡雪地奔馳這款游戲&#xff0c;買sd的一部分也是為了它。可在我打開這個游戲時&#xff0c;游戲發生閃退問題。查閱了網絡各個途徑&#xff0c;基本沒有解決方法。因此我自己分析終于解決該問題。以下是我解決問題的思路&#xff0c;僅供記錄參考&#xff1a; 游戲在崩…