2/e 1998/04 MFC 1/e Windows MFC MFC 2/e 1998/05 1998 UNALIS 3/e 2/e 2/e 3/e 3/e MFC 2/e MFC 3/e MFC MFC 2/e VC5+MFC42 VC6+MFC421 MFC 2/e 1
MFC 2/e PDF http://www.jjhou.com http://expert.csdn.net/jjhou GBK mirror - anyway solution MFC 1/e MFC 2/e jjhou@ccca.nctu.edu.tw 2
dissecting MFC 2/e part1.pdf chap1~chap3 3,384,209 dissecting MFC 2/e part2.pdf chap4 2,448,990 dissecting MFC 2/e part3.pdf chap5~chap7 2,158,594 dissecting MFC 2/e part4.pdf chap8~chap16 5,171,266 dissecting MFC 2/e part5.pdf appendix A,B,C,D 1,527,111 -- the end 3
山 高 月 小 水 落 石 出
深 入 淺 出 MFC ( 第 ㆓ 版 使 用 Visual C++ 5.0 & MFC 4.2) Dissecting MFC (Second Edition Using Visual C++ 5.0 & MFC 4.2) 侯 俊 傑 著 松 崗 電 腦 圖 資 料 股 份 有 限 公 司 印 行
Pioneer is the one that an arrow on his back
.. 1996 11 MFC Application Framework MFC MFC MFC MFC MFC MFC MFC MFC.. enjoyable Kruglinski Inside Visual C++ Hou Dissecting MFC MFC Programming i
. lnlo@hkstart.com Inside Visual C++ 4.0 MFC 50~70 MFC MFC 30~40 virtual function template exception... Lung Feng <h6003@kl.ntou.edu.tw> 1992 Windows MFC ii
Asing Chang <asing@ms4.hinet.net>, Dissecting MFC Petzold Pietrek, Jaguar <simon830@ms7.hinet.net> R & D MFC Shieh <lmy64621@mail.seeder.net.tw> MFC MFC.. MFC MFC MFC Visual C++ 4.0 iii
yrleu@netrd.iii.org.tw Visual C++ 4.0 Windows Programming Windows 95 MFC MFC Windows Programming MFC Fox Wang MFC Windows Programming Charles Petzold Programming Windows 95 David J.Kruglinski Inside Visual C++ MFC iv
. robin.hood@ibm.net MFC 640KB MFC... MFC CWinApp CDocManager. skyman@tpts4.seed.net.tw MFC v
Rusty CompBook MFC MFC MFC Windows SDK Programming Windows 95 with MFC MFC. Richard MFC step0~step1 10:00 Shelly vi
Jedi Your books is already 100 times better than any translation on the market. I won't think of to get a Chinese computer book unless you wrote it or translated it. shiowli@ms13.hinet.net 1997/11 MFC Windows Windows MFC puppet MFC Charles Petzold David J.Kruglinski eureka "anchor" <hcy89@mozart.ee.ncku.edu.tw> I am a student of NCKU EE Department, I am also a reader of you books. Your Book give me a lot of help on my research. vii
z22356@ms13.hinet.net MFC 80% David david@mail.u-p-c.com Windows C++ Visual Basic Windows MFC How What Why Windows How What Why!!!! viii
Chengwei chengwei@accton.com.tw MFC!! Fox Wang <wych@ms10.hinet.net> wuwei akira <hakira@hotmail.com> I'm your reader in Shanghai JiaoTong University in mainland. Your <Programming WINDOWS MFC> MFC is a very good book that I wanted to have for years. Thank you very much. So I want to know if there are another your book that I can buy in mainland? I hope to read your new books. ix
hon.bbs@bbs.ee.ncu.edu.tw " " " " "wking" <wking@telekbird.com.cn> Microsoft Developer Studio MFC Microsoft Foundation Classes C++ 32 Windows MFC macros C++ VC++ C++ C++ C++ VC++ VC++ Microsoft Developer Studio MFC C++ VC++ C++ MFC WINDOWS MFC MFC email x
EricYang <robe@freebsd.csie.nctu.edu.tw> cview.bbs@cis.nctu.edu.tw News / BBS programming MFC sir MFC... "lishyhan" <lishyhan@ms14.hinet.net> MFC dengqi@glocom-us.com embedded system software C Assembly embedded system Intel processor embedded system Motorola processor Intel 8086, 8051 Motorola 68000 assembly framework project Win95 framework VC++ MFC xi
News / BBS CompBook and/or programming MFC MFC ob9@bbs.ee.ntu.edu.tw MFC os2.bbs@titan.cc.ntu.edu.tw!! openwin.bbs@cis.nctu.edu.tw MFC sir MFC... ~~ Rosario.bbs@bbs.ntu.edu.tw MFC ~~~ C++ Visual C++ DOS Windows? hschin.bbs@bbs.cs.nthu.edu.tw MFC xii
News / BBS CompBook and/or programming VISUAL C++? wayne.bbs@bbs.ee.ncu Visual C++ Inside visual C++ MFC MFC Sagitta.bbs@firebird.cs.ccu.edu.tw Inside Visual C++ 4.0 MFC ( ) MFC MFC MFC Windows MFC dickg.bbs@csie.nctu.edu.tw MFC so... on-line help VC Rusty (Rusty) Programming Windows 95 with MFC Jeff Prosise / Microsoft Press Inside Visual C++ MFC MFC xiii
News / BBS CompBook and/or programming Visual C++ kuhoung.bbs@csie.nctu.edu.tw (1) Inside Visual C++ 5.0 (2) MFC Professional 5.0 (3) Mr. Any Books "howard" <lm3@ms22.hinet.net> SDK MFC MSDN VC Windows help? MFC "apexsoft" <lishyhan@ms14.hinet.net> Visual C++ MFC SDK CCA.bbs@cis.nctu.edu.tw help C++ MFC Document/View/Frame Dynamic Creation, Message mapping MFC MFC trace code xiv
News / BBS CompBook and/or programming DECLARE_DYNCREATE, DECLARE_DYNAMIC, IMPLEMENT_DYNAMIC, IMPLEMENT_DYNCREATE, DECLA RE_MESSAGE_MAP, BEGIN_MESSAGE_MAP, END_MESSAGE_MAP titoni MFC 2/e MFC... MFC... basic -> FORTRAN -> C -> C++... szu.bbs@bbs.es.ncku.edu.tw frame1... SDK Data structure xv
bin_zhou I am your reader of WINDOWS MFC MFC. I'm leaving in HUBEI WUHAN. Now, I have already get the book in HUA_ZHONG_LI_GONG_DA_XUE. And I am interested in this book very much. a8756001@mail.npust.edu.tw, MFC MFC Visual C++ IDE MFC Mike Dong <mikedong@online.sh.cn> C/C++ WINDOWS MFC MFC C++ MFC WINDOWS SDK WINDOWS API MFC MFC Windows API classes MFC framework programming classes member functions Windows APIs xvi
luke@orchid.ee.ntu.edu.tw MFC K advanced compiler trace java compiler mail "BaiLu" <jinyang@public1.wx.js.cn> DELPHI PB WINDOWS MFC MFC C++ "Zhang Yongzhong" <yongzhongz@263.net> WINDOWS MFC xvii
xviii
MFC 9150 VC++ MFC MFC application framework 1 Windows 2 3 1 runtime type information dynamic creation persistence document/view K 2 message based event driven programming model 3 message mapping command routing K 1
MFC Internals MFC Internals MFC Internals Dissecting MFC MFC programming MFC programming MFC Internals Dissecting MFC programming MFC MFC application framework 99.99999% programmer application framework... BBS Internet News 2
Visual C++ 5.0 & MFC 4.21 Visual C++ 6.0 programming MFC Visual C++ 6.0. 1998.09.11 jjhou@ccca.nctu.edu.tw FAX 886-3-5733976 3
4
Visual C++ 5.0 MFC 4.2 5
MFC. 1997.04.15 jjhou@ccca.nctu.edu.tw FAX 886-3-5733976 6
version control version control version control version control MFC C++ MFC Windows application framework MFC programming 7
MFC Windows SDK application framework MFC MFC Programming Windows 95 with MFC Jeff Prosise Microsoft Press Inside Visual C++ 4.0 David J.Kruglinski Microsoft Press MFC MFC Visual C++ MFC MFC MFC MFC C++ MFC MFC MFC application framework MFC 8
MFC MFC application framework MFC Windows C++ Visual C++ Visual C++ Visual C++ application framework MFC Visual C++ AppWizard AppWizard Visual C++ Scribble Runtime Type Information RTTI Dynamic Creation Persistence Serialization Message Mapping Command Routing Scribble 9
1994/08 Visual C++ MFC 1995/04 MFC Microsoft Systems Journal 1995/07 Paul Dilascia Meandering Through the Maze of MFC Message and Command Routing Addison Wesley 1996/06 MFC Internals Programming Windows 95 with MFC Inside Visual C++ 4.0 MFC Runtime Type Information Dynamic Creation Message Mapping Command Routing MFC DOS C++ MFC MFC MFC application framework MFC MFC application framework MFC MFC application framework 10
1996.08.15 P.S.?! 11
12
目 錄 目 錄 (* 表 示 本 版 新 增 內 容 ) * 讀 者 來 函 / 1 * 第 ㆓ 版 序 / 5 第 ㆒ 版 序 / 7 目 錄 / 13 第 0 章 你 ㆒ 定 要 知 道 ( 導 讀 ) / 27 這 本 書 適 合 誰 / 27 你 需 要 什 麼 技 術 基 礎 / 29 你 需 要 什 麼 軟 硬 體 環 境 / 29 讓 我 們 使 用 同 ㆒ 種 語 言 / 30 本 書 符 號 習 慣 / 34 磁 片 內 容 與 安 裝 / 34 範 例 程 式 說 明 / 34 與 前 版 本 之 差 異 / 39 如 何 聯 絡 作 者 / 40 第 ㆒ 篇 勿 在 浮 砂 築 高 臺 - 本 書 技 術 前 提 / 001 第 1 章 Win32 程 式 基 本 觀 念 / 003 Win32 程 式 開 發 流 程 / 005 需 要 什 麼 函 式 庫 (.LIB) / 005 需 要 什 麼 表 頭 檔 (.H) / 006 13
深 入 淺 出 MFC 以 訊 息 為 基 礎, 以 事 件 驅 動 之 / 007 ㆒ 個 具 體 而 微 的 Win32 程 式 / 009 程 式 進 入 點 WinMain / 015 視 窗 類 別 之 註 冊 與 視 窗 之 誕 生 / 016 訊 息 迴 路 / 018 視 窗 的 生 命 樞 - 視 窗 函 式 / 019 訊 息 映 射 (Message Map) 雛 形 / 020 對 話 盒 的 運 作 / 022 模 組 定 義 檔 (.DEF) / 024 資 源 描 述 檔 (.RC) / 024 Windows 程 式 的 生 與 死 / 025 閒 置 時 間 的 處 理 :OnIdle / 027 * Console 程 式 / 028 * Console 程 式 與 DOS 程 式 的 差 別 / 029 * Console 程 式 的 編 譯 聯 結 / 031 * JBACKUP:Win32 Console 程 式 設 計 / 032 * MFCCON:MFC Console 程 式 設 計 / 035 * 什 麼 是 C Runtime Library 的 多 緒 版 本 / 038 行 程 與 執 行 緒 (Process and Thread) / 039 核 心 物 件 / 039 ㆒ 個 行 程 的 誕 生 與 死 亡 / 040 產 生 子 行 程 / 041 ㆒ 個 執 行 緒 的 誕 生 與 死 亡 / 044 * 以 _beginthreadex 取 代 CreateThread / 046 執 行 緒 優 先 權 (Priority) / 048 * 多 緒 程 式 設 計 實 例 / 050 14
目 錄 第 2 章 C++ 的 重 要 性 質 / 055 類 別 及 其 成 員 - 談 封 裝 (encapsulation) / 056 基 礎 類 別 與 衍 生 類 別 - 談 繼 承 (Inheritance)/ 057 this 指 標 / 061 虛 擬 函 式 與 多 型 (Polymorphism) / 062 類 別 與 物 件 大 解 剖 / 077 Object slicing 與 虛 擬 函 式 / 082 靜 態 成 員 ( 變 數 與 函 式 ) / 085 C++ 程 式 的 生 與 死 : 兼 談 建 構 式 與 解 構 式 / 088 * ㆕ 種 不 同 的 物 件 生 存 方 式 / 090 * 所 謂 "Unwinding" / 092 執 行 時 期 型 別 資 訊 (RTTI) / 092 動 態 生 成 (Dynamic Creation) / 095 異 常 處 理 (Exception Handling) / 096 Template / 100 Template Functions / 101 Template Classes / 104 Templates 的 編 譯 與 聯 結 / 106 第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 / 109 MFC 類 別 階 層 / 111 Frame1 範 例 程 式 / 111 MFC 程 式 的 初 始 化 過 程 / 115 Frame2 範 例 程 式 / 118 RTTI( 執 行 時 期 型 別 辨 識 ) / 122 CRuntimeClass 與 類 別 型 錄 網 / 123 DECLARE_DYNAMIC / IMPLEMENT_DYNAMIC 巨 集 / 125 Frame3 範 例 程 式 / 132 15
深 入 淺 出 MFC IsKindOf( 型 別 辨 識 ) / 140 Frame4 範 例 程 式 / 141 Dynamic Creation( 動 態 生 成 ) / 143 DECLARE_DYNCREATE / IMPLEMENT_DYNCREATE 巨 集 / 144 Frame6 範 例 程 式 / 151 Persistence( 永 續 生 存 ) 機 制 / 160 Serialize( 資 料 讀 寫 ) / 161 DECLARE_SERIAL/IMPLEMENT_SERIAL 巨 集 / 167 沒 有 範 例 程 式 / 170 Message Mapping( 訊 息 映 射 ) / 170 Frame7 範 例 程 式 / 181 Command Routing( 命 令 繞 行 ) / 191 Frame8 範 例 程 式 / 203 * 本 章 回 顧 / 216 第 ㆓ 篇 欲 善 工 事 先 利 其 器 - Visual C++ 5.0 開 發 工 具 / 217 第 4 章 Visual C++ - 整 合 性 軟 體 開 發 環 境 / 219 安 裝 與 組 成 / 220 ㆕ 個 重 要 的 工 具 / 234 內 務 府 總 管 :Visual C++ 整 合 開 發 環 境 / 236 關 於 project / 237 關 於 工 具 設 定 / 241 Source Browser / 243 Online Help / 247 除 錯 工 具 / 249 VC++ 除 錯 器 / 251 Exception Handling / 255 16
目 錄 程 式 碼 產 生 器 - AppWizard / 257 東 圈 西 點 完 成 MFC 程 式 骨 幹 / 258 Scribble Step0 / 270 威 力 強 大 的 資 源 編 輯 器 / 294 Icon 編 輯 器 / 295 Cursor 編 輯 器 / 296 Bitmap 編 輯 器 / 297 ToolBar 編 輯 器 / 297 VERSIONINFO 資 源 編 輯 器 / 299 String Table 編 輯 器 / 300 Menu 編 輯 器 / 301 Accelerator 編 輯 器 / 303 Dialog 編 輯 器 / 304 * Console 程 式 的 專 案 管 理 / 305 第 ㆔ 篇 淺 出 MFC 程 式 設 計 / 309 第 5 章 總 觀 Application Framework / 311 什 麼 是 Application Framework / 311 侯 捷 怎 麼 說 / 312 我 怎 麼 說 / 314 別 怎 麼 說 / 317 為 什 麼 使 用 Application Framework / 321 Microsoft Foundation Class(MFC) / 324 白 頭 宮 女 話 寶 :Visual C++ 與 MFC / 327 縱 覽 MFC / 329 General Purpose classes / 330 Windows API classes / 333 17
深 入 淺 出 MFC Application framework classes / 334 High level abstractions / 334 Afx 全 域 函 式 / 335 * MFC 巨 集 (macros) / 335 * MFC 資 料 型 態 (data type) / 338 第 6 章 MFC 程 式 設 計 導 論 - MFC 程 式 的 生 死 因 果 / 343 不 ㆓ 法 門 : 熟 記 MFC 類 別 的 階 層 架 構 / 346 需 要 什 麼 函 式 庫 (.LIB) / 347 需 要 什 麼 含 入 檔 (.H) / 349 簡 化 的 MFC 程 式 架 構 - 以 Hello MFC 為 例 / 351 Hello 程 式 原 始 碼 / 352 MFC 程 式 的 來 龍 去 脈 / 357 我 只 借 用 兩 個 類 別 :CWinApp 和 CFrameWnd / 358 CWinApp - 取 代 WinMain 的 位 / 359 CFrameWnd - 取 代 WndProc 的 位 / 362 引 爆 器 - Application object / 364 隱 晦 不 明 的 WinMain / 366 AfxWinInit - AFX 內 部 初 始 化 動 作 / 370 CWinApp::InitApplication / 372 CMyWinApp::InitInstance / 374 CFrameWnd::Create 產 生 主 視 窗 ( 並 註 冊 視 窗 類 別 ) / 376 * 奇 怪 的 視 窗 類 別 名 稱 Afx:b:14ae:6:3e8f / 387 視 窗 顯 示 與 更 新 / 389 CWinApp::Run - 程 式 生 命 的 活 水 源 頭 / 390 把 訊 息 與 處 理 函 式 串 接 在 ㆒ 起 :Message Map 機 制 /394 來 龍 去 脈 總 整 理 / 397 Callback 函 式 / 398 18
目 錄 * 閒 置 時 間 (idle time) 的 處 理 :OnIdle / 403 Dialog 與 Control / 406 通 用 對 話 盒 (Common Controls) / 407 本 章 回 顧 / 409 第 7 章 簡 單 而 完 整 :MFC 骨 幹 程 式 / 411 不 ㆓ 法 門 : 熟 記 MFC 類 別 的 階 層 架 構 / 411 MFC 程 式 的 UI 新 風 貌 / 412 Document/View 支 撐 你 的 應 用 程 式 / 419 利 用 Visual C++ 工 具 完 成 Scribble step0 / 423 骨 幹 程 式 使 用 哪 些 MFC 類 別? / 423 Document Template 的 意 義 / 430 Scribble 的 Document/View 設 計 / 436 主 視 窗 的 誕 生 / 438 工 具 列 和 狀 態 列 的 誕 生 (Toolbar & Status bar) / 440 滑 鼠 拖 放 (Drag and Drop) / 442 訊 息 映 射 (Message Map) / 445 標 準 選 單 File/Edit/View/Window/Help / 446 對 話 盒 / 449 改 用 CEditView / 450 第 ㆕ 篇 深 入 MFC 程 式 設 計 / 453 第 8 章 Document-View 深 入 探 討 / 455 為 什 麼 需 要 Document-View( 形 而 )/ 455 Document / 457 View / 458 Document Frame(View Frame) / 459 19
深 入 淺 出 MFC Document Template / 459 CDocTemplate 管 理 CDocument / CView / CFrameWnd / 460 Scribble Step1 的 Document( 資 料 結 構 設 計 ) / 468 MFC Collection Classes 的 選 用 / 469 Template-Based Classes / 471 Template-Based Classes 的 使 用 方 法 / 471 CScribbleDoc 的 修 改 / 473 SCRIBBLEDOC.H / 475 SCRIBBLEDOC.CPP / 477 文 件 :㆒ 連 串 的 線 條 / 481 CScribbleDoc 的 成 員 變 數 / 481 CObList / 481 CScribbleDoc 的 成 員 函 式 / 482 線 條 與 座 標 點 / 484 CStroke 的 成 員 變 數 / 484 CArray<CPoint, CPoint> / 484 CStroke 的 成 員 函 式 / 484 Scribble Step1 的 View: 資 料 重 繪 與 編 輯 / 487 CScribbleView 的 修 改 / 488 SCRIBBLEVIEW.H / 488 SCRIBBLEVIEW.CPP / 489 View 的 重 繪 動 作 - GetDocument 和 OnDraw / 493 CScribbleView 的 成 員 變 數 / 493 CScribbleView 的 成 員 函 式 / 493 View 與 使 用 者 的 交 談 ( 滑 鼠 訊 息 處 理 實 例 ) / 495 ClassWizard 的 輔 佐 / 496 WizardBar 的 輔 佐 / 498 Serialize: 物 件 的 檔 案 讀 寫 / 498 20
目 錄 Serialization 以 外 的 檔 案 讀 寫 動 作 / 499 檯 面 的 Serialize 動 作 / 501 檯 面 的 Serialize 寫 檔 奧 秘 / 507 檯 面 的 Serialize 讀 檔 奧 秘 / 514 DYNAMIC / DYNCREATE / SERIAL ㆔ 巨 集 / 522 Serializable 的 必 要 條 件 / 527 CObject 類 別 / 529 IsKindOf / 529 IsSerializable / 530 CObject::Serialize / 531 CArchive 類 別 / 531 operator<< 和 operator>> / 532 效 率 考 量 / 536 自 定 SERIAL 巨 集 給 抽 象 類 別 使 用 / 537 在 CObList 加 入 CStroke 以 外 的 類 別 / 537 Document 與 View 交 流 - 為 Scribble Step4 做 準 備 / 543 第 9 章 訊 息 映 射 與 命 令 繞 行 / 547 到 底 要 解 決 什 麼 / 547 訊 息 分 類 / 549 萬 流 歸 宗 Command Target(CCmdTarget) / 550 ㆔ 個 奇 怪 的 巨 集,㆒ 張 巨 大 的 網 / 551 DECLARE_MESSAGE_MAP 巨 集 / 552 訊 息 映 射 網 的 形 成 :BEGIN_/ON_/END_ 巨 集 / 544 米 諾 托 斯 (Minotauros) 與 西 修 斯 (Theseus) / 560 兩 萬 五 千 里 長 征 - 訊 息 的 流 竄 / 566 直 線 溯 (㆒ 般 Windows 訊 息 ) / 567 拐 彎 溯 (WM_COMMAND 命 令 訊 息 ) / 572 21
深 入 淺 出 MFC 羅 塞 達 碑 石 :AfxSig_xx 的 秘 密 / 580 Scribble Step2:UI 物 件 的 變 化 / 585 改 變 選 單 / 585 改 變 工 具 列 / 588 利 用 ClassWizard 連 接 命 令 項 識 別 碼 與 命 令 處 理 函 式 / 590 維 護 UI 物 件 狀 態 (UPDATE_COMMAND_UI) / 594 本 章 回 顧 / 599 第 10 章 MFC 與 對 話 盒 / 601 對 話 盒 編 輯 器 / 602 利 用 ClassWizard 連 接 對 話 盒 與 其 專 屬 類 別 / 606 PENDLG.H / 610 PENDLG.CPP / 610 對 話 盒 的 訊 息 處 理 函 式 / 613 MFC 各 式 各 樣 的 MAP / 615 對 話 盒 資 料 交 換 與 查 核 (DDX & DDV) / 617 MFC 各 式 各 樣 的 DDx_ 函 式 / 621 如 何 喚 起 對 話 盒 / 622 本 章 回 顧 / 625 第 11 章 View 功 能 之 加 強 與 重 繪 效 率 之 提 昇 / 627 同 時 修 改 多 個 Views:UpdateAllViews 和 OnUpdate / 629 在 View 定 義 ㆒ 個 hint / 631 把 hint 傳 給 OnUpdate / 635 利 用 hint 增 加 重 繪 效 率 / 637 可 捲 動 的 視 窗 :CScrollView / 640 大 視 窗 的 小 窗 口 :Splitter / 650 分 裂 視 窗 的 功 能 / 650 22
目 錄 分 裂 視 窗 的 程 式 概 念 / 651 分 裂 視 窗 之 實 作 / 653 本 章 回 顧 / 657 第 12 章 印 表 與 預 覽 / 659 概 觀 / 659 列 印 動 作 的 背 景 原 理 / 663 MFC 預 設 的 印 表 機 制 / 669 Scribble 列 印 機 制 的 補 強 / 685 印 表 機 的 頁 和 文 件 的 頁 / 685 配 置 GDI 繪 圖 工 具 / 687 尺 寸 與 方 向 : 關 於 映 像 模 式 ( 座 標 系 統 ) / 688 分 頁 / 693 表 頭 (Header) 與 表 尾 (Footer)/ 695 動 態 計 算 頁 碼 / 696 列 印 預 覽 (Print Preview) / 697 本 章 回 顧 / 698 第 13 章 多 重 文 件 與 多 重 顯 示 / 701 MDI 和 SDI / 701 多 重 顯 像 (Multiple Views) / 703 視 窗 的 動 態 分 裂 / 704 視 窗 的 靜 態 分 裂 / 707 CreateStatic 和 CreateView / 709 視 窗 的 靜 態 ㆔ 叉 分 裂 / 711 Graph 範 例 程 式 / 713 靜 態 分 裂 視 窗 之 觀 念 整 理 / 724 同 源 子 視 窗 / 725 23
深 入 淺 出 MFC CMDIFrameWnd::OnWindowNew / 726 Text 範 例 程 式 / 727 非 制 式 作 法 的 缺 點 / 734 多 重 文 件 / 736 新 的 Document 類 別 / 736 新 的 Document Template / 739 新 的 UI 系 統 / 740 新 文 件 的 檔 案 讀 寫 動 作 / 742 * 第 14 章 MFC 多 緒 程 式 設 計 (Multi-threaded Programming in MFC) / 745 從 作 業 系 統 層 面 看 執 行 緒 / 745 ㆔ 個 觀 念 : 模 組 行 程 執 行 緒 / 746 執 行 緒 優 先 權 (Priority) / 748 執 行 緒 排 程 (Scheduling) / 751 Thread Context / 751 從 程 式 設 計 層 面 看 執 行 緒 / 752 Worker Threads 和 UI Threads / 754 錯 誤 觀 念 / 754 正 確 態 度 / 755 MFC 多 緒 程 式 設 計 / 755 探 索 CWinThread / 755 產 生 ㆒ 個 Worker Thread / 759 產 生 ㆒ 個 UI Thread / 761 執 行 緒 的 結 束 / 763 執 行 緒 與 同 步 控 制 / 763 MFC 多 緒 程 式 實 例 / 766 24
目 錄 * 第 15 章 定 製 ㆒ 個 AppWizard / 771 到 底 Wizard 是 什 麼? / 733 Custom AppWizard 的 基 本 操 作 / 774 剖 析 AppWizard Components / 779 Dialog Templates 和 Dialog Classes / 780 Macros / 781 Directives / 783 動 手 修 改 Top Studio AppWizard / 784 利 用 資 源 編 輯 器 修 改 IDD_CUSTOM1 對 話 窗 畫 面 / 785 利 用 ClassWizard 修 改 CCustom1Dlg 類 別 / 785 改 寫 OnDismiss 虛 擬 函 式, 在 其 定 義 macros / 787 修 改 text template / 788 Top Studio AppWizard 執 行 結 果 /789 更 多 的 資 訊 / 790 * 第 16 章 站 眾 的 肩 膀 - 使 用 Components 和 ActiveX Controls / 791 什 麼 是 Component Gallery / 792 使 用 Components / 795 Splash screen / 795 System Info for About Dlg / 797 Tips of the Day / 798 Components 實 際 運 用 :ComTest 程 式 / 799 修 改 ComTest 程 式 內 容 / 818 使 用 ActiveX Controls / 822 ActiveX Control 基 礎 觀 念 :Properties Methods Events / 823 ActiveX Controls 的 五 大 使 用 步 驟 / 825 使 用 "Grid" ActiveX Control:OcxTest 程 式 / 827 25
深 入 淺 出 MFC 第 五 篇 附 錄 / 843 附 錄 A 無 責 任 書 評 : 從 搖 籃 到 墳 墓 - Windows 的 完 全 學 習 / 845 * 無 責 任 書 評 :MFC ㆕ 大 王 / 856 附 錄 B Scribble Step5 程 式 原 始 碼 列 表 / 873 附 錄 C Visual C++ 5.0 MFC 範 例 程 式 總 覽 / 915 * 附 錄 D 以 MFC 重 建 Debug Window(DBWIN) / 921 26
第 0 章 你 ㆒ 定 要 知 道 ( 導 讀 ) 第 0 章 深 入 淺 出 MFC MFC Microsoft Foundation Classes Windows Visual C++ MFC Application Object Framework Oriented Runtime Dynamic Type Creation Persistence Information Message Mapping Command Routing MFC MFC in32 message based, event driven, multitasking, multithreading, console programming C++ this 27
深 入 淺 出 MFC template exception handling MFC Console Visual C++ Visual C++ User's Guide MFC MFC MFC MFC MFC MFC MFC MFC MFC MFC MFC Eureka Eureka Console DOS-like Windows DOS Box Application Framework Scribble Visual C++ MFC 13 Multi-View Multi-Document 14 ~16 MFC Custom AppWizard Component Gallery ActiveX controls components 28
第 0 章 你 ㆒ 定 要 知 道 ( 導 讀 ) Windows C/SDK C++/MFC C++/MFC 1. C++ 2. Windows callback... 3. Microsoft Foundation Classes MFC 4. Visual C++ C++ C++ C++ MFC MFC C++ C++ inheritance MFC MFC C++ C++ C++ C++ Win16 Win32 DOS Win32 Wizards message loop window procedure Windows -- MFC OWL Open Class Library Visual C++ Borland C++ VisualAge C++ Windows 95 Windows NT Visual C++ 32 Visual C++ 5.0 29
深 入 淺 出 MFC RAM 16MB RAM Pentium 133 96M RAM 2GB 17 Visual C++ Windows 95 Visual C++ 5.0 class object framework Document View API - Application Programming Interface API C DOS interrupt vector API OLE Interface C++ API MFC Windows C++ API 30
第 0 章 你 ㆒ 定 要 知 道 ( 導 讀 ) SDK - Software Development Kit SDK Phar Lap 386 DOS Extender SDK Windows SDK Microsoft Windows raw API SDK Windows API SDK API Borland C++ SDK API Windows SDK Windows raw API MFC - Microsoft Foundation Classes Windows API C++ C++ Class Library Windows MFC Windows Symantec C++ WATCOM C/C++ MFC Borland C++ MFC -- OWL OWL - Object Windows Library Application Framework C++ Borland C++ Application Framework - C++ Application Framework MFC OWL IBM Open Class Library Application Framework C++ Java Delphi API - Application Programming Interface DLL - Dynamic Link Library GUI - Graphics User Interface MDI - Multiple Document Interface 31
深 入 淺 出 MFC MFC - Microsoft Foundation Class OLE - Object Linking & Embedded OWL - Object Windows Library SDK - Software Development Kit SDI - Single Document Interface UI - User Interface WinApp : Windows Application control drag & drop Icon linked-list listbox notification preemptive process queue template Edit ListBox Button... template C++ class template Windows dialog template MFC Document Template window class window focus 32
第 0 章 你 ㆒ 定 要 知 道 ( 導 讀 ) class object constructor destructor operator override overloading Encapsulation Inheritance Dynamic Binding late binding virtual function Polymorphism member function data member Base Class Derived Class "double click" "click" Class Object Menu 33
深 入 淺 出 MFC CreateWindow strtok WM_CREATE ID_FILE_OPEN CDocument::Serialize m_pnewviewclass BEGIN_MESSAGE_MAP public Win32 C Runtime Windows ID MFC MFC MFC C++ File/New New New Project EXE.OBJ.RES Visual C++ 5.0 DOS XCOPY Generic Win32 Win32 Jbackup Win32 console 34
第 0 章 你 ㆒ 定 要 知 道 ( 導 讀 ) Visual C++ DOS-like Win32 API MFCcon console Visual C++ DOS-like MFC classes MltiThrd Win32 CreateThread Frame1~8 console DOS-like Application Framework Persistence Frame1 MFC application object Frame2 MFC WinMain Frame3 CRuntimeClass DYNAMIC Frame4 IsKindOf RTTI Frame5 Dynamic Creation MFC 2.5 Frame6 Dynamic Creation MFC 4.x Frame7 Message Map Frame8 Command Routing Hello MFC MFC Document/View -- MFC 1.0 MFC callback WM_PAINT "Hello MFC" idle time 35
深 入 淺 出 MFC Scribble Step0~Step5 Scribble MFC Generic SDK Visual C++ Class Library User's Guide Scribble Step1~Step7 Visual C++ 5.0 \DEVSTUDIO\VC\MFC\SAMPLES\SCRIBBLE Step1~Step5 Step0 Step6 OnLine Help Step7 OLE Server Scribble Step0 MFC AppWizard MFC Scribble Step1 Document/View WM_PAINT What You See Is What You Get MM_TEXT 15 640 300dpi AppWizard ClassWizard Document CView::OnDraw CDocument::Serialize Scribble Step2 Message 36
第 0 章 你 ㆒ 定 要 知 道 ( 導 讀 ) Mapping Command Routing Scribble Step3 10 pixel ClassWizard MFC DDX/DDV control DDX Dialog Data exchange DDV Dialog Data Validation Scribble Step4-11 Scribble Document Views --! Step4 Document Views Invalidate Region Step1 Document Step1 View Splitter Scribble Step5 12 Step1 CScribbleView::OnDraw 37
深 入 淺 出 MFC Mapping Mode 0.01 Graph 13 Text 13 Document view Graph2 13 Document Document View UI MltiThrd 14 MFC MFC Mltithrd Top 15 AppWizard Top Studio AppWizard MFC AppWizard ComTest 16 Component Gallery components Splash Screen SysInfo Tip Of The Day OcxTest 16 Component Gallery Grid ActiveX control 38
第 0 章 你 ㆒ 定 要 知 道 ( 導 讀 ) MFC 1. Visual C++ 4.0 Visual C++ 5.0 Visual C++ - MFC Visual C++ 5.0 MFC 4.2 2. Console Win32 Mltithrd 3. 4. Frame5 MFC 2.5 Dynamic Creation 5. Visual C++ 5.0 Console 6. Afx:x:y:z:w Hello idle time 7. 14~16 8. < / > MFC 9. OWL MFC DBWIN Scribble step1 CStroke Visual C++ 4.2 Visual C++ 5.0 VC++ 4.2 VC++ 5.0 "forward declaration of data structure class" VC++ CStroke SCRIBBLEDOC.H CScribbleDoc CScribbleDoc SCRIBBLEDOC.H #477 39
深 入 淺 出 MFC Email jjhou@ccca.nctu.edu.tw 39 13 FAX 03-5733976 40
1 深 入 淺 出 MFC 2nd Edition 1
2 第 ㆒ 篇 勿 在 浮 砂 築 高 台
Win32 MFC Win32 SDK event driven message based MFC application framework Windows MFC application framework Windows Message Based Event Driven wizard puppet MFC Windows C++ polymorphism Windows 3
Windows Visual C++ MFC Dialog Editor Image Editor Font Editor.DLG.BMP.BMP.ICO.ICO.CUR.CUR.FON.FON.C.H.RC RC Compiler C Compiler.RES.RES.OBJ.OBJ.DEF CvtRes tool text file binary file.lib.lib C C runtime, runtime, DLL Import, DLL Import, LINKER.EXE.EXE RBJ RBJ 4
Win32 Windows UI User Interface RC EXE 1-1 UI UI.ico.bmp.cur.rc RC RC.EXE UI.RES Windows.LIB Windows Windows API.dll DLL Dynamic Link Library.exe.dll.fon.mod.drv.ocx Windows C Runtimes Windows API C Runtimes Visual C++ 4.0 32 small/medium/large : LIBC.LIB - C Runtime MSVCRT.LIB - C Runtime MSVCRT40.DLL import MSVCRT40.DLL Windows API Windows GDI32.DLL USER32.DLL KERNEL32.DLL 5
DLL API import 32 Windows import GDI32.LIB USER32.LIB KERNEL32.LIB Windows 95 16/32 32 GDI32.DLL USER32.DLL KERNEL32.DLL KRNL386.EXE 32 16 DLLs thunking layer APIs Windows API Common Dialog ToolHelp GDI USER KERNEL COMMDLG.DLL TOOLHELP.DLL APIs DLLs import COMDLG32.LIB TH32.LIB Generic makefile.h Windows WINDOWS.H 5000 Visual C++ 4.0 WINDOWS.H API WINDOWS.H WINDOWS.H API system DLLs COMMDLG.DLL MAPI.DLL TAPI.DLL COMMDLG.H MAPI.H TAPI.H 6
message based event driven Windows while USER system queue Windows Windows application queue GetMessage API GUI UNIX X Window OS/2 Presentation Manager Windows MSG msg; while (GetMessage(&msg, NULL, NULL, NULL)) TranslateMessage(&msg); DispatchMessage(&msg); // Windows API MSG Windows : /* Queued message structure */ typedef struct tagmsg } MSG; HWND hwnd; UINT message; // WM_xxx WM_MOUSEMOVE WM_SIZE... WPARAM wparam; LPARAM lparam; DWORD time; POINT pt; 7
window procedure window function Windows API Windows MYAPP.EXE Mouse Driver System message queue Keyboard Driver Messages from other windows PostMessage() Application message queue WinMain(hInst, hprev,...) MSG msg; RegisterClass(...); CreateWindow(...); ShowWindow(...); UpdateWindow(...); while(getmessage(&msg...)) TranslateMessage(...); DispatchMessage(...); } return msg.wparam; } Window Procedure Windows USER Module SendMessage() WndProc(hwnd, msg, wparam, lparam) switch (msg) case WM_CREATE:... case WM_COMMAND:... case WM_LBUTTONDOWN:... case WM_PAINT:... case WM_CLOSE:... case WM_DESTROY:... default: return DefWindowProc(...); } return(0); } 1-2 Windows 8
Win32 Windows Hello Windows 1-2 Win32 Win32 makefile makefile -- generic.res : generic.rc generic.h rc generic.rc : generic.res generic.rc generic.h rc generic.rc makefile makefile NMAKE.EXE Microsoft MAKE.EXE Borland MAKE.EXE 9
Generic.mak DOS nmake generic.mak p.224 #0001 # filename : generic.mak #0002 # make file for generic.exe (Generic Windows Application) #0003 # usage : nmake generic.mak (Microsoft C/C++ 9.00) (Visual C++ 2.x) #0004 # usage : nmake generic.mak (Microsoft C/C++ 10.00) (Visual C++ 4.0) #0005 #0006 all: generic.exe #0007 #0008 generic.res : generic.rc generic.h #0009 rc generic.rc #0010 #0011 generic.obj : generic.c generic.h #0012 cl -c -W3 -Gz -D_X86_ -DWIN32 generic.c #0013 #0014 generic.exe : generic.obj generic.res #0015 link /MACHINE:I386 -subsystem:windows generic.res generic.obj \ #0016 libc.lib kernel32.lib user32.lib gdi32.lib Generic.h #0001 //--------------------------------------------------------------- #0002 // : generic.h #0003 //--------------------------------------------------------------- #0004 BOOL InitApplication(HANDLE); #0005 BOOL InitInstance(HANDLE, int); #0006 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); #0007 LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM); Generic.c Windows API #0001 //--------------------------------------------------------------- #0002 // Generic - Win32 #0003 // Top Studio * J.J.Hou #0004 // : generic.c #0005 // : #0006 // : generic.mak #0007 //--------------------------------------------------------------- #0008 #0009 #include <windows.h> // #0010 #include "resource.h" // #0011 #include "generic.h" // #0012 #0013 HINSTANCE _hinst; // Instance handle #0014 HWND _hwnd; 10
#0015 #0016 char _szappname[] = "Generic"; // #0017 char _sztitle[] = "Generic Sample Application"; // #0018 #0019 //--------------------------------------------------------------- #0020 // WinMain - #0021 //--------------------------------------------------------------- #0022 int CALLBACK WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, #0023 LPSTR lpcmdline, int ncmdshow) #0024 #0025 MSG msg; #0026 #0027 UNREFERENCED_PARAMETER(lpCmdLine); // #0028 #0029 if (!hprevinstance) #0030 if (!InitApplication(hInstance)) #0031 return (FALSE); #0032 #0033 if (!InitInstance(hInstance, ncmdshow)) #0034 return (FALSE); #0035 #0036 while (GetMessage(&msg, NULL, 0, 0)) #0037 TranslateMessage(&msg); #0038 DispatchMessage(&msg); #0039 } #0040 #0041 return (msg.wparam); // PostQuitMessage #0042 } #0043 //--------------------------------------------------------------- #0044 // InitApplication - #0045 //--------------------------------------------------------------- #0046 BOOL InitApplication(HINSTANCE hinstance) #0047 #0048 WNDCLASS wc; #0049 #0050 wc.style = CS_HREDRAW CS_VREDRAW; #0051 wc.lpfnwndproc = (WNDPROC)WndProc; // #0052 wc.cbclsextra = 0; #0053 wc.cbwndextra = 0; #0054 wc.hinstance = hinstance; #0055 wc.hicon = LoadIcon(hInstance, "jjhouricon"); #0056 wc.hcursor = LoadCursor(NULL, IDC_ARROW); #0057 wc.hbrbackground = GetStockObject(WHITE_BRUSH); // #0058 wc.lpszmenuname = "GenericMenu"; //.RC #0059 wc.lpszclassname = _szappname; #0060 11
#0061 return (RegisterClass(&wc)); #0062 } #0063 //--------------------------------------------------------------- #0064 // InitInstance - #0065 //--------------------------------------------------------------- #0066 BOOL InitInstance(HINSTANCE hinstance, int ncmdshow) #0067 #0068 _hinst = hinstance; // #0069 #0070 _hwnd = CreateWindow( #0071 _szappname, #0072 _sztitle, #0073 WS_OVERLAPPEDWINDOW, #0074 CW_USEDEFAULT, #0075 CW_USEDEFAULT, #0076 CW_USEDEFAULT, #0077 CW_USEDEFAULT, #0078 NULL, #0079 NULL, #0080 hinstance, #0081 NULL #0082 ); #0083 #0084 if (!_hwnd) #0085 return (FALSE); #0086 #0087 ShowWindow(_hWnd, ncmdshow); // #0088 UpdateWindow(_hWnd); // WM_PAINT #0089 return (TRUE); #0090 } #0091 //--------------------------------------------------------------- #0092 // WndProc - #0093 //--------------------------------------------------------------- #0094 LRESULT CALLBACK WndProc(HWND hwnd, UINT message, #0095 WPARAM wparam, LPARAM lparam) #0096 #0097 int wmid, wmevent; #0098 #0099 switch (message) #0100 case WM_COMMAND: #0101 #0102 wmid = LOWORD(wParam); #0103 wmevent = HIWORD(wParam); #0104 #0105 switch (wmid) #0106 case IDM_ABOUT: 12
#0107 DialogBox(_hInst, // #0108 "AboutBox", // #0109 hwnd, // #0110 (DLGPROC)About // #0111 ); #0112 break; #0113 #0114 case IDM_EXIT: #0115 // #0116 DestroyWindow (hwnd); #0117 break; #0118 #0119 default: #0120 return (DefWindowProc(hWnd, message, wparam, lparam)); #0121 } #0122 break; #0123 #0124 case WM_DESTROY: // #0125 PostQuitMessage(0); #0126 break; #0127 #0128 default: #0129 return (DefWindowProc(hWnd, message, wparam, lparam)); #0130 } #0131 return (0); #0132 } #0133 //--------------------------------------------------------------- #0134 // #0135 //--------------------------------------------------------------- #0136 LRESULT CALLBACK About(HWND hdlg, UINT message, #0137 WPARAM wparam, LPARAM lparam) #0138 #0139 UNREFERENCED_PARAMETER(lParam); // #0140 #0141 switch (message) #0142 case WM_INITDIALOG: #0143 return (TRUE); // TRUE #0144 #0145 case WM_COMMAND: #0146 if (LOWORD(wParam) == IDOK #0147 LOWORD(wParam) == IDCANCEL) #0148 EndDialog(hDlg, TRUE); #0149 return (TRUE); // TRUE #0150 } #0151 break; #0152 } 13
#0153 return (FALSE); // FALSE #0154 } Generic.rc #0001 //--------------------------------------------------------------- #0002 // : generic.rc #0003 //--------------------------------------------------------------- #0004 #include "windows.h" #0005 #include "resource.h" #0006 #0007 jjhouricon ICON DISCARDABLE "jjhour.ico" #0008 #0009 GenericMenu MENU DISCARDABLE #0010 BEGIN #0011 POPUP "&File" #0012 BEGIN #0013 MENUITEM "&New", IDM_NEW, GRAYED #0014 MENUITEM "&Open...", IDM_OPEN, GRAYED #0015 MENUITEM "&Save", IDM_SAVE, GRAYED #0016 MENUITEM "Save &As...", IDM_SAVEAS, GRAYED #0017 MENUITEM SEPARATOR #0018 MENUITEM "&Print...", IDM_PRINT, GRAYED #0019 MENUITEM "P&rint Setup...", IDM_PRINTSETUP, GRAYED #0020 MENUITEM SEPARATOR #0021 MENUITEM "E&xit", IDM_EXIT #0022 END #0023 POPUP "&Edit" #0024 BEGIN #0025 MENUITEM "&Undo\tCtrl+Z", IDM_UNDO, GRAYED #0026 MENUITEM SEPARATOR #0027 MENUITEM "Cu&t\tCtrl+X", IDM_CUT, GRAYED #0028 MENUITEM "&Copy\tCtrl+C", IDM_COPY, GRAYED #0029 MENUITEM "&Paste\tCtrl+V", IDM_PASTE, GRAYED #0030 MENUITEM "Paste &Link", IDM_LINK, GRAYED #0031 MENUITEM SEPARATOR #0032 MENUITEM "Lin&ks...", IDM_LINKS, GRAYED #0033 END #0034 POPUP "&Help" #0035 BEGIN #0036 MENUITEM "&Contents", IDM_HELPCONTENTS, GRAYED #0037 MENUITEM "&Search for Help On...", IDM_HELPSEARCH, GRAYED #0038 MENUITEM "&How to Use Help", IDM_HELPHELP, GRAYED #0039 MENUITEM SEPARATOR #0040 MENUITEM "&About Generic...", IDM_ABOUT #0041 END 14
#0042 END #0043 #0044 AboutBox DIALOG DISCARDABLE 22, 17, 144, 75 #0045 STYLE DS_MODALFRAME WS_CAPTION WS_SYSMENU #0046 CAPTION "About Generic" #0047 BEGIN #0048 CTEXT "Windows 95", -1,0, 5,144,8 #0049 CTEXT "Generic Application",-1,0,14,144,8 #0050 CTEXT "Version 1.0", -1,0,34,144,8 #0051 DEFPUSHBUTTON "OK", IDOK,53,59,32,14,WS_GROUP #0052 END main WinMain C int main(int argc, char *argv[ ], char *envp[ ]);... } WinMain Windows int CALLBACK WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance,... } LPSTR lpcmdline, int ncmdshow) // Win32 CALLBACK stdcall // // _pascal _cdecl Windows shell Windows 3.1 Windows 95 Windows C startup code WinMain 15
Windows API CreateWindow API RegisterClass RegisterClass WNDCLASS CreateWindow 11 WNDCLASS wc; GENERIC.C GENERIC.C wc.style = CS_HREDRAW CS_VREDRAW; wc.lpfnwndproc = (WNDPROC)WndProc; wc.cbclsextra = 0; wc.cbwndextra = 0; wc.hinstance = hinstance; wc.hicon = LoadIcon(hInstance, "jjhouricon"); wc.hcursor = LoadCursor(NULL, IDC_ARROW); wc.hbrbackground = GetStockObject(WHITE_BRUSH); wc.lpszmenuname = "GenericMenu"; wc.lpszclassname = "Generic"; RegisterClass(&wc); HWND hwnd; hwnd = CreateWindow( "Generic", "Generic Sample Application", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, // left CW_USEDEFAULT, // top CW_USEDEFAULT, // width CW_USEDEFAULT, // height NULL, NULL, hinstance, NULL );... END LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)... } jjhouricon ICON DISCARDABLE "jjhour.ico" GenericMenu MENU DISCARDABLE BEGIN POPUP "&File"... POPUP "&Edit"... POPUP "&Help" } GENERIC.C GENERIC.C GENERIC.RC GENERIC.RC height width 16
1-3 wc.lpfnwndproc CreateWindow ShowWindow WM_PAINT UpdateWindow Generic RegisterClass InitApplication CreateWindow InitInstance int CALLBACK WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpcmdline, int ncmdshow)... } if (!hprevinstance) if (!InitApplication(hInstance)) return (FALSE); if (!InitInstance(hInstance, ncmdshow)) return (FALSE); //-------------------------------------------------- BOOL InitApplication(HINSTANCE hinstance) WNDCLASS wc;... } return (RegisterClass(&wc)); //-------------------------------------------------- BOOL InitInstance(HINSTANCE hinstance, int ncmdshow) _hwnd = CreateWindow(...);... } InitApplication InitInstance Windows 3.x instance RegisterClass 17
InitApplication WinMain hprevinstance instance CreateWindow InitInstance Windows NT Windows 95 Win32 instance Win32 hprevinstance 0 RegisterClass CreateWindow InitApplication InitInstance MFC CWinApp MFC WinMain while (GetMessage(&msg,...)) } TranslateMessage(&msg); // DispatchMessage(&msg); // TranslateMessage DispatchMessage wc.lpfnwndproc ) DispatchMessage 1-2 DispatchMessage USER GetMessage Windows 3.x non-preemptive Windows 95
Windows NT preemptive GetMessage CPU DispatchMessage USER switch/case Windows call back Windows Windows LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) switch/case default: DefWindowProc Windows wparam lparam wparam 16 16 32 32 Windows Programming Modal call back GetMessage 19
callback Message Map MFC MFC MSGMAP_ENTRY dim struct MSGMAP_ENTRY UINT nmessage; LONG (*pfn)(hwnd, UINT, WPARAM, LPARAM); }; #define dim(x) (sizeof(x) / sizeof(x[0])) MSGMAP_ENTRY pfn nmessage C++ _messageentries[ ] _commandentries[ ] // struct MSGMAP_ENTRY _messageentries[] = WM_CREATE, OnCreate, WM_PAINT, OnPaint, WM_SIZE, OnSize, WM_COMMAND, OnCommand, WM_SETFOCUS, OnSetFocus, WM_CLOSE, OnClose, WM_DESTROY, OnDestroy, } ; 20
// Command-ID struct MSGMAP_ENTRY _commandentries = IDM_ABOUT, OnAbout, IDM_FILEOPEN, OnFileOpen, IDM_SAVEAS, OnSaveAs, } ; WM_COMMAND //---------------------------------------------------------------------- // //---------------------------------------------------------------------- LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) int i; for(i=0; i < dim(_messageentries); i++) // if (message == _messageentries[i].nmessage) return((*_messageentries[i].pfn)(hwnd, message, wparam, lparam)); } return(defwindowproc(hwnd, message, wparam, lparam)); } //---------------------------------------------------------------------- // OnCommand -- WM_COMMAND //---------------------------------------------------------------------- LONG OnCommand(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) int i; for(i=0; i < dim(_commandentries); i++) // if (LOWORD(wParam) == _commandentries[i].nmessage) return((*_commandentries[i].pfn)(hwnd, message, wparam, lparam)); } return(defwindowproc(hwnd, message, wparam, lparam)); } //---------------------------------------------------------------------- LONG OnCreate(HWND hwnd, UINT wmsg, UINT wparam, LONG lparam)... } 21
//---------------------------------------------------------------------- LONG OnAbout(HWND hwnd, UINT wmsg, UINT wparam, LONG lparam)... } //---------------------------------------------------------------------- WndProc OnCommand _messageentries[ ] _commandentries[ ] MFC Message Map MFC MFC Message Map Windows 1. modal 2. modeless modal Generic About 1. dialog template RC... 2. dialog procedure WM_INITDIALOG WM_COMMAND WM_COMMAND notification 22
Modal DialogBox EndDialog API 1-4 TRUE FALSE FALSE ( Dialog Templatet),in RC file. 1 AboutBox DIALOG DISCARDABLE 22, 17, 144, 75 STYLE DS_MODALFRAME WS_CAPTION WS_SYSMENU CAPTION "About Generic" BEGIN CTEXT "Windows 95", -1,0, 5,144,8 CTEXT "Generic Application",-1,0,14,144,8 CTEXT "Version 1.0", -1,0,34,144,8 DialogBox DEFPUSHBUTTON "OK", IDOK,53,59,32,14,WS_GROUP DialogBox(_hInst, END "AboutBox", // hwnd, // (DLGPROC)About // ); 2 4 LRESULT CALLBACK About(HWND hdlg, UINT message, WPARAM wparam, LPARAM lparam) UNREFERENCED_PARAMETER(lParam); //, switch (message) case WM_INITDIALOG: return (TRUE); // TRUE case WM_COMMAND: if (LOWORD(wParam) == IDOK 3 LOWORD(wParam) == IDCANCEL) EndDialog(hDlg, TRUE); return (TRUE); // TRUE } break; } return (FALSE); // FALSE } WM_COMMAND IDOK 23
.DEF Windows heap stack callback... NAME Generic DESCRIPTION 'Generic Sample' EXETYPE STUB CODE DATA HEAPSIZE 4096 WINDOWS STACKSIZE 10240 EXPORTS 'WINSTUB.EXE' PRELOAD DISCARDABLE PRELOAD MOVEABLE MULTIPLE MainWndProc @1 AboutBox @2 Visual C++.DEF STUB stub Windows DOS This Program Requires Microsoft Windows This Program Can Not Run in DOS mode Win16 stub Win32 Win32 Stub.RC RC ICON CURSOR BITMAP FONT DIALOG MENU ACCELERATOR STRING VERSIONINFO Visual C++ 4.0 TOOLBAR RC Generic ICON MENU DIALOG 24
Windows Windows Windows Windows 1-5 1-6 5 Message queue WM_CLOSE 2 8 WM_QUIT WM_DESTROY WinMain(hInst, hprev,...) MSG msg; RegisterClass(...); CreateWindow(...); ShowWindow(...); UpdateWindow(...); while(getmessage(&msg...)) TranslateMessage(...); DispatchMessage(...); } return msg.wparam; WndProc(hwnd, msg, wparam, lparam) switch (msg) case WM_CREATE:... case WM_COMMAND:... case WM_LBUTTONDOWN:... case WM_PAINT:... case WM_MOUSEMOVE:... case WM_DESTROY:... PostQuitMessage(0); 7 break; default: return DefWindowProc(...); } return(0); case } case WM_CLOSE: 6 WM_CLOSE: DestroyWindow(...); DestroyWindow(...); (in DefWindowProc) 3 WM_CREATE 1 USER Module 25
1. CreateWindow CreateWindow WM_CREATE... 2. GetMessage WM_QUIT GetMessage 0 while 3. DispatchMessage Windows USER 4. 2. 3. 5. Close WM_CLOSE DefWindowProc 6. DefWindowProc WM_CLOSE DestroyWindow DestroyWindow WM_DESTROY 7. WM_DESTROY PostQuitMessage 8. PostQuitMessage WM_QUIT GetMessage 2 1-6 1-5 WM_DESTROY ÓÃPostQuitMessage Close DefWindowProc DestroyWindow 26
OnIdle idle time timer WM_TIMER WM_MOUSEMOVE WM_MOUSEMOVE SDK WinMain while (TRUE) } if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) } else } if (msg.message == WM_QUIT) break; TranslateMessage(&msg); DispatchMessage(&msg); OnIdle(); PeekMessage GetMessage primary thread UI API GetMessage PeekMessage OnIdle HelloMFC MFC idle time p.403 27
Console Windows WinMain Dialog Box Message Box Windows API DialogBox MessageBox C/C++ main printf Where did the good times go Win32 Windows GUI Visual C++ "DOS-like" GUI Win32 API console console MFC GUI collection classes CArray CList CMap CFile CStdioFile BBS C/C++ Visual C++ Visual Visual C++ programming MFC programming C++ MFC programming Visual C++ C/C++ console C++ console console MFC console "DOS-like" console edit MFC CEditView console 28
Windows console console JBACKUP Win32 console Win32 API MFCCON MFC console MFC CStudioFile CString Console Console DOS DOS console Windows DOS Box Windows C++ IDE Console Windows Win32 main C runtime GUI Win32 API console console cin cout DOS DOS main C runtime Win32 API DOS Windows DOS Box Win95 WinNT 29
Console console Win32 API KERNEL32.DLL Windows processes threads -- GUI API DOS console printf cout scanf cin DOS MZ MZ Mark Zbikowski DOS Console Win32 PE Portable Executable Win32 Visual C++ DUMPBIN PE JBACKUP MFCCON H:\u004\prog\jbackup.01>dumpbin /summary jbackup.exe Microsoft (R) COFF Binary File Dumper Version 5.00.7022 Copyright (C) Microsoft Corp 1992-1997. All rights reserved. Dump of file jbackup.exe File Type: EXECUTABLE IMAGE Summary 5000.data 1000.idata 1000.rdata 5000.text DOS 30
C:\UTILITY>dumpbin /summary dsize.exe Microsoft (R) COFF Binary File Dumper Version 5.00.7022 Copyright (C) Microsoft Corp 1992-1997. All rights reserved. Dump of file dsize.exe DUMPBIN : warning LNK4094: "dsize.exe" is an MS-DOS executable; use EXEHDR to dump it Summary Console makefile console, 如 : /D_CONSOLE subsystem #0001 # filename : pedump.mak #0002 # make file for pedump.exe #0003 # usage : nmake pedump.msc (Visual C++ 5.0) #0004 #0005 all : pedump.exe #0006 #0007 pedump.exe: pedump.obj exedump.obj objdump.obj common.obj #0008 link /subsystem:console /incremental:yes \ #0009 /machine:i386 /out:pedump.exe \ #0010 pedump.obj common.obj exedump.obj objdump.obj \ #0011 kernel32.lib user32.lib #0012 #0013 pedump.obj : pedump.c #0014 cl /W3 /GX /Zi /YX /Od /DWIN32 /D_CONSOLE /FR /c pedump.c #0015 #0016 common.obj : common.c #0017 cl /W3 /GX /Zi /YX /Od /DWIN32 /D_CONSOLE /FR /c common.c #0018 #0019 exedump.obj : exedump.c #0020 cl /W3 /GX /Zi /YX /Od /DWIN32 /D_CONSOLE /FR /c exedump.c #0021 #0022 objdump.obj : objdump.c #0023 cl /W3 /GX /Zi /YX /Od /DWIN32 /D_CONSOLE /FR /c objdump.c cl jbackup.c <ENTER> jbackup.exe 31
Frame_ cl my.cpp mfc.cpp <ENTER> my.exe Generic.exe CL.EXE JBACKUP Win32 Console console 1. main 2. printf scanf cin cout 3. GUI Win32 API JBACKUP C:\SomeoneDir>JBACKUP SrcDir [DstDir] JBACKUP g: k: SrcDir DstDir DstDir DstDir k: -- MO -- k: SrcDir JBACKUP g: g: g:\u002\doc g:\u002\doc k:\u002\doc k:\u002\doc JBACK SrcDir DstDir SrcDir DstDir DstDir ScrDir DstDir 32
xcopy MO JBACKUP SrcDir recursive JBACKUP Win32 APIs GetCurrentDirectory FindFirstFile FindNextFile CompareFileTime CopyFile DeleteFile SrcDir DstDir JBACKUP SrcDir srcfiles[ ] SRCFILE typedef struct _SRCFILE WIN32_FIND_DATA fd; BOOL bisnew; } SRCFILE; SRCFILE srcfiles[filemax]; WIN32_FIND_DATA fd; // prepare srcfiles[]... bret = TRUE; isrcfiles = 0; hfile = FindFirstFile(SrcDir, &fd); while (hfile!= INVALID_HANDLE_VALUE && bret) if (fd.dwfileattributes == FILE_ATTRIBUTE_ARCHIVE) } srcfiles[isrcfiles].fd = fd; srcfiles[isrcfiles].bisnew = FALSE; isrcfiles++; 33
} bret = FindNextFile(hFile, &fd); DstDir destfiles[ ] DESTFILE typedef struct _DESTFILE WIN32_FIND_DATA fd; BOOL bmatch; } DESTFILE; DESTFILE destfiles[filemax]; WIN32_FIND_DATA fd; } bret = TRUE; idestfiles = 0; hfile = FindFirstFile(DstDir, &fd); while (hfile!= INVALID_HANDLE_VALUE && bret) if (fd.dwfileattributes == FILE_ATTRIBUTE_ARCHIVE) } destfiles[idestfiles].fd = fd; destfiles[idestfiles].bmatch = FALSE; idestfiles++; bret = FindNextFile(hFile, &fd); srcfiles[ ] destfiles[ ] scrfiles[ ] desfiles[ ] bisnew TRUE desfiles[ ] srcfiles[ ] bmatch FALSE srcfiles[ ] bisnew TRUE DstDir destfiles[ ] bmatch FALSE JBACKUP Jbackup.01 34
MFCCON MFC Console Win32 MFC console MFC 40 Win32 console MFC CStdioFile CString CObject CFile CString CStdioFile CMemFile CSocketFile COleStreamFile MFC CFile I/O CStdioFile CFile CStdioFile C runtime fopen stream Stream CString 100 Fabonacci sequence 1. 1 2. 35
#0001 // File : MFCCON.CPP #0002 // Author : J.J.Hou / Top Studio #0003 // Date : 1997.04.06 #0004 // Goal : Fibonacci sequencee, less than 100 #0005 // Build : cl /MT mfccon.cpp (/MT means Multithreading) #0006 #0007 #include <afx.h> #0008 #include <stdio.h> #0009 #0010 int main() #0011 #0012 int lo, hi; #0013 CString str; #0014 CStdioFile ffibo; #0015 #0016 ffibo.open("fibo.dat", CFile::modeWrite #0017 CFile::modeCreate CFile::typeText); #0018 #0019 str.format("%s\n", "Fibonacci sequencee, less than 100 :"); #0020 printf("%s", (LPCTSTR) str); #0021 ffibo.writestring(str); #0022 #0023 lo = hi = 1; #0024 #0025 str.format("%d\n", lo); #0026 printf("%s", (LPCTSTR) str); #0027 ffibo.writestring(str); #0028 #0029 while (hi < 100) #0030 #0031 str.format("%d\n", hi); #0032 printf("%s", (LPCTSTR) str); #0033 ffibo.writestring(str); #0034 hi = lo + hi; #0035 lo = hi - lo; #0036 } #0037 #0038 ffibo.close(); #0039 return 0; #0040 } 36
Fibonacci sequencee, less than 100 : 1 1 2 3 5 8 13 21 34 55 89 1. main MFC Console 2. AFX.H 3. GUI MFC CStdioFile CString 4. /MT C runtime MFC console C runtime /MT Microsoft (R) 32-Bit Incremental Linker Version 5.00.7022 Copyright (C) Microsoft Corp 1992-1997. All rights reserved. /out:mfccon.exe mfccon.obj nafxcw.lib(thrdcore.obj) : error LNK2001: unresolved external symbol endthreadex nafxcw.lib(thrdcore.obj) : error LNK2001: unresolved external symbol beginthreadex mfccon.exe : fatal error LNK1120: 2 unresolved externals beginthreadex endthreadex MFC MFCCON mfccon.01 37
C Runtime C runtime 1970s PC C runtime multithreaded synchronous mechanism critical section mutex semaphore event runtime -- Visual C++ C runtime errno Visual C++ C runtime Single-Threaded static libc.lib 898,826 Multithreaded static libcmt.lib 951,142 Multithreaded DLL msvcrt.lib 5,510,000 Debug Single-Threaded static libcd.lib 2,374,542 Debug Multithreaded static libcmtd.lib 2,949,190 Debug Multithreaded DLL msvcrtd.lib 803,418 Visual C++ C runtime /ML Single-Threaded static /MT Multithreaded static /MD Multithreaded DLL dynamic import library /MLd Debug Single-Threaded static /MTd Debug Multithreaded static /MDd Debug Multithreaded DLL dynamic import library 38
Process and Thread OS/2 Windows NT Windows 95 PC process CPU kernel object GDI GDI Pen Brush GDI? GDI usage count event mutex semaphore file file-mapping process thread CreateEvent CreateMutex CreateSemaphore CreateFile CreateFileMapping CreateProcess CreateThread file-mapping memory mapping file process thread 39
API handle 1 CloseHandle process process process shell Win95 Windows 3.x App.exe shell CreateProcess 1. shell CreateProcess App.exe 2. 1 3. 4GB 4. App.exe DLLs PE.idata section 5. primary thread CPU 6. C runtime Startup code 7. Startup code App WinMain 8. App 9. App WinMain WinMain 10. Startup code 11. ExitProcess 40
Windows shell shell CreateProcess CreateProcess API CreateProcess( ); LPCSTR lpapplicationname, LPSTR lpcommandline, LPSECURITY_ATTRIBUTES lpprocessattributes, LPSECURITY_ATTRIBUTES lpthreadattributes, BOOL binherithandles, DWORD dwcreationflags, LPVOID lpenvironment, LPCSTR lpcurrentdirectory, LPSTARTUPINFO lpstartupinfo, LPPROCESS_INFORMATION lpprocessinformation lpapplicationname lpcommandline command line lpapplicationname.exe lpapplicationname NULL lpcommandline token ".EXE" Windows 1. 2. 3. Windows 4. Windows System 41
5. path CreateProcess("E:\\CWIN95\\NOTEPAD.EXE", "README.TXT",...); E:\CWIN95\NOTEPAD.EXE "README.TXT" CreateProcess(NULL, "NOTEPAD README.TXT",...); NOTEPAD.EXE "README.TXT" CreateProcess TRUE FALSE dwcreationflags CREATE_SUSPENDED lpenvironment NULL lpcurrentdirectory NULL lpstartupinfo STARTUPINFO API PROCESS_INFORMATION 42
typedef struct _PROCESS_INFORMATION HANDLE hprocess; HANDLE hthread; DWORD dwprocessid; DWORD dwthreadid; } PROCESS_INFORMATION; handle handles VOID ExitProcess(UINT fuexitcode); BOOL TerminateProcess(HANDLE hprocess, UINT fuexitcode); handle TerminateProcess DLLs TerminateProcess CloseHandle PROCESS_INFORMATION ProcInfo; BOOL fsuccess; fsuccess = CreateProcess(...,&ProcInfo); if (fsuccess) CloseHandle(ProcInfo.hThread); CloseHandle(ProcInfo.hProcess); } 43
Windows CreateThread 1. handle CreateThread 2. 1 3. context 4. 5. context SS IP CPU context switch context CreateThread CreateThread(LPSECURITY_ATTRIBUTES lpthreadattributes, DWORD dwstacksize, LPTHREAD_START_ROUTINE lpstartaddress, LPVOID lpparameter, DWORD dwcreationflags, LPDWORD lpthreadid ); API Windows 95 0 CREATE_SUSPENDED ResumeThread DWORD ID 44
VOID ReadTime(VOID); HANDLE hthread; DWORD ThreadID; hthread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ReadTime, NULL, 0, &ThreadID);... //-------------------------------------------------------------------- // thread // GetSystemTime, // hwnddlg 的 IDE_TIMER _h //-------------------------------------------------------------------- VOID ReadTime(VOID) char str[50]; SYSTEMTIME st; } while(1) GetSystemTime(&st); sprintf(str,"%u:%u:%u", st.whour, st.wminute, st.wsecond); SetDlgItemText (_hwnddlg, IDE_TIMER, str); Sleep (1000); // } CreateThread Win32 ExitThread TerminateThread TerminateThread API 45
_beginthreadex CreateThread Windows Win32 API C runtime C runtime C runtime CreateThread _beginthreadex ANSI C runtime _beginthreadex CreateThread Win32 _beginthreadex Windows windows.h CloseHandle CloseHandle Win32 API windows.h Windows _beginthreadex CreateThread unsigned long _beginthreadex( void *security, unsigned stack_size, unsigned ( stdcall *start_address)(void *), void *arglist, unsigned initflag, unsigned* thrdaddr ); _beginthreadex unsigned long Win32 HANDLE CreateThread _beginthreadex errno doserrno #0001 #include <windows.h> #0002 #include <process.h> 46
#0003 unsigned stdcall myfunc(void* p); #0004 #0005 void main() #0006 #0007 unsigned long thd; #0008 unsigned tid; #0009 #0010 thd = _beginthreadex(null, #0011 0, #0012 myfunc, #0013 0, #0014 0, #0015 &tid ); #0016 if (thd!= NULL) #0017 #0018 CloseHandle(thd); #0019 } #0020 } #0021 #0022 unsigned stdcall myfunc(void* p) #0023 #0024 // do your job... #0025 } Win32 API ExitThread C runtime _endthreadex _beginthreadex ID _beginthreadex _endthreadex Jim Beveridge & Robert Wiener Addison Wesley Multithreading Applications in Win32 Win32 / / 47
Priority CPU 0 31 Priority Class 1-7 CreateProcess dwcreationflags NORMAL_PRIORITY_CLASS -- IDLE_PRIORITY_CLASS idle IDLE_PRIORITY_CLASS 4 normal NORMAL_PRIORITY_CLASS 9( 前 景 ) 或 7( 背 景 ) high HIGH_PRIORITY_CLASS 13 realtime REALTIME_PRIORITY_CLASS 24 "idle" CPU "normal" "normal" 9 7 "high" Ctrl+Esc task manager "realtime" 48
Ctrl+Alt+Del "realtime" IDLE_ NORMAL_ HIGH_ REALTIME_ SetThreadPriority SetThreadPriority SetThreadPriority THREAD_PRIORITY_LOWEST -2 THREAD_PRIORITY_BELOW_NORMAL -1 THREAD_PRIORITY_NORMAL THREAD_PRIORITY_ABOVE_NORMAL +1 THREAD_PRIORITY_HIGHEST +2 SetThreadPriority : : THREAD_PRIORITY_IDLE 1 16 THREAD_PRIORITY_TIME_CRITICAL 15 31 1-8 49
idle lowest below normal normal above normal highest time critical idle 1 2 3 4 5 6 15 normal ( ) 1 5 6 7 8 9 15 normal ( ) 1 7 8 9 10 11 15 high 1 11 12 13 14 15 15 realtime 16 22 23 24 25 26 31 1-8 Win32 MltiThrd MltiThrd.01-2 -1 0 +1 +2 HANDLE _hthread[5]; // global variable... LONG APIENTRY MainWndProc (HWND hwnd, UINT message, UINT wparam, LONG lparam) DWORD ThreadID[5]; static DWORD ThreadArg[5] = HIGHEST_THREAD, // 0x00 ABOVE_AVE_THREAD, // 0x3F NORMAL_THREAD, // 0x7F BELOW_AVE_THREAD, // 0xBF LOWEST_THREAD // 0xFF }; //... for(i=0; i<5; i++) // threads _hthread[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc, &ThreadArg[i], CREATE_SUSPENDED, &ThreadID[i]); // 設 定 thread priorities SetThreadPriority(_hThread[0], THREAD_PRIORITY_HIGHEST); SetThreadPriority(_hThread[1], THREAD_PRIORITY_ABOVE_NORMAL); 50
} SetThreadPriority(_hThread[2], THREAD_PRIORITY_NORMAL); SetThreadPriority(_hThread[3], THREAD_PRIORITY_BELOW_NORMAL); SetThreadPriority(_hThread[4], THREAD_PRIORITY_LOWEST);... Resume Threads ThreadProc Rectangle Sleep(10) CPU 30000 CPU CPU 30000 UINT _udelaytype=nodelay; // global variable... VOID ThreadProc(DWORD *ThreadArg) RECT rect; HDC hdc; HANDLE hbrush, holdbrush; DWORD dwthreadhits = 0; int ithreadno, i;... do dwthreadhits++; // // Rectangle(hDC, *(ThreadArg), rect.bottom-(dwthreadhits/10), *(ThreadArg)+0x40, rect.bottom); } // if (_udelaytype == SLEEPDELAY) Sleep(10); else if (_udelaytype == FORLOOPDELAY) for (i=0; i<30000; i++); else // _udelaytype == NODELAY) } } while (dwthreadhits < 1000); // 1000 次... 51
1-9 "for loop delay" "sleep delay" Resume Thread for loop delay 1-9a 0 1 2... sleep delay 1-9b 14 1-9a MltiThrd.exe for loop delay 1-9b MltiThrd.exe s leep delay 1-9a 1 2~4 CPU 14 52
1-10 Process Viewer Visual C++ 5.0 Mltithrd.exe MLTITHRD.EXE 10 53
54
C++ Object Oriented Programming Object Oriented Programming Language C++ C C C++ JAVA Small Talk C++ C++ Basic Assembly C++ MFC C++ 55
C++ MFC Programming C++ OO application framework DOS Windows - encapsulation object class property Java field method member variable data member function member variable member function CSquare color display color display CSquare square; // square square.color = RED; // RED square.display(); // C++ CSquare class CSquare // C private: public: }; int m_color; // m_ void display()... } void setcolor(int color) m_color = color; } 56
C++ private public protected private public m_color private setcolor private encapsulation (Inheritance) C struct function pointer C++ base class derived class Shape Shape Ellipse Ellipse Triangle Triangle Rectangle Rectangle Circle Circle Square Square IsKindOf Circle Ellipse Ellipse Shape Square Rectangle Rectangle Shape 57
#0001 class CShape // #0002 #0003 private: #0004 int m_color; #0005 #0006 public: #0007 void setcolor(int color) m_color = color; } #0008 }; #0009 #0010 class CRect : public CShape // #0011 // #0012 public: #0013 void display()... } #0014 }; #0015 #0016 class CEllipse : public CShape // #0017 // m_color setcolor() #0018 public: #0019 void display()... } #0020 }; #0021 #0022 class CTriangle : public CShape // #0023 // m_color setcolor() #0024 public: #0025 void display()... } #0026 }; #0027 #0028 class CSquare : public CRect // #0029 #0030 public: #0031 void display()... } #0032 }; #0033 #0034 class CCircle : public CEllipse // #0035 #0036 public: #0037 void display()... } #0038 }; CSquare square; CRect rect1, rect2; CCircle circle; square.setcolor(1); // square.m_color = 1; 58
square.display(); // CSquare::display rect1.setcolor(2); // rect1.m_color = 2 rect1.display(); // CRect::display rect2.setcolor(3); // rect2.m_color = 3 rect2.display(); // CRect::display circle.setcolor(4); // circle.m_color = 4 circle.display(); // CCircle::display 1. CShape CShape m_color setcolor implicit 2. rect1 rect2 m_color setcolor CRect::setcolor CShape::setcolor rect1 m_color rect2 m_color this CRect::setcolor(int color, CRect* this) this->m_color = color; } this this rect1.setcolor rect2.setcolor CRect::setcolor this rect1.setcolor rect2.setcolor CRect::setcolor CShape::setcolor rect1.m_color rect2.m_color this 59
3. display CShape display 4. display for while CShape shapes[5];... // 5 shapes for (int i=0; i<5; i++) shapes[i].display; } 5. Shape C++ CShape shape; // shape.setcolor(); //?! display C++ 60
this rect1 rect2 m_color rect1.setcolor rect2.setcolor CRect::setcolor CRect::setcolor m_color this rect1.setcolor(2); // rect1 CRect rect2.setcolor(3); // rect2 CRect CRect::setcolor(2, (CRect*)&rect1); CRect::setcolor(3, (CRect*)&rect2); CRect setcolor CShape CShape::setcolor(2, (CRect*)&rect1); CShape::setcolor(3, (CRect*)&rect2); this class CShape... public: }; void setcolor(int color) m_color = color; } class CShape... public: }; void setcolor(int color, (CShape*)this) this->m_color = color; } 61
(Polymorphism CShape shapes[5];... // 5 shapes for (int i=0; i<5; i++) } shapes[i].display; application framework framework display display CShape* pshape; pshape->display(); while loop Ellipse Square Triangle Rect Circle Square Circle Circle C++ virtual function +?! 62
Visual C++ Introdoction to C++ CEmployee CEmployee CManager CManager CWage CWage CSales CSales Visual C++ Class Info : #0001 #include <string.h> #0002 #0003 //--------------------------------------------------------------- #0004 class CEmployee // #0005 #0006 private: #0007 char m_name[30]; #0008 #0009 public: #0010 CEmployee(); #0011 CEmployee(const char* nm) strcpy(m_name, nm); } #0012 }; 63
64 #0057 // #0013 //--------------------------------------------------------------- #0014 class CWage : public CEmployee // #0015 #0016 private : #0017 float m_wage; #0018 float m_hours; #0019 #0020 public : #0021 CWage(const char* nm) : CEmployee(nm) m_wage = 250.0; m_hours = 40.0; } #0022 void setwage(float wg) m_wage = wg; } #0023 void sethours(float hrs) m_hours = hrs; } #0024 float computepay(); #0025 }; #0026 //--------------------------------------------------------------- #0027 class CSales : public CWage // #0028 #0029 private : #0030 float m_comm; #0031 float m_sale; #0032 #0033 public : #0034 CSales(const char* nm) : CWage(nm) m_comm = m_sale = 0.0; } #0035 void setcommission(float comm) m_comm = comm; } #0036 void setsales(float sale) m_sale = sale; } #0037 float computepay(); #0038 }; #0039 //--------------------------------------------------------------- #0040 class CManager : public CEmployee // #0041 #0042 private : #0043 float m_salary; #0044 public : #0045 CManager(const char* nm) : CEmployee(nm) m_salary = 15000.0; } #0046 void setsalary(float salary) m_salary = salary; } #0047 float computepay(); #0048 }; #0049 //--------------------------------------------------------------- #0050 void main() #0051 #0052 CManager amanager(" "); #0053 CSales asales(" "); #0054 CWage awager(" "); #0055 } #0056 //---------------------------------------------------------------
CWage CEmployee CSales CWage CSales // private data of CEmployee char m_name[30]; // private data of CWage float m_wage; float m_hours; // private data of CSales float m_comm; float m_sale; void setwage(float wg); void sethours(float hrs); void setcommission(float comm); void setsale(float sales); void computepay(); Visual C++ main 65
float CManager::computePay() } computepay return m_salary; // float CWage::computePay() } return (m_wage * m_hours); // * float CSales::computePay() // * * } return (m_wage * m_hours + m_comm * m_sale); // CSales CWage m_wage m_hours private float CSales::computePay() } return computepay() + m_comm * m_sale; computepay -- float CSales::computePay() } return CWage::computePay() + m_comm * m_sale; CSales asales(" "); 66
: asales.cwage::computepay(); // : asales.computepay(); // scope resolution operator :: application framework MFC CWage awager; CSales asales(" "); awager = asales; // asales = awager; // cast : CWage* pwager; CSales* psales; CSales asales(" "); pwager = &asales; // psales = (CSales *)pwager; // 67
CEmployee* pemployee; CWage awager(" "); CSales asales(" "); CManager amanager(" "); pempolyee = &awager; // pempolyee = &asales; // pempolyee = &amanager; // linked list add add(cemployee* pemp); // pemp C++ CSales asales(" ") CSales* psales; CWage* pwager; psales = &asales; pwager = &asales; // pwager->setsales(800.0); // ) // CWage setsales psales->setsales(800.0); // CSales::setSales psales pwager pwager->computepay(); // CWage::computePay() psales->computepay(); // CSales::computePay() psales pwager CSales computepay 68
1. class CBase BaseFunc() class CDerived DeriFunc() CBase* pbase; 2. explicit cast class CBase BaseFunc() class CDerived CDerived *pderi; CBase abase("jason"); pderi = &abase; // // CDerived* pderi; DeriFunc() 3. 1 69
class CBase BaseFunc() CommFunc() CBase* pbase; CDerived* pderi; class CDerived DeriFunc() CommFunc() pbase->commfunc() CBase::CommFunc pderi->commfunc() CDerived::CommFunc printnames CEmployee getname while int count = 0; CEmployee* pemp;... while (pemp = aniter.getnext()) count++; cout << count << ' ' << pemp->getname() << endl; } aniter.getnext CEmPloyee* CEmployee getname CEmployee* pemp; pemp->getname(); pemp->computepay(); while loop 經 理 時 薪 職 員 銷 售 員 時 薪 職 員 時 薪 職 員 銷 售 員 時 薪 職 員 銷 售 員 70
while pemp->computepay while CEmployee::computePay CEmployee::computePay CWage CManager CSales while computepay CEmpolyee computepay polymorphism pemp pemp->computepay CManager::computePay pemp pemp->computepay CSales::computePay pemp pemp->computepay CWage::computePay 71
add getnext computepay virtual CEmployee* pemp; CWage awager(" 曾 銘 源 "); CSales asales(" 侯 俊 傑 "); CManager amanager(" 陳 美 靜 "); pemp = &awager; cout << pemp->computepay(); // pemp = &asales; cout << pemp->computepay(); // pemp = &amanager; cout << pemp->computepay(); // CWage::computePay CSales::computePay CManager::computePay Shape display #0001 #include <iostream.h> #0002 class CShape #0003 #0004 public: #0005 virtual void display() cout << "Shape \n"; } #0006 }; #0007 //------------------------------------------------ #0008 class CEllipse : public CShape #0009 #0010 public: #0011 virtual void display() cout << "Ellipse \n"; } #0012 }; #0013 //------------------------------------------------ #0014 class CCircle : public CEllipse #0015 #0016 public: #0017 virtual void display() cout << "Circle \n"; } #0018 }; #0019 //------------------------------------------------ #0020 class CTriangle : public CShape #0021 #0022 public: #0023 virtual void display() cout << "Triangle \n"; } #0024 }; 72
#0025 //------------------------------------------------ #0026 class CRect : public CShape #0027 #0028 public: #0029 virtual void display() cout << "Rectangle \n"; } #0030 }; #0031 //------------------------------------------------ #0032 class CSquare : public CRect #0033 #0034 public: #0035 virtual void display() cout << "Square \n"; } #0036 }; #0037 //------------------------------------------------ #0038 void main() #0039 #0040 CShape ashape; #0041 CEllipse aellipse; #0042 CCircle acircle; #0043 CTriangle atriangle; #0044 CRect arect; #0045 CSquare asquare; #0046 CShape* pshape[6] = &ashape, #0047 &aellipse, #0048 âle, #0049 &atriangle, #0050 &arect, #0051 &asquare }; #0052 #0053 for (int i=0; i< 6; i++) #0054 pshape[i]->display(); #0055 } #0056 //------------------------------------------------ 得 到 的 結 果 是 : Shape Ellipse Circle Triangle Rectangle Square 73
virtual Shape Shape Shape Shape Shape Shape Employee Shape pemp = &awager; cout << pemp->computepay(); pemp = &asales; cout << pemp->computepay(); pemp = &aboss; cout << pemp->computepay(); CShape* pshape[6]; for (int i=0; i< 6; i++) pshape[i]->display(); // 6 scope resolution operator :: virtual MFC document Serialize view OnDraw CMyDoc CMyView 74
Polymorphism Polymorphism "the ability to assume many forms" pemp->computepay late binding dynamic binding C C++ non-virtual early binding static binding Polymorphism Polymorphism MFC CAnimal CYahoo roar roar Shape CShape display CShape display class CShape public: virtual void display() } }; 75
class CShape public: virtual void display() cout << "Shape \n"; } }; CShape spaceholder C++ class CShape public: }; virtual void display() = 0; // "= 0" instantiate 'Shape' error : illegal attempt to instantiate abstract class. CCircle CShape CShape CCircle virtual Polymorphism "the ability to assume many forms" C++ Polymorphism 76
"=0" abstract Class concrete class) virtual C++ C++ vtable vptr class Class1 }; public : data1; data2; memfunc(); virtual vfunc1(); virtual vfunc2(); virtual vfunc3(); Class1 77
class Class1 public : m_data1; m_data2; memfunc(); virtual vfunc1(); virtual vfunc2(); virtual vfunc3(); } Class1 vptr m_data1 m_data2 vtable (*vfunc1)() (*vfunc2)() (*vfunc3)() Class1::vfunc1() Class1::vfunc2() Class1::vfunc3() Class1::memfunc() C++ C this C++ Class1 vptr vptr class Class2 : public Class1 public : data3; memfunc(); virtual vfunc2(); }; 78
class Class2 : public Class1 public : m_data3; memfunc(); virtual vfunc2(); } vptr m_data1 m_data2 m_data3 Class2 vtable (*vfunc1)() (*vfunc2)() (*vfunc3)() Class1::vfunc1() Class2::vfunc2() Class1::vfunc3() Class2::memfunc() Class1 vfunc2 Class1::vfunc2 Class2 vfunc2 Class2::vfunc2 #0001 #include <iostream.h> #0002 #include <stdio.h> #0003 #0004 class ClassA #0005 #0006 public: #0007 int m_data1; #0008 int m_data2; #0009 void func1() } #0010 void func2() } #0011 virtual void vfunc1() } #0012 virtual void vfunc2() } #0013 }; #0014 #0015 class ClassB : public ClassA #0016 #0017 public: #0018 int m_data3; #0019 void func2() } #0020 virtual void vfunc1() } #0021 }; #0022 #0023 class ClassC : public ClassB #0024 79
80 #0025 public: #0026 int m_data1; #0027 int m_data4; #0028 void func2() } #0029 virtual void vfunc1() } #0030 }; #0031 #0032 void main() #0033 #0034 cout << sizeof(classa) << endl; #0035 cout << sizeof(classb) << endl; #0036 cout << sizeof(classc) << endl; #0037 #0038 ClassA a; #0039 ClassB b; #0040 ClassC c; #0041 #0042 b.m_data1 = 1; #0043 b.m_data2 = 2; #0044 b.m_data3 = 3; #0045 c.m_data1 = 11; #0046 c.m_data2 = 22; #0047 c.m_data3 = 33; #0048 c.m_data4 = 44; #0049 c.classa::m_data1 = 111; #0050 #0051 cout << b.m_data1 << endl; #0052 cout << b.m_data2 << endl; #0053 cout << b.m_data3 << endl; #0054 cout << c.m_data1 << endl; #0055 cout << c.m_data2 << endl; #0056 cout << c.m_data3 << endl; #0057 cout << c.m_data4 << endl; #0058 cout << c.classa::m_data1 << endl; #0059 #0060 cout << &b << endl; #0061 cout << &(b.m_data1) << endl; #0062 cout << &(b.m_data2) << endl; #0063 cout << &(b.m_data3) << endl; #0064 cout << &c << endl; #0065 cout << &(c.m_data1) << endl; #0066 cout << &(c.m_data2) << endl; #0067 cout << &(c.m_data3) << endl; #0068 cout << &(c.m_data4) << endl; #0069 cout << &(c.classa::m_data1) << endl; #0070 }
: 12 Sizeof (ClassA) 2 個 int 加 ㆒ 個 vptr 16 Sizeof (ClassB) ClassA, 1 int 24 Sizeof (ClassC) ClassB, 再 加 2 int 1 b.m_data1 的 內 容 2 b.m_data2 的 內 容 3 b.m_data3 的 內 容 11 c.m_data1 的 內 容 22 c.m_data2 的 內 容 33 c.m_data3 的 內 容 44 c.m_data4 的 內 容 111 c.classa::m_data1 的 內 容 0x0064FDCC 0x0064FDD0 0x0064FDD4 0x0064FDD8 0x0064FDB0 0x0064FDC0 0x0064FDB8 0x0064FDBC 0x0064FDC4 0x0064FDB4 b vptr b.m_data1 b.m_data2 b.m_data3 c vptr c.m_data1 c.m_data2 c.m_data3 c.m_data4 c.classa::m_data1 81
a b c : a (ClassA ) vptr m_data1 m_data2 vtable (*vfunc1)() (*vfunc2)() ClassA::vfunc1() ClassA::vfunc2() ClassA::func1() ClassA::func2() 0x0064FDCC 0x0064FDD0 0x0064FDD4 0x0064FDD8 b (ClassB ) vptr m_data1 m_data2 m_data3 vtable (*vfunc1)() (*vfunc2)() ClassB::vfunc1() ClassA::vfunc2() ClassB::func2() 0x0064FDB0 0x0064FDB4 0x0064FDB8 0x0064FDBC c (ClassC ) vptr ClassA::m_data1 m_data2 m_data3 vtable (*vfunc1)() (*vfunc2)() ClassC::vfunc1() ClassA::vfunc2() ClassC::func2() 0x0064FDC0 m_data1 0x0064FDC4 m_data4 Object slicing CObject CObject virtual void Serialize(); CDocument CDocument void func(); virtual void Serialize(); CMyDoc CMyDoc virtual void Serialize(); 82
第 2 章 C++ 的 重 要 性 質 : #0001 #include <iostream.h> #0002 #0003 class CObject #0004 #0005 public: #0006 virtual void Serialize() cout << "CObject::Serialize() \n\n"; } #0007 }; #0008 #0009 class CDocument : public CObject #0010 #0011 public: #0012 int m_data1; #0013 void func() cout << "CDocument::func()" << endl; #0014 Serialize(); #0015 } #0016 #0017 virtual void Serialize() cout << "CDocument::Serialize() \n\n"; } #0018 }; #0019 #0020 class CMyDoc : public CDocument #0021 #0022 public: #0023 int m_data2; #0024 virtual void Serialize() cout << "CMyDoc::Serialize() \n\n"; } #0025 }; #0026 //--------------------------------------------------------------- #0027 void main() #0028 #0029 CMyDoc mydoc; #0030 CMyDoc* pmydoc = new CMyDoc; #0031 #0032 cout << "#1 testing" << endl; #0033 mydoc.func(); #0034 #0035 cout << "#2 testing" << endl; #0036 ((CDocument*)(&mydoc))->func(); #0037 #0038 cout << "#3 testing" << endl; #0039 pmydoc->func(); #0040 #0041 cout << "#4 testing" << endl; #0042 ((CDocument)mydoc).func(); #0043 } 83
第 ㆒ 篇 勿 在 浮 砂 築 高 台 CMyDoc func CDocument CDocument::func CDocument::func Serialize non-virtual CDocument::Serialize #1 testing CDocument::func() CMyDoc::Serialize() #2 testing CDocument::func() CMyDoc::Serialize() #3 testing CDocument::func() CMyDoc::Serialize() #4 testing CDocument::func() CDocument::Serialize() <-- 注 意 Serialize Serialize framework MFC upcasting (CDocument)mydoc slicing mydoc vptr vptr m_data1 m_data2 object slicing (CDocument)mydoc; CDocument vptr vptr m_data1 mydoc vptr vptr m_data1 84
第 2 章 C++ 的 重 要 性 質 ((CDocument)mydoc).func(); mydoc func mydoc ((CDocument)mydoc).func() copy constructor CDocument vtable CDocument vtable data g mydoc slicin class SavingAccount private: char m_name[40]; // 存 戶 姓 名 char m_addr[60]; // 存 戶 址 double m_total; // 存 款 額 double m_rate; // 利 率... }; m_rate 85
m_rate m_rate m_rate static class SavingAccount private: char m_name[40]; // char m_addr[60]; // double m_total; // static double m_rate; //... }; static static main double SavingAccount::m_rate = 0.0075; // static void main()... } m_rate private static static assignment static error LNK2001: unresolved external symbol "private: static double SavingAccount::m_rate"(?m_rate@SavingAccount@@2HA) static HelloMFC DBWIN MFC RTTI MFC CRuntimeClass static 86
第 2 章 C++ 的 重 要 性 質 static // void main() SavingAccount::m_rate = 0.0075; // } static // void main() SavingAccount myaccount; myaccount.m_rate = 0.0075; // } static access level s non-static static object class private static static setrate class SavingAccount private: char m_name[40]; // char m_addr[60]; // double m_total; // static double m_rate; // 利 率... public: static void setrate(double newrate) m_rate = newrate; }... }; double SavingAccount::m_rate = 0.0075; // void main() 87
第 ㆒ 篇 勿 在 浮 砂 築 高 台 SavingAccount::setRate(0.0074); // } SavingAccount myaccount; myaccount.setrate(0.0074); // static this static non-static this static this MFC callback Hello World C++ C++ new C malloc new constructor destructor ~ most based most derived frame1 88
第 2 章 C++ 的 重 要 性 質 #0001 #include <iostream.h> #0002 #include <string.h> #0003 #0004 class CDemo #0005 #0006 public: #0007 CDemo(const char* str); #0008 ~CDemo(); #0009 private: #0010 char name[20]; #0011 }; #0012 #0013 CDemo::CDemo(const char* str) // #0014 #0015 strncpy(name, str, 20); #0016 cout << "Constructor called for " << name << '\n'; #0017 } #0018 #0019 CDemo::~CDemo() // #0020 #0021 cout << "Destructor called for " << name << '\n'; #0022 } #0023 #0024 void func() #0025 #0026 CDemo LocalObjectInFunc("LocalObjectInFunc"); // in stack ➎ #0027 static CDemo StaticObject("StaticObject"); // local static ➏ #0028 CDemo* pheapobjectinfunc = new CDemo("HeapObjectInFunc"); // in heap ➐ #0029 #0030 cout << "Inside func" << endl; ➑ #0031 #0032 } ➒ #0033 #0034 CDemo GlobalObject("GlobalObject"); // global static ➊ #0035 #0036 void main() #0037 #0038 CDemo LocalObjectInMain("LocalObjectInMain"); // in stack ➋ #0039 CDemo* pheapobjectinmain = new CDemo("HeapObjectInMain"); // in heap ➌ #0040 #0041 cout << "In main, before calling func\n"; ➍ #0042 func(); #0043 cout << "In main, after calling func\n"; ➓ #0044 #0045 } ➀ 89
第 ㆒ 篇 勿 在 浮 砂 築 高 台 : ➊ Constructor called for GlobalObject ➋ Constructor called for LocalObjectInMain ➌ Constructor called for HeapObjectInMain ➍ In main, before calling func ➎ Constructor called for LocalObjectInFunc ➏ Constructor called for StaticObject ➐ Constructor called for HeapObjectInFunc ➑ Inside func ➒ Destructor called for LocalObjectInFunc ➓ In main, after calling func ➀ Destructor called for LocalObjectInMain Destructor called for StaticObject Destructor called for GlobalObject GlobalObject application object static new delete in stack in heap global local static static C++ 90
第 2 章 C++ 的 重 要 性 質 void MyFunc() CFoo foo; // stack foo }... heap void MyFunc() }... CFoo* pfoo = new CFoo(); // heap CFoo foo; // void MyFunc()... } static CFoo foo; // scope C++ CFoo C++ -- stack heap -- function scope startup startup main WinMain C++ startup I/O stream static 91
第 ㆒ 篇 勿 在 浮 砂 築 高 台 main WinMain startup C instance stack heap MyFunc Unwinding C++ destructed exception exception han exception exception handling RTTI Runtime RTTI Type Information Visual C++ 4.0 Borland C++ 5.0 #0001 // RTTI.CPP - built by C:\> cl.exe -GR rtti.cpp <ENTER> #0002 #include <typeinfo.h> #0003 #include <iostream.h> #0004 #include <string.h> #0005 #0006 class graphicimage 92
第 2 章 C++ 的 重 要 性 質 #0007 #0008 protected: #0009 char name[80]; #0010 #0011 public: #0012 graphicimage() #0013 #0014 strcpy(name,"graphicimage"); #0015 } #0016 #0017 virtual void display() #0018 #0019 cout << "Display a generic image." << endl; #0020 } #0021 #0022 char* getname() #0023 #0024 return name; #0025 } #0026 }; #0027 //--------------------------------------------------------------- #0028 class GIFimage : public graphicimage #0029 #0030 public: #0031 GIFimage() #0032 #0033 strcpy(name,"gifimage"); #0034 } #0035 #0036 void display() #0037 #0038 cout << "Display a GIF file." << endl; #0039 } #0040 }; #0041 #0042 class PICTimage : public graphicimage #0043 #0044 public: #0045 PICTimage() #0046 #0047 strcpy(name,"pictimage"); #0048 } #0049 #0050 void display() #0051 #0052 cout << "Display a PICT file." << endl; 93
第 ㆒ 篇 勿 在 浮 砂 築 高 台 #0053 } #0054 }; #0055 //--------------------------------------------------------------- #0056 void processfile(graphicimage *type) #0057 #0058 if (typeid(gifimage) == typeid(*type)) #0059 #0060 ((GIFimage *)type)->display(); #0061 } #0062 else if (typeid(pictimage) == typeid(*type)) #0063 #0064 ((PICTimage *)type)->display(); #0065 } #0066 else #0067 cout << "Unknown type! " << (typeid(*type)).name() << endl; #0068 } #0069 #0070 void main() #0071 #0072 graphicimage *gimage = new GIFimage(); #0073 graphicimage *pimage = new PICTimage(); #0074 #0075 processfile(gimage); #0076 processfile(pimage); #0077 } Display a GIF file. Display a PICT file. RTTI 1. /GR /GR enable C++ RTTI 2. typeinfo.h 3. typeid overloading Polymo typeid #58 type _info& type _info typeinfo.h class type_info 94
public: virtual ~type_info(); int operator==(const type_info& rhs) const; int operator!=(const type_info& rhs) const; int before(const type_info& rhs) const; const char* name() const; const char* raw_name() const; private:... }; Visual C++ 4.0 RTTI MFC 4.x RTTI MFC 1.0 MFC MFC RTTI DECLARE_DYNAMIC IMPLEMENT_DYNAMIC CRuntimeClass MFC RTTI DOS Dynamic Creation) persistence RAM MFC Serialize Serialize new char classname[30] = getclassname(); // CObject* obj = new classname; // 95
new classname new MFC CObject Serialize Serialize -- MFC DECLARE_DYNCREATE IMPLEMENT_DYNCREATE CRuntimeClass DOS Exception Handling) Exception C++ nested Watcom C++ ANSI C+ + Borland C++ 4.0 Microsoft Visual C++ Symantec C++ C++ exception C setjmp longjmp C++ exception handler exception handling MFC OWL application frameworks C++ exception 1. try } exception 2. catch } exception catch try 3. throw exception 96
第 2 章 C++ 的 重 要 性 質 try // try block. } catch (char *p) printf("caught a char* exception, value %s\n",p); } catch (double d) printf("caught a numeric exception, value %g\n",d); } catch (...) // catch anything printf("caught an unknown exception\n"); } MFC exception Visual C++ 4.0 C++ exceptions MFC exception MFC ANSI MFC exceptions exception C++ types exception MFC C++ exception handling TRY CATCH(type,object) AND_CATCH(type,object) END_CATCH CATCH_ALL(object) AND_CATCH_ALL(object) END_CATCH_ALL END_TRY THROW() THROW_LAST() MFC exceptions TRY CATCH TRY // try block. } CATCH (CMemoryException, e) 97
第 ㆒ 篇 勿 在 浮 砂 築 高 台 printf("caught a memory exception.\n"); } AND_CATCH_ALL (e) printf("caught an exception.\n"); } END_CATCH_ALL THROW C++ throw THROW AfxThrow _ MFC Exception Type MFC Throw Function DOS support Windows support CException v v CMemoryException AfxThrowMemoryException v v CFileException AfxThrowFileException v v CArchiveException AfxThrowArchiveException v v CNotSupportedException AfxThrowNotSupportedException v v CResourceException AfxThrowResourceException v COleException AfxThrowOleException v COleDispatchException AfxThrowOleDispatchException v CDBException AfxThrowDBException v CDaoException AfxThrowDaoException v CUserException AfxThrowUserException v MFC exceptions 4.x : // in AFX.H //////////////////////////////////////////////////////////////////////// // Exception macros using try, catch and throw // (for backward compatibility to previous versions of MFC) #ifndef _AFX_OLD_EXCEPTIONS #define TRY AFX_EXCEPTION_LINK _afxexceptionlink; try 98
第 2 章 C++ 的 重 要 性 質 #define CATCH(class, e) } catch (class* e) \ ASSERT(e->IsKindOf(RUNTIME_CLASS(class))); \ _afxexceptionlink.m_pexception = e; #define AND_CATCH(class, e) } catch (class* e) \ ASSERT(e->IsKindOf(RUNTIME_CLASS(class))); \ _afxexceptionlink.m_pexception = e; #define END_CATCH } } #define THROW(e) throw e #define THROW_LAST() (AfxThrowLastCleanup(), throw) // Advanced macros for smaller code #define CATCH_ALL(e) } catch (CException* e) \ ASSERT(e->IsKindOf(RUNTIME_CLASS(CException))); \ _afxexceptionlink.m_pexception = e; #define AND_CATCH_ALL(e) } catch (CException* e) \ ASSERT(e->IsKindOf(RUNTIME_CLASS(CException))); \ _afxexceptionlink.m_pexception = e; #define END_CATCH_ALL } } } #define END_TRY } catch (CException* e) \ ASSERT(e->IsKindOf(RUNTIME_CLASS(CException))); \ _afxexceptionlink.m_pexception = e; } } #else //_AFX_OLD_EXCEPTIONS //////////////////////////////////////////////////////////////////////// // Exception macros using setjmp and longjmp // (for portability to compilers with no support for C++ exception handling) #define TRY \ AFX_EXCEPTION_LINK _afxexceptionlink; \ if (::setjmp(_afxexceptionlink.m_jumpbuf) == 0) #define CATCH(class, e) \ else if (::AfxCatchProc(RUNTIME_CLASS(class))) \ class* e = (class*)_afxexceptionlink.m_pexception; #define AND_CATCH(class, e) \ } else if (::AfxCatchProc(RUNTIME_CLASS(class))) \ class* e = (class*)_afxexceptionlink.m_pexception; 99
第 ㆒ 篇 勿 在 浮 砂 築 高 台 #define END_CATCH \ } else ::AfxThrow(NULL); } } #define THROW(e) AfxThrow(e) #define THROW_LAST() AfxThrow(NULL) // Advanced macros for smaller code #define CATCH_ALL(e) \ else CException* e = _afxexceptionlink.m_pexception; #define AND_CATCH_ALL(e) \ } else CException* e = _afxexceptionlink.m_pexception; #define END_CATCH_ALL } } #define END_TRY } #endif //_AFX_OLD_EXCEPTIONS Template C++ MFC C++ Template MFC Scribble MFC collection classes MFC 3.0 template Visual C++ 2.0 C++ template template Kaare Christian 1994/01/25 PC-Magazine C++ template x, y 100
第 2 章 C++ 的 重 要 性 質 long C++ overloaded C C++ Templates C++ template C++ template function class Template Functions power 0 #0001 int power(int base, int exponent) #0002 #0003 int result = base; #0004 if (exponent == 0) return (int)1; #0005 if (exponent < 0) return (int)0; #0006 while (--exponent) result *= base; #0007 return result; #0008 } 101
第 ㆒ 篇 勿 在 浮 砂 築 高 台 #0001 long power(long base, int exponent) #0002 #0003 long result = base; #0004 if (exponent == 0) return (long)1; #0005 if (exponent < 0) return (long)0; #0006 while (--exponent) result *= base; #0007 return result; #0008 }...... template template <class T> T power(t base, int exponent); template <class T> T power(t base, int exponent); template "class" C++ class <class T T> power template #0001 template <class T> #0002 T power(t base, int exponent) #0003 #0004 T result = base; #0005 if (exponent == 0) return (T)1; #0006 if (exponent < 0) return (T)0; #0007 while (--exponent) result *= base; #0008 return result; #0009 } T template template 102
第 2 章 C++ 的 重 要 性 質 #0001 #include <iostream.h> #0002 void main() #0003 #0004 int i = power(5, 4); #0005 long l = power(1000l, 3); #0006 long double d = power((long double)1e5, 2); #0007 #0008 cout << "i= " << i << endl; #0009 cout << "l= " << l << endl; #0010 cout << "d= " << d << endl; #0011 } i= 625 l= 1000000000 d= 1e+010 T int T long T long double int i = power(1000l, 4); // long int template T power result base 1. T result = base; 2. return (T)1; 3. return (T)0; 4. result *= base; 5. return result; C++ int long C power C++ template C++ class T C++ 103
第 ㆒ 篇 勿 在 浮 砂 築 高 台 Template Classes template classes CThree Min Max template class #0001 template <class T> #0002 class CThree #0003 #0004 public : #0005 CThree(T t1, T t2, T t3); #0006 T Min(); #0007 T Max(); #0008 private: #0009 T a, b, c; #0010 }; T int float #0001 template <class T> #0002 T CThree<T>::Min() #0003 #0004 T minab = a < b? a : b; #0005 return minab < c? minab : c; #0006 } #0007 #0008 template <class T> #0009 T CThree<T>::Max() #0010 #0011 T maxab = a < b? b : a; #0012 return maxab < c? c : maxab; #0013 } #0014 #0015 template <class T> #0016 CThree<T>::CThree(T t1, T t2, T t3) : #0017 a(t1), b(t2), c(t3) #0018 104
第 2 章 C++ 的 重 要 性 質 #0019 return; #0020 } template <class T> CThree<T> template class #0001 #include <iostream.h> #0002 void main() #0003 #0004 CThree<int> obj1(2, 5, 4); #0005 cout << obj1.min() << endl; #0006 cout << obj1.max() << endl; #0007 #0008 CThree<float> obj2(8.52, -6.75, 4.54); #0009 cout << obj2.min() << endl; #0010 cout << obj2.max() << endl; #0011 #0012 CThree<long> obj3(646600l, 437847L, 364873L); #0013 cout << obj3.min() << endl; #0014 cout << obj3.max() << endl; #0015 } 2 5-6.75 8.52 364873 646600 template T T template classes CThree copy operator< Min Max T 105
第 ㆒ 篇 勿 在 浮 砂 築 高 台 template classes template classes C++ int float Templates C++ templates template template template function template class template template Borland Smart Template template A.CPP B.CPP THREE.H template CThree A.CPP B.CPP THREE.H A.CPP int double template A.OBJ int double template B.CPP int float template B.OBJ int float template A.OBJ int 2-1 106
第 2 章 C++ 的 重 要 性 質 THREE.H template <class T> class CThree... } compiler preprocess A.CPP B.CPP #include #include three.h three.h #include #include three.h three.h............ CThree<int> CThree<int> obj1; obj1; CThree<int> CThree<int> obj1; obj1; CThree<double> CThree<double> obj2; obj2; CThree<float> CThree<float> obj2; obj2; A.OBJ CThree int version CThree double version compile CThree int version CThree float version B.OBJ link.exe CThree float version CThree int version CThree double version 2-1 template Borland smart 107
108 第 ㆒ 篇 勿 在 浮 砂 築 高 台
MFC MFC MFC application framework MFC application framework MFC MFC 4.0 189 252 58 10 MB MFC 4.2 29 MFC RTTI Runtime Type Information Dynamic Creation Persistence Message Mapping Message Routing 109
第 ㆒ 篇 勿 在 浮 砂 築 高 台 MFC Application Framework Minotaur application framework application framework MFC 10 Minotaur MFC MFC Console Windows MFC MFC MFC MFC.H MFC.CPP MY.H MY.CPP "My" CWinApp CMyWinApp CDocument CMyDoc 110
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 MFC Frame1 MFC CObject CObject CCmdTarget CCmdTarget CWinThread CWinThread CWnd CWnd CWinApp CWinApp CView CDocument CDocument CMyWinApp CMyWinApp CMyView CMyView CFrameWnd CFrameWnd CMyFrameWnd CMyFrameWnd CMyDoc CMyDoc MFC Frame? MFC MFC MFC Frame1 MFC.H #0001 #include <iostream.h> #0002 #0003 class CObject #0004 #0005 public: 111
第 ㆒ 篇 勿 在 浮 砂 築 高 台 #0006 CObject::CObject() cout << "CObject Constructor \n"; } #0007 CObject::~CObject() cout << "CObject Destructor \n"; } #0008 }; #0009 #0010 class CCmdTarget : public CObject #0011 #0012 public: #0013 CCmdTarget::CCmdTarget() cout << "CCmdTarget Constructor \n"; } #0014 CCmdTarget::~CCmdTarget() cout << "CCmdTarget Destructor \n"; } #0015 }; #0016 #0017 class CWinThread : public CCmdTarget #0018 #0019 public: #0020 CWinThread::CWinThread() cout << "CWinThread Constructor \n"; } #0021 CWinThread::~CWinThread() cout << "CWinThread Destructor \n"; } #0022 }; #0023 #0024 class CWinApp : public CWinThread #0025 #0026 public: #0027 CWinApp* m_pcurrentwinapp; #0028 #0029 public: #0030 CWinApp::CWinApp() m_pcurrentwinapp = this; cout << "CWinApp Constructor \n"; } #0031 CWinApp::~CWinApp() cout << "CWinApp Destructor \n"; } #0032 }; #0033 #0034 class CDocument : public CCmdTarget #0035 #0036 public: #0037 CDocument::CDocument() cout << "CDocument Constructor \n"; } #0038 CDocument::~CDocument() cout << "CDocument Destructor \n"; } #0039 }; #0040 #0041 #0042 class CWnd : public CCmdTarget #0043 #0044 public: #0045 CWnd::CWnd() cout << "CWnd Constructor \n"; } #0046 CWnd::~CWnd() cout << "CWnd Destructor \n"; } #0047 }; #0048 #0049 class CFrameWnd : public CWnd #0050 112
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 #0051 public: #0052 CFrameWnd::CFrameWnd() cout << "CFrameWnd Constructor \n"; } #0053 CFrameWnd::~CFrameWnd() cout << "CFrameWnd Destructor \n"; } #0054 }; #0055 #0056 class CView : public CWnd #0057 #0058 public: #0059 CView::CView() cout << "CView Constructor \n"; } #0060 CView::~CView() cout << "CView Destructor \n"; } #0061 }; #0062 #0063 #0064 // global function #0065 #0066 CWinApp* AfxGetApp(); MFC.CPP #0001 #include "my.h" // mfc.h CMyWinApp... #0002 #0003 extern CMyWinApp theapp; #0004 #0005 CWinApp* AfxGetApp() #0006 #0007 return theapp.m_pcurrentwinapp; #0008 } MY.H #0001 #include <iostream.h> #0002 #include "mfc.h" #0003 #0004 class CMyWinApp : public CWinApp #0005 #0006 public: #0007 CMyWinApp::CMyWinApp() cout << "CMyWinApp Constructor \n"; } #0008 CMyWinApp::~CMyWinApp() cout << "CMyWinApp Destructor \n"; } #0009 }; #0010 #0011 class CMyFrameWnd : public CFrameWnd #0012 #0013 public: #0014 CMyFrameWnd() cout << "CMyFrameWnd Constructor \n"; } #0015 ~CMyFrameWnd() cout << "CMyFrameWnd Destructor \n"; } 113
第 ㆒ 篇 勿 在 浮 砂 築 高 台 #0016 }; MY.CPP #0001 #include "my.h" #0002 #0003 CMyWinApp theapp; // global object #0004 #0005 //--------------------------------------------------------------- #0006 // main #0007 //--------------------------------------------------------------- #0008 void main() #0009 #0010 #0011 CWinApp* papp = AfxGetApp(); #0012 #0013 } Frame1 cl my.cpp mfc.cpp <Enter> Frame1 CObject Constructor CCmdTarget Constructor CWinThread Constructor CWinApp Constructor CMyWinApp Constructor CMyWinApp Destructor CWinApp Destructor CWinThread Destructor CCmdTarget Destructor CObject Destructor Frame1 new theapp C++ DOS main Windows WinMain theapp main main 114
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 main AfxGetApp theapp MFC MFC MFC Windows Windows MFC Frame2 Visual C++ Class View InitApplication InitInstance MFC CWinApp 115
第 ㆒ 篇 勿 在 浮 砂 築 高 台 CMyWinApp InitInstance -- main // MY.CPP CMyWinApp theapp; void main() } CWinApp* papp = AfxGetApp(); papp->initapplication(); papp->initinstance(); papp->run(); papp theapp papp->initapplication() CWinApp::InitApplication papp->initinstance() CMyWinApp::InitInstance CMyWinApp papp->run() CWinApp::Run CMyWinApp::InitInstance BOOL CMyWinApp::InitInstance() } cout << "CMyWinApp::InitInstance \n"; m_pmainwnd = new CMyFrameWnd; // CMyFrameWnd::CMyFrameWnd return TRUE; CMyFrameWnd::CMyFrameWnd() Create(); // Create CMyFrameWnd // CFrameWnd::Create } BOOL CFrameWnd::Create() 116
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 cout << "CFrameWnd::Create \n"; CreateEx(); // CreateEx CFrameWnd // CWnd::CreateEx return TRUE; } BOOL CWnd::CreateEx() cout << "CWnd::CreateEx \n"; PreCreateWindow(); // CWnd CFrameWnd // CWnd::PreCreateWindow // CFrameWnd::PreCreateWindow return TRUE; } CFrameWnd::PreCreateWindow Object slicing BOOL CFrameWnd::PreCreateWindow() cout << "CFrameWnd::PreCreateWindow \n"; return TRUE; } MFC Frame2 cl my.cpp mfc.cpp <Enter> Frame2 CWinApp::InitApplication CMyWinApp::InitInstance CMyFrameWnd::CMyFrameWnd CFrameWnd::Create CWnd::CreateEx CFrameWnd::PreCreateWindow CWinApp::Run CWinThread::Run 117
第 ㆒ 篇 勿 在 浮 砂 築 高 台 Frame2 MFC.H #0001 #define BOOL int #0002 #define TRUE 1 #0003 #define FALSE 0 #0004 #0005 #include <iostream.h> #0006 #0007 class CObject #0008 #0009 public: #0010 CObject::CObject() } #0011 CObject::~CObject() } #0012 }; #0013 #0014 class CCmdTarget : public CObject #0015 #0016 public: #0017 CCmdTarget::CCmdTarget() } #0018 CCmdTarget::~CCmdTarget() } #0019 }; #0020 #0021 class CWinThread : public CCmdTarget #0022 #0023 public: #0024 CWinThread::CWinThread() } #0025 CWinThread::~CWinThread() } #0026 #0027 virtual BOOL InitInstance() #0028 cout << "CWinThread::InitInstance \n"; #0029 return TRUE; #0030 } #0031 virtual int Run() #0032 cout << "CWinThread::Run \n"; #0033 return 1; #0034 } #0035 }; #0036 #0037 class CWnd; #0038 #0039 class CWinApp : public CWinThread #0040 #0041 public: 118
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 #0042 CWinApp* m_pcurrentwinapp; #0043 CWnd* m_pmainwnd; #0044 #0045 public: #0046 CWinApp::CWinApp() m_pcurrentwinapp = this; } #0047 CWinApp::~CWinApp() } #0048 #0049 virtual BOOL InitApplication() #0050 cout << "CWinApp::InitApplication \n"; #0051 return TRUE; #0052 } #0053 virtual BOOL InitInstance() #0054 cout << "CWinApp::InitInstance \n"; #0055 return TRUE; #0056 } #0057 virtual int Run() #0058 cout << "CWinApp::Run \n"; #0059 return CWinThread::Run(); #0060 } #0061 }; #0062 #0063 #0064 class CDocument : public CCmdTarget #0065 #0066 public: #0067 CDocument::CDocument() } #0068 CDocument::~CDocument() } #0069 }; #0070 #0071 #0072 class CWnd : public CCmdTarget #0073 #0074 public: #0075 CWnd::CWnd() } #0076 CWnd::~CWnd() } #0077 #0078 virtual BOOL Create(); #0079 BOOL CreateEx(); #0080 virtual BOOL PreCreateWindow(); #0081 }; #0082 #0083 class CFrameWnd : public CWnd #0084 #0085 public: #0086 CFrameWnd::CFrameWnd() } #0087 CFrameWnd::~CFrameWnd() } 119
第 ㆒ 篇 勿 在 浮 砂 築 高 台 #0088 BOOL Create(); #0089 virtual BOOL PreCreateWindow(); #0090 }; #0091 #0092 class CView : public CWnd #0093 #0094 public: #0095 CView::CView() } #0096 CView::~CView() } #0097 }; #0098 #0099 #0100 // global function #0101 CWinApp* AfxGetApp(); MFC.CPP #0001 #include "my.h" // #0002 mfc.h #0003 extern CMyWinApp theapp; // external global object #0004 #0005 BOOL CWnd::Create() #0006 #0007 cout << "CWnd::Create \n"; #0008 return TRUE; #0009 } #0010 #0011 BOOL CWnd::CreateEx() #0012 #0013 cout << "CWnd::CreateEx \n"; #0014 PreCreateWindow(); #0015 return TRUE; #0016 } #0017 #0018 BOOL CWnd::PreCreateWindow() #0019 #0020 cout << "CWnd::PreCreateWindow \n"; #0021 return TRUE; #0022 } #0023 #0024 BOOL CFrameWnd::Create() #0025 #0026 cout << "CFrameWnd::Create \n"; #0027 CreateEx(); #0028 return TRUE; #0029 } CMyWinApp... 120
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 #0030 #0031 BOOL CFrameWnd::PreCreateWindow() #0032 #0033 cout << "CFrameWnd::PreCreateWindow \n"; #0034 return TRUE; #0035 } #0036 #0037 #0038 CWinApp* AfxGetApp() #0039 #0040 return theapp.m_pcurrentwinapp; #0041 } MY.H #0001 #include <iostream.h> #0002 #include "mfc.h" #0003 #0004 class CMyWinApp : public CWinApp #0005 #0006 public: #0007 CMyWinApp::CMyWinApp() } #0008 CMyWinApp::~CMyWinApp() } #0009 #0010 virtual BOOL InitInstance(); #0011 }; #0012 #0013 class CMyFrameWnd : public CFrameWnd #0014 #0015 public: #0016 CMyFrameWnd(); #0017 ~CMyFrameWnd() } #0018 }; MY.CPP #0001 #include "my.h" #0002 #0003 CMyWinApp theapp; // global object #0004 #0005 BOOL CMyWinApp::InitInstance() #0006 #0007 cout << "CMyWinApp::InitInstance \n"; #0008 m_pmainwnd = new CMyFrameWnd; #0009 return TRUE; 121
第 ㆒ 篇 勿 在 浮 砂 築 高 台 #0010 } #0011 #0012 CMyFrameWnd::CMyFrameWnd() #0013 #0014 cout << "CMyFrameWnd::CMyFrameWnd \n"; #0015 Create(); #0016 } #0017 #0018 //--------------------------------------------------------------- #0019 // main #0020 //--------------------------------------------------------------- #0021 void main() #0022 #0023 #0024 CWinApp* papp = AfxGetApp(); #0025 #0026 papp->initapplication(); #0027 papp->initinstance(); #0028 papp->run(); #0029 } RTTI Visual C++ 4.0 RTTI 1. /GR /GR enable C++ RTTI 2. typeinfo.h 3. typeid RTTI Runtime Type Identification MFC RTTI DOS IsKindOf TRUE FALSE Shape CSquare* psquare = new CSquare; cout << psquare->iskindof(csquare); // 1 TRUE cout << psquare->iskindof(crect); // 1 TRUE cout << psquare->iskindof(cshape); // 1 TRUE 122
cout << psquare->iskindof(ccircle); // 0 FALSE MFC IsKindOf CMyDoc* pmydoc = new CMyDoc; cout << pmydoc->iskindof(cmydoc); // 1 TRUE cout << pmydoc->iskindof(cdocument); // 1 TRUE cout << pmydoc->iskindof(ccmdtarget); // 1 TRUE cout << pmydoc->iskindof(cwnd); // 0 FALSE CRuntimeClass RTTI RGB RTTI linked list CRuntimeClass Next First First static CRuntimeClass // in MFC.H struct CRuntimeClass // Attributes LPCSTR m_lpszclassname; int m_nobjectsize; UINT m_wschema; // schema number of the loaded class CObject* (PASCAL* m_pfncreateobject)(); // NULL => abstract class CRuntimeClass* m_pbaseclass; // CRuntimeClass objects linked together in simple list static CRuntimeClass* pfirstclass; // start of class list CRuntimeClass* m_pnextclass; // linked list of registered classes }; 123
第 ㆒ 篇 勿 在 浮 砂 築 高 台 CRuntimeClass m_lpszclassname m_nobjectsize m_wschema CRuntimeClass::pFirstClass static m_pfncreateobject m_pbaseclass m_pnextclass CRuntimeClass "class" CObject::classCObject CObject CCmdTarget::classCCmdTarget CCmdTarget CWinThread::classCWinThread CWinThread m_pbaseclass m_pnextclass m_pbaseclass m_pnextclass m_pbaseclass m_pnextclass NULL NULL CObject::classCObject CCmdTarget::classCCmdTarget CWnd::classCWnd CWinApp::classCWinApp CWnd CWinApp static CRuntimeClass::pFirstClass m_pbaseclass m_pnextclass CCmdTarget::classCCmdTarget m_pbaseclass m_pnextclass CWinThread::classCWinThread 124
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 DECLARE_DYNAMIC / IMPLEMENT_DYNAMIC CRuntimeClass DECLARE_DYNAMIC #define DECLARE_DYNAMIC(class_name) \ public: \ static CRuntimeClass class##class_name; \ virtual CRuntimeClass* GetRuntimeClass() const; ## DECLARE_DYNAMIC(CView) public: static CRuntimeClass classcview; virtual CRuntimeClass* GetRuntimeClass() const; DECLARE_DYNAMIC OK OK CRuntimeClass IMPLEMENT _DYNAMIC #define IMPLEMENT_DYNAMIC(class_name, base_class_name) \ _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, NULL) _IMPLEMENT _RUNTIMECLASS #define _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name,wschema,pfnnew) \ static char _lpsz##class_name[] = #class_name; \ CRuntimeClass class_name::class##class_name = \ _lpsz##class_name, sizeof(class_name), wschema, pfnnew, \ RUNTIME_CLASS(base_class_name), NULL }; \ static AFX_CLASSINIT _init_##class_name(&class_name::class##class_name); \ CRuntimeClass* class_name::getruntimeclass() const \ return &class_name::class##class_name; } \ 125
第 ㆒ 篇 勿 在 浮 砂 築 高 台 RUNTIME_CLASS #define RUNTIME_CLASS(class_name) \ (&class_name::class##class_name) IMPLEMENT _DYNAMIC struct AFX_CLASSINIT struct AFX_CLASSINIT AFX_CLASSINIT(CRuntimeClass* pnewclass); }; C++ struct class AFX_CLASSINIT::AFX_CLASSINIT(CRuntimeClass* pnewclass) pnewclass->m_pnextclass = CRuntimeClass::pFirstClass; CRuntimeClass::pFirstClass = pnewclass; } linked list // in header file class CView : public CWnd DECLARE_DYNAMIC(CView)... }; // in implementation file IMPLEMENT_DYNAMIC(CView, CWnd) // in header file class CView : public CWnd public: static CRuntimeClass classcview; \ virtual CRuntimeClass* GetRuntimeClass() const;... }; 126
// in implementation file static char _lpszcview[] = "CView"; CRuntimeClass CView::classCView = _lpszcview, sizeof(cview), 0xFFFF, NULL, &CWnd::classCWnd, NULL }; static AFX_CLASSINIT _init_cview(&cview::classcview); CRuntimeClass* CView::GetRuntimeClass() const return &CView::classCView; } DECLARE_DYNAMIC(Cxxx) IMPLEMENT_DYNAMIC(Cxxx, Cxxxbase) Cxxx::classCxxx Cxxx sizeof(cxxx) 0xFFFF m_pfncreateobject m_pbaseclass NULL Cxxxbase::classCxxxbase m_pnextclass CObject DECLARE_DYNAMIC IMPLEMENT_DYNAMIC // in header file class CObject public: virtual CRuntimeClass* GetRuntimeClass() const;... public: static CRuntimeClass classcobject; }; 127
第 ㆒ 篇 勿 在 浮 砂 築 高 台 // in implementation file static char szcobject[] = "CObject"; struct CRuntimeClass CObject::classCObject = szcobject, sizeof(cobject), 0xffff, NULL, NULL }; static AFX_CLASSINIT _init_cobject(&cobject::classcobject); CRuntimeClass* CObject::GetRuntimeClass() const return &CObject::classCObject; } CRuntimeClass static // in implementation file CRuntimeClass* CRuntimeClass::pFirstClass = NULL; CObject::classCObject CObject sizeof(cobject) CRuntimeClass::pFirstClass static 0xFFFF m_pfncreateobject m_pbaseclass m_pnextclass NULL NULL NULL 128
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 Frame3.h CObject CObject CCmdTarget CCmdTarget CWinThread CWinThread CWnd CWnd CWinApp CWinApp CView CDocument CDocument CMyWinApp CMyWinApp CMyView CMyView CFrameWnd CFrameWnd CMyFrameWnd CMyFrameWnd CMyDoc CMyDoc class CObject... }; class CCmdTarget : public CObject DECLARE_DYNAMIC(CCmdTarget)... }; class CWinThread : public CCmdTarget DECLARE_DYNAMIC(CWinThread)... }; class CWinApp : public CWinThread DECLARE_DYNAMIC(CWinApp)... }; class CDocument : public CCmdTarget DECLARE_DYNAMIC(CDocument) 129
第 ㆒ 篇 勿 在 浮 砂 築 高 台... }; class CWnd : public CCmdTarget DECLARE_DYNAMIC(CWnd) // MFC DECLARE_DYNCREATE()... }; class CFrameWnd : public CWnd DECLARE_DYNAMIC(CFrameWnd) // MFC DECLARE_DYNCREATE()... }; class CView : public CWnd DECLARE_DYNAMIC(CView)... }; class CMyWinApp : public CWinApp... }; class CMyFrameWnd : public CFrameWnd... // MFC DECLARE_DYNCREATE() }; class CMyDoc : public CDocument... // MFC DECLARE_DYNCREATE() }; class CMyView : public CView... // MFC DECLARE_DYNCREATE() }; Frame3.cpp IMPLEMENT_DYNAMIC(CCmdTarget, CObject) IMPLEMENT_DYNAMIC(CWinThread, CCmdTarget) IMPLEMENT_DYNAMIC(CWinApp, CWinThread) IMPLEMENT_DYNAMIC(CWnd, CCmdTarget) // MFC IMPLEMENT_DYNCREATE() IMPLEMENT_DYNAMIC(CFrameWnd, CWnd) // MFC IMPLEMENT_DYNCREATE() IMPLEMENT_DYNAMIC(CDocument, CCmdTarget) IMPLEMENT_DYNAMIC(CView, CWnd) 3-1 130
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 CObject::classCObject CObject CCmdTarget::classCCmdTarget CCmdTarget CWinThread::classCWinThread CWinThread m_pbaseclass m_pnextclass m_pbaseclass m_pnextclass m_pbaseclass m_pnextclass NULL NULL CFrameWnd::classCFrameWnd CFrameWnd CWnd::classCWnd CWnd CWinApp::classCWinApp CWinApp m_pbaseclass m_pnextclass m_pbaseclass m_pnextclass m_pbaseclass m_pnextclass CDocument::classCDocument CDocument m_pbaseclass m_pnextclass CView::classCView CView m_pbaseclass m_pnextclass static CRuntimeClass::pFirstClass 3-1 CRuntimeClass RTTI main PrintAllClas schema no. void PrintAllClasses() CRuntimeClass* pclass; // just walk through the simple list of registered classes for (pclass = CRuntimeClass::pFirstClass; pclass!= NULL; pclass = pclass->m_pnextclass) cout << pclass->m_lpszclassname << "\n"; 131
第 ㆒ 篇 勿 在 浮 砂 築 高 台 } } cout << pclass->m_nobjectsize << "\n"; cout << pclass->m_wschema << "\n"; Frame3 cl my.cpp mfc.cpp <Enter> Frame3 CView 4 65535 CDocument 4 65535 CFrameWnd 4 65535 CWnd 4 65535 CWinApp 12 65535 CWinThread 4 65535 CCmdTarget 4 65535 CObject 4 65535 Frame3 MFC.H #0001 #define BOOL int #0002 #define TRUE 1 #0003 #define FALSE 0 132
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 #0004 #define LPCSTR LPSTR #0005 typedef char* LPSTR; #0006 #define UINT int #0007 #define PASCAL _stdcall #0008 #0009 #include <iostream.h> #0010 #0011 class CObject; #0012 #0013 struct CRuntimeClass #0014 #0015 // Attributes #0016 LPCSTR m_lpszclassname; #0017 int m_nobjectsize; #0018 UINT m_wschema; // schema number of the loaded class #0019 CObject* (PASCAL* m_pfncreateobject)(); // NULL => abstract class #0020 CRuntimeClass* m_pbaseclass; #0021 #0022 // CRuntimeClass objects linked together in simple list #0023 static CRuntimeClass* pfirstclass; // start of class list #0024 CRuntimeClass* m_pnextclass; // linked list of registered classes #0025 }; #0026 #0027 struct AFX_CLASSINIT #0028 AFX_CLASSINIT(CRuntimeClass* pnewclass); }; #0029 #0030 #define RUNTIME_CLASS(class_name) \ #0031 (&class_name::class##class_name) #0032 #0033 #define DECLARE_DYNAMIC(class_name) \ #0034 public: \ #0035 static CRuntimeClass class##class_name; \ #0036 virtual CRuntimeClass* GetRuntimeClass() const; #0037 #0038 #define _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wschema, pfnnew) \ #0039 static char _lpsz##class_name[] = #class_name; \ #0040 CRuntimeClass class_name::class##class_name = \ #0041 _lpsz##class_name, sizeof(class_name), wschema, pfnnew, \ #0042 RUNTIME_CLASS(base_class_name), NULL }; \ #0043 static AFX_CLASSINIT _init_##class_name(&class_name::class##class_name); \ #0044 CRuntimeClass* class_name::getruntimeclass() const \ #0045 return &class_name::class##class_name; } \ #0046 #0047 #define IMPLEMENT_DYNAMIC(class_name, base_class_name) \ #0048 _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, NULL) #0049 133
第 ㆒ 篇 勿 在 浮 砂 築 高 台 #0050 class CObject #0051 #0052 public: #0053 CObject::CObject() #0054 } #0055 CObject::~CObject() #0056 } #0057 #0058 virtual CRuntimeClass* GetRuntimeClass() const; #0059 #0060 public: #0061 static CRuntimeClass classcobject; #0062 }; #0063 #0064 class CCmdTarget : public CObject #0065 #0066 DECLARE_DYNAMIC(CCmdTarget) #0067 public: #0068 CCmdTarget::CCmdTarget() #0069 } #0070 CCmdTarget::~CCmdTarget() #0071 } #0072 }; #0073 #0074 class CWinThread : public CCmdTarget #0075 #0076 DECLARE_DYNAMIC(CWinThread) #0077 public: #0078 CWinThread::CWinThread() #0079 } #0080 CWinThread::~CWinThread() #0081 } #0082 #0083 virtual BOOL InitInstance() #0084 return TRUE; #0085 } #0086 virtual int Run() #0087 return 1; #0088 } #0089 }; #0090 #0091 class CWnd; #0092 #0093 class CWinApp : public CWinThread #0094 #0095 DECLARE_DYNAMIC(CWinApp) 134
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 #0096 public: #0097 CWinApp* m_pcurrentwinapp; #0098 CWnd* m_pmainwnd; #0099 #0100 public: #0101 CWinApp::CWinApp() #0102 m_pcurrentwinapp = this; #0103 } #0104 CWinApp::~CWinApp() #0105 } #0106 #0107 virtual BOOL InitApplication() #0108 return TRUE; #0109 } #0110 virtual BOOL InitInstance() #0111 return TRUE; #0112 } #0113 virtual int Run() #0114 return CWinThread::Run(); #0115 } #0116 }; #0117 #0118 class CDocument : public CCmdTarget #0119 #0120 DECLARE_DYNAMIC(CDocument) #0121 public: #0122 CDocument::CDocument() #0123 } #0124 CDocument::~CDocument() #0125 } #0126 }; #0127 #0128 class CWnd : public CCmdTarget #0129 #0130 DECLARE_DYNAMIC(CWnd) #0131 public: #0132 CWnd::CWnd() #0133 } #0134 CWnd::~CWnd() #0135 } #0136 #0137 virtual BOOL Create(); #0138 BOOL CreateEx(); #0139 virtual BOOL PreCreateWindow(); #0140 }; #0141 135
第 ㆒ 篇 勿 在 浮 砂 築 高 台 #0142 class CFrameWnd : public CWnd #0143 #0144 DECLARE_DYNAMIC(CFrameWnd) #0145 public: #0146 CFrameWnd::CFrameWnd() #0147 } #0148 CFrameWnd::~CFrameWnd() #0149 } #0150 BOOL Create(); #0151 virtual BOOL PreCreateWindow(); #0152 }; #0153 #0154 class CView : public CWnd #0155 #0156 DECLARE_DYNAMIC(CView) #0157 public: #0158 CView::CView() #0159 } #0160 CView::~CView() #0161 } #0162 }; #0163 #0164 #0165 // global function #0166 CWinApp* AfxGetApp(); MFC.CPP #0001 #include "my.h" // mfc.h CMyWinApp... #0002 #0003 extern CMyWinApp theapp; #0004 #0005 static char szcobject[] = "CObject"; #0006 struct CRuntimeClass CObject::classCObject = #0007 szcobject, sizeof(cobject), 0xffff, NULL, NULL }; #0008 static AFX_CLASSINIT _init_cobject(&cobject::classcobject); #0009 #0010 CRuntimeClass* CRuntimeClass::pFirstClass = NULL; #0011 #0012 AFX_CLASSINIT::AFX_CLASSINIT(CRuntimeClass* pnewclass) #0013 #0014 pnewclass->m_pnextclass = CRuntimeClass::pFirstClass; #0015 CRuntimeClass::pFirstClass = pnewclass; #0016 } #0017 #0018 CRuntimeClass* CObject::GetRuntimeClass() const 136
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 #0019 #0020 return &CObject::classCObject; #0021 } #0022 #0023 BOOL CWnd::Create() #0024 #0025 return TRUE; #0026 } #0027 #0028 BOOL CWnd::CreateEx() #0029 #0030 PreCreateWindow(); #0031 return TRUE; #0032 } #0033 #0034 BOOL CWnd::PreCreateWindow() #0035 #0036 return TRUE; #0037 } #0038 #0039 BOOL CFrameWnd::Create() #0040 #0041 CreateEx(); #0042 return TRUE; #0043 } #0044 #0045 BOOL CFrameWnd::PreCreateWindow() #0046 #0047 return TRUE; #0048 } #0049 #0050 IMPLEMENT_DYNAMIC(CCmdTarget, CObject) #0051 IMPLEMENT_DYNAMIC(CWinThread, CCmdTarget) #0052 IMPLEMENT_DYNAMIC(CWinApp, CWinThread) #0053 IMPLEMENT_DYNAMIC(CWnd, CCmdTarget) #0054 IMPLEMENT_DYNAMIC(CFrameWnd, CWnd) #0055 IMPLEMENT_DYNAMIC(CDocument, CCmdTarget) #0056 IMPLEMENT_DYNAMIC(CView, CWnd) #0057 #0058 // global function #0059 CWinApp* AfxGetApp() #0060 #0061 return theapp.m_pcurrentwinapp; #0062 } 137
第 ㆒ 篇 勿 在 浮 砂 築 高 台 MY.H #0001 #include <iostream.h> #0002 #include "mfc.h" #0003 #0004 class CMyWinApp : public CWinApp #0005 #0006 public: #0007 CMyWinApp::CMyWinApp() #0008 } #0009 CMyWinApp::~CMyWinApp() #0010 } #0011 #0012 virtual BOOL InitInstance(); #0013 }; #0014 #0015 class CMyFrameWnd : public CFrameWnd #0016 #0017 public: #0018 CMyFrameWnd(); #0019 ~CMyFrameWnd() #0020 } #0021 }; #0022 #0023 #0024 class CMyDoc : public CDocument #0025 #0026 public: #0027 CMyDoc::CMyDoc() #0028 } #0029 CMyDoc::~CMyDoc() #0030 } #0031 }; #0032 #0033 class CMyView : public CView #0034 #0035 public: #0036 CMyView::CMyView() #0037 } #0038 CMyView::~CMyView() #0039 } #0040 }; #0041 #0042 // global function #0043 void PrintAllClasses(); 138
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 MY.CPP #0001 #include "my.h" #0002 #0003 CMyWinApp theapp; #0004 #0005 BOOL CMyWinApp::InitInstance() #0006 #0007 m_pmainwnd = new CMyFrameWnd; #0008 return TRUE; #0009 } #0010 #0011 CMyFrameWnd::CMyFrameWnd() #0012 #0013 Create(); #0014 } #0015 #0016 void PrintAllClasses() #0017 #0018 CRuntimeClass* pclass; #0019 #0020 // just walk through the simple list of registered classes #0021 for (pclass = CRuntimeClass::pFirstClass; pclass!= NULL; #0022 pclass = pclass->m_pnextclass) #0023 #0024 cout << pclass->m_lpszclassname << "\n"; #0025 cout << pclass->m_nobjectsize << "\n"; #0026 cout << pclass->m_wschema << "\n"; #0027 } #0028 } #0029 //--------------------------------------------------------------- #0030 // main #0031 //--------------------------------------------------------------- #0032 void main() #0033 #0034 CWinApp* papp = AfxGetApp(); #0035 #0036 papp->initapplication(); #0037 papp->initinstance(); #0038 papp->run(); #0039 #0040 PrintAllClasses(); #0041 } 139
第 ㆒ 篇 勿 在 浮 砂 築 高 台 IsKindOf 3-1 IsKindOf 1. CObject IsKindOf CRuntimeClass TRUE FALSE // in header file class CObject public:... BOOL IsKindOf(const CRuntimeClass* pclass) const; }; // in implementation file BOOL CObject::IsKindOf(const CRuntimeClass* pclass) const CRuntimeClass* pclassthis = GetRuntimeClass(); while (pclassthis!= NULL) if (pclassthis == pclass) return TRUE; pclassthis = pclassthis->m_pbaseclass; } return FALSE; // walked to the top, no match } while m_ m_pnextclass CView* pview = new CView; pview->iskindof(runtime_class(cwinapp)); IsKindOf &CWinApp::classCWinApp GetRuntimeClass &CView ::classcview 3-1 CView CWnd CCmdTarget CObject CRuntimeClass CView ::classcview IsKindOf 140
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 2. IsKindOf 的 使 用 方 式 如 : CMyDoc* pmydoc = new CMyDoc; CMyView* pmyview = new CMyView; cout << pmydoc->iskindof(runtime_class(cmydoc)); // 應 該 獲 得 TRUE cout << pmydoc->iskindof(runtime_class(cdocument)); // 應 該 獲 得 TRUE cout << pmydoc->iskindof(runtime_class(ccmdtarget)); // 應 該 獲 得 TRUE cout << pmydoc->iskindof(runtime_class(cobject)); // 應 該 獲 得 TRUE cout << pmydoc->iskindof(runtime_class(cwinapp)); // 應 該 獲 得 FALSE cout << pmydoc->iskindof(runtime_class(cview)); // 應 該 獲 得 FALSE cout << pmyview->iskindof(runtime_class(cview)); // 應 該 獲 得 TRUE cout << pmyview->iskindof(runtime_class(cobject)); // 應 該 獲 得 TRUE cout << pmyview->iskindof(runtime_class(cwnd)); // 應 該 獲 得 TRUE cout << pmyview->iskindof(runtime_class(cframewnd)); // FALSE IsKindOf Frame4 Frame4 Frame4 Frame3 CObject IsKindOf non-mfc // in header file class CMyFrameWnd : public CFrameWnd DECLARE_DYNAMIC(CMyFrameWnd) // MFC DECLARE_DYNCREATE()... // DECLARE_DYNCREATE() }; class CMyDoc : public CDocument DECLARE_DYNAMIC(CMyDoc) // MFC DECLARE_DYNCREATE()... // DECLARE_DYNCREATE() }; class CMyView : public CView DECLARE_DYNAMIC(CMyView) // MFC DECLARE_DYNCREATE()... // DECLARE_DYNCREATE() }; 141
第 ㆒ 篇 勿 在 浮 砂 築 高 台 // in implementation file... IMPLEMENT_DYNAMIC(CMyFrameWnd, CFrameWnd) // MFC IMPLEMENT_DYNCREATE() // IMPLEMENT_DYNCREATE()... IMPLEMENT_DYNAMIC(CMyDoc, CDocument) // MFC IMPLEMENT_DYNCREATE() // IMPLEMENT_DYNCREATE()... IMPLEMENT_DYNAMIC(CMyView, CView) // MFC IMPLEMENT_DYNCREATE() // IMPLEMENT_DYNCREATE() Frame4 cl my.cpp mfc.cpp <Enter> Frame4 pmydoc->iskindof(runtime_class(cmydoc)) 1 pmydoc->iskindof(runtime_class(cdocument)) 1 pmydoc->iskindof(runtime_class(ccmdtarget)) 1 pmydoc->iskindof(runtime_class(cobject)) 1 pmydoc->iskindof(runtime_class(cwinapp)) 0 pmydoc->iskindof(runtime_class(cview)) 0 pmyview->iskindof(runtime_class(cview)) 1 pmyview->iskindof(runtime_class(cobject)) 1 pmyview->iskindof(runtime_class(cwnd)) 1 pmyview->iskindof(runtime_class(cframewnd)) 0 pmywnd->iskindof(runtime_class(cframewnd)) 1 pmywnd->iskindof(runtime_class(cwnd)) 1 pmywnd->iskindof(runtime_class(cobject)) 1 pmywnd->iskindof(runtime_class(cdocument)) 0 142
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 Dynamic Creation ( C++ CRuntimeClass::CreateObject C++ CRuntimeClass // in MFC.H struct CRuntimeClass // Attributes LPCSTR m_lpszclassname; int m_nobjectsize; UINT m_wschema; // schema number of the loaded class CObject* (PASCAL* m_pfncreateobject)(); // NULL => abstract class CRuntimeClass* m_pbaseclass; CObject* CreateObject(); static CRuntimeClass* PASCAL Load(); }; // CRuntimeClass objects linked together in simple list static CRuntimeClass* pfirstclass; // start of class list CRuntimeClass* m_pnextclass; // linked list of registered classes 143
DECLARE_DYNCREATE/IMPLEMENT_DYNCREATE CRuntimeClass DECLARE_DYNCREATE IMPLEMENT _DYNCREATE #define DECLARE_DYNCREATE(class_name) \ DECLARE_DYNAMIC(class_name) \ static CObject* PASCAL CreateObject(); #define IMPLEMENT_DYNCREATE(class_name, base_class_name) \ CObject* PASCAL class_name::createobject() \ return new class_name; } \ _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, \ class_name::createobject) CFrameWnd // in header file class CFrameWnd : public CWnd DECLARE_DYNCREATE(CFrameWnd)... }; // in implementation file IMPLEMENT_DYNCREATE(CFrameWnd, CWnd) /P // in header file class CFrameWnd : public CWnd public: static CRuntimeClass classcframewnd; virtual CRuntimeClass* GetRuntimeClass() const; static CObject* PASCAL CreateObject();... }; // in implementation file CObject* PASCAL CFrameWnd::CreateObject() return new CFrameWnd; } 144
static char _lpszcframewnd[] = "CFrameWnd"; CRuntimeClass CFrameWnd::classCFrameWnd = _lpszcframewnd, sizeof(cframewnd), 0xFFFF, CFrameWnd::CreateObject, RUNTIME_CLASS(CWnd), NULL }; static AFX_CLASSINIT _init_cframewnd(&cframewnd::classcframewnd); CRuntimeClass* CFrameWnd::GetRuntimeClass() const return &CFrameWnd::classCFrameWnd; } CO bject::classcobject C O b je ct CCm dtarget::classccm dtarget CCm dtarget CW inthread::classcw inthread CW inthread m _pbaseclass m _pnextclass m _pbaseclass m _pnextclass m _pbaseclass m _pnextclass NULL NULL CFrameW nd::classcframew nd CFram ew nd C W n d ::c la s s C W n d CW nd CW inapp::classcw inapp CW inapp m _pbaseclass m _pnextclass m _pbaseclass m _pnextclass m _pbaseclass m _pnextclass CDocum ent::classcdocum ent C D o cu m e n t m _pbaseclass m _pnextclass CView ::classcview C V ie w m _pbaseclass m _pnextclass s t a t i c CRuntim eclass::pfirstclass CreateObject new Dynamic Creation RTTI _DYNCREATE _DYNAMIC Frame6 Frame5 MFC 2.5 MFC 4.x Frame5 145
第 ㆒ 篇 勿 在 浮 砂 築 高 台 Frame6.h class CObject... }; class CCmdTarget : public CObject DECLARE_DYNAMIC(CCmdTarget)... }; class CWinThread : public CCmdTarget DECLARE_DYNAMIC(CWinThread)... }; class CWinApp : public CWinThread DECLARE_DYNAMIC(CWinApp)... }; class CDocument : public CCmdTarget DECLARE_DYNAMIC(CDocument)... }; class CWnd : public CCmdTarget DECLARE_DYNCREATE(CWnd)... }; class CFrameWnd : public CWnd DECLARE_DYNCREATE(CFrameWnd)... }; class CView : public CWnd DECLARE_DYNAMIC(CView)... }; class CMyWinApp : public CWinApp... }; class CMyFrameWnd : public CFrameWnd 146
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 DECLARE_DYNCREATE(CMyFrameWnd)... }; class CMyDoc : public CDocument DECLARE_DYNCREATE(CMyDoc)... }; class CMyView : public CView DECLARE_DYNCREATE(CMyView)... };.cpp IMPLEMENT_DYNAMIC(CCmdTarget, CObject) IMPLEMENT_DYNAMIC(CWinThread, CCmdTarget) IMPLEMENT_DYNAMIC(CWinApp, CWinThread) IMPLEMENT_DYNCREATE(CWnd, CCmdTarget) IMPLEMENT_DYNCREATE(CFrameWnd, CWnd) IMPLEMENT_DYNAMIC(CDocument, CCmdTarget) IMPLEMENT_DYNAMIC(CView, CWnd) IMPLEMENT_DYNCREATE(CMyFrameWnd, CFrameWnd) IMPLEMENT_DYNCREATE(CMyDoc, CDocument) IMPLEMENT_DYNCREATE(CMyView, CView) 3-2 147
第 ㆒ 篇 勿 在 浮 砂 築 高 台 CObject::classCObject CObject 4 CCmdTarget::classCCmdTarget CCmdTarget 4 CWinThread::classCWinThread CWinThread 4 m_pfncreateobject NULL m_pfncreateobject NULL m_pfncreateobject NULL m_pnextclass m_pnextclass m_pnextclass NULL CFrameWnd::classCFrameWnd CFrameWnd 12 CWnd::classCWnd CWnd 4 CWinApp::classCWinApp CWinApp 4 m_pfncreateobject m_pfncreateobject m_pfncreateobject NULL m_pnextclass m_pnextclass m_pnextclass CDocument::classCDocument CDocument 4 CView::classCView CView 4 static CRuntimeClass::pFirstClass m_pfncreateobject NULL m_pfncreateobject NULL m_pnextclass m_pnextclass 3-2 CRuntimeClass Dynamic Creation m_pfncreateobject NULL main void main()... //Test Dynamic Creation CRuntimeClass* pclassref; CObject* pob; while(1) 148
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 if ((pclassref = CRuntimeClass::Load()) == NULL) break; pob = pclassref->createobject(); if (pob!= NULL) pob->sayhello(); } } CRuntimeClass::CreateObject 和 CRuntimeClass::Load 如 : // in implementation file CObject* CRuntimeClass::CreateObject() if (m_pfncreateobject == NULL) TRACE1("Error: Trying to create object which is not " "DECLARE_DYNCREATE \nor DECLARE_SERIAL: %hs.\n", m_lpszclassname); return NULL; } CObject* pobject = NULL; pobject = (*m_pfncreateobject)(); } return pobject; CRuntimeClass* PASCAL CRuntimeClass::Load() char szclassname[64]; CRuntimeClass* pclass; // JJHOU : instead of Load from file, we Load from cin. cout << "enter a class name... "; cin >> szclassname; for (pclass = pfirstclass; pclass!= NULL; pclass = pclass->m_pnextclass) if (strcmp(szclassname, pclass->m_lpszclassname) == 0) return pclass; } } TRACE1("Error: Class not found: %s \n", szclassname); return NULL; // not found 149
第 ㆒ 篇 勿 在 浮 砂 築 高 台 SayHello SayHello SayHello main while CRuntimeClass ::Load NULL CRuntimeClass ::Load NULL Frame6 cl my.cpp mfc.cpp <Enter> Frame6 enter a class name... CObject Error: Trying to create object which is not DECLARE_DYNCREATE or DECLARE_SERIAL: CObject. enter a class name... CView Error: Trying to create object which is not DECLARE_DYNCREATE or DECLARE_SERIAL: CView. enter a class name... CMyView CWnd Constructor CMyView Constructor Hello CMyView enter a class name... CMyFrameWnd CWnd Constructor CFrameWnd Constructor CMyFrameWnd Constructor Hello CMyFrameWnd enter a class name... CMyDoc CMyDoc Constructor Hello CMyDoc 150
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 enter a class name... CWinApp Error: Trying to create object which is not DECLARE_DYNCREATE or DECLARE_SERIAL: CWinApp. enter a class name... CJjhou Error: Class not found: CJjhou Frame6 MFC.H #0001 #define BOOL int #0002 #define TRUE 1 #0003 #define FALSE 0 #0004 #define LPCSTR LPSTR #0005 typedef char* LPSTR; #0006 #define UINT int #0007 #define PASCAL _stdcall #0008 #define TRACE1 printf #0009 #0010 #include <iostream.h> #0011 #include <stdio.h> #0012 #include <string.h> #0013 #0014 class CObject; #0015 #0016 struct CRuntimeClass #0017 #0018 // Attributes #0019 LPCSTR m_lpszclassname; #0020 int m_nobjectsize; #0021 UINT m_wschema; // schema number of the loaded class #0022 CObject* (PASCAL* m_pfncreateobject)(); // NULL => abstract class #0023 CRuntimeClass* m_pbaseclass; #0024 #0025 CObject* CreateObject(); #0026 static CRuntimeClass* PASCAL Load(); #0027 #0028 // CRuntimeClass objects linked together in simple list #0029 static CRuntimeClass* pfirstclass; // start of class list #0030 CRuntimeClass* m_pnextclass; // linked list of registered classes #0031 }; #0032 #0033 struct AFX_CLASSINIT 151
第 ㆒ 篇 勿 在 浮 砂 築 高 台 #0034 AFX_CLASSINIT(CRuntimeClass* pnewclass); }; #0035 #0036 #define RUNTIME_CLASS(class_name) \ #0037 (&class_name::class##class_name) #0038 #0039 #define DECLARE_DYNAMIC(class_name) \ #0040 public: \ #0041 static CRuntimeClass class##class_name; \ #0042 virtual CRuntimeClass* GetRuntimeClass() const; #0043 #0044 #define DECLARE_DYNCREATE(class_name) \ #0045 DECLARE_DYNAMIC(class_name) \ #0046 static CObject* PASCAL CreateObject(); #0047 #0048 #define _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wschema, pfnnew) \ #0049 static char _lpsz##class_name[] = #class_name; \ #0050 CRuntimeClass class_name::class##class_name = \ #0051 _lpsz##class_name, sizeof(class_name), wschema, pfnnew, \ #0052 RUNTIME_CLASS(base_class_name), NULL }; \ #0053 static AFX_CLASSINIT _init_##class_name(&class_name::class##class_name); \ #0054 CRuntimeClass* class_name::getruntimeclass() const \ #0055 return &class_name::class##class_name; } \ #0056 #0057 #define IMPLEMENT_DYNAMIC(class_name, base_class_name) \ #0058 _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, NULL) #0059 #0060 #define IMPLEMENT_DYNCREATE(class_name, base_class_name) \ #0061 CObject* PASCAL class_name::createobject() \ #0062 return new class_name; } \ #0063 _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, \ #0064 class_name::createobject) #0065 #0066 class CObject #0067 #0068 public: #0069 CObject::CObject() #0070 } #0071 CObject::~CObject() #0072 } #0073 #0074 virtual CRuntimeClass* GetRuntimeClass() const; #0075 BOOL IsKindOf(const CRuntimeClass* pclass) const; #0076 #0077 public: #0078 static CRuntimeClass classcobject; #0079 virtual void SayHello() cout << "Hello CObject \n"; } 152
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 #0080 }; #0081 #0082 class CCmdTarget : public CObject #0083 #0084 DECLARE_DYNAMIC(CCmdTarget) #0085 public: #0086 CCmdTarget::CCmdTarget() #0087 } #0088 CCmdTarget::~CCmdTarget() #0089 } #0090 }; #0091 #0092 class CWinThread : public CCmdTarget #0093 #0094 DECLARE_DYNAMIC(CWinThread) #0095 public: #0096 CWinThread::CWinThread() #0097 } #0098 CWinThread::~CWinThread() #0099 } #0100 #0101 virtual BOOL InitInstance() #0102 return TRUE; #0103 } #0104 virtual int Run() #0105 return 1; #0106 } #0107 }; #0108 #0109 class CWnd; #0110 #0111 class CWinApp : public CWinThread #0112 #0113 DECLARE_DYNAMIC(CWinApp) #0114 public: #0115 CWinApp* m_pcurrentwinapp; #0116 CWnd* m_pmainwnd; #0117 #0118 public: #0119 CWinApp::CWinApp() #0120 m_pcurrentwinapp = this; #0121 } #0122 CWinApp::~CWinApp() #0123 } #0124 #0125 virtual BOOL InitApplication() 153
第 ㆒ 篇 勿 在 浮 砂 築 高 台 #0126 return TRUE; #0127 } #0128 virtual BOOL InitInstance() #0129 return TRUE; #0130 } #0131 virtual int Run() #0132 return CWinThread::Run(); #0133 } #0134 }; #0135 #0136 #0137 class CDocument : public CCmdTarget #0138 #0139 DECLARE_DYNAMIC(CDocument) #0140 public: #0141 CDocument::CDocument() #0142 } #0143 CDocument::~CDocument() #0144 } #0145 }; #0146 #0147 class CWnd : public CCmdTarget #0148 #0149 DECLARE_DYNCREATE(CWnd) #0150 public: #0151 CWnd::CWnd() #0152 cout << "CWnd Constructor \n"; #0153 } #0154 CWnd::~CWnd() #0155 } #0156 #0157 virtual BOOL Create(); #0158 BOOL CreateEx(); #0159 virtual BOOL PreCreateWindow(); #0160 void SayHello() cout << "Hello CWnd \n"; } #0161 }; #0162 #0163 class CFrameWnd : public CWnd #0164 #0165 DECLARE_DYNCREATE(CFrameWnd) #0166 public: #0167 CFrameWnd::CFrameWnd() #0168 cout << "CFrameWnd Constructor \n"; #0169 } #0170 CFrameWnd::~CFrameWnd() #0171 } 154
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 #0172 BOOL Create(); #0173 virtual BOOL PreCreateWindow(); #0174 void SayHello() cout << "Hello CFrameWnd \n"; } #0175 }; #0176 #0177 class CView : public CWnd #0178 #0179 DECLARE_DYNAMIC(CView) #0180 public: #0181 CView::CView() #0182 } #0183 CView::~CView() #0184 } #0185 }; #0186 #0187 // global function #0188 CWinApp* AfxGetApp(); MFC.CPP #0001 #include "my.h" // it should be mfc.h, but for CMyWinApp definition, so... #0002 #0003 extern CMyWinApp theapp; #0004 #0005 static char szcobject[] = "CObject"; #0006 struct CRuntimeClass CObject::classCObject = #0007 szcobject, sizeof(cobject), 0xffff, NULL, NULL }; #0008 static AFX_CLASSINIT _init_cobject(&cobject::classcobject); #0009 #0010 CRuntimeClass* CRuntimeClass::pFirstClass = NULL; #0011 #0012 AFX_CLASSINIT::AFX_CLASSINIT(CRuntimeClass* pnewclass) #0013 #0014 pnewclass->m_pnextclass = CRuntimeClass::pFirstClass; #0015 CRuntimeClass::pFirstClass = pnewclass; #0016 } #0017 #0018 CObject* CRuntimeClass::CreateObject() #0019 #0020 if (m_pfncreateobject == NULL) #0021 #0022 TRACE1("Error: Trying to create object which is not " #0023 "DECLARE_DYNCREATE \nor DECLARE_SERIAL: %hs.\n", #0024 m_lpszclassname); #0025 return NULL; #0026 } 155
第 ㆒ 篇 勿 在 浮 砂 築 高 台 #0027 #0028 CObject* pobject = NULL; #0029 pobject = (*m_pfncreateobject)(); #0030 #0031 return pobject; #0032 } #0033 #0034 CRuntimeClass* PASCAL CRuntimeClass::Load() #0035 #0036 char szclassname[64]; #0037 CRuntimeClass* pclass; #0038 #0039 // JJHOU : instead of Load from file, we Load from cin. #0040 cout << "enter a class name... "; #0041 cin >> szclassname; #0042 #0043 for (pclass = pfirstclass; pclass!= NULL; pclass = pclass->m_pnextclass) #0044 #0045 if (strcmp(szclassname, pclass->m_lpszclassname) == 0) #0046 return pclass; #0047 } #0048 #0049 TRACE1("Error: Class not found: %s \n", szclassname); #0050 return NULL; // not found #0051 } #0052 #0053 CRuntimeClass* CObject::GetRuntimeClass() const #0054 #0055 return &CObject::classCObject; #0056 } #0057 #0058 BOOL CObject::IsKindOf(const CRuntimeClass* pclass) const #0059 #0060 CRuntimeClass* pclassthis = GetRuntimeClass(); #0061 while (pclassthis!= NULL) #0062 #0063 if (pclassthis == pclass) #0064 return TRUE; #0065 pclassthis = pclassthis->m_pbaseclass; #0066 } #0067 return FALSE; // walked to the top, no match #0068 } #0069 #0070 BOOL CWnd::Create() #0071 #0072 return TRUE; 156
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 #0073 } #0074 #0075 BOOL CWnd::CreateEx() #0076 #0077 PreCreateWindow(); #0078 return TRUE; #0079 } #0080 #0081 BOOL CWnd::PreCreateWindow() #0082 #0083 return TRUE; #0084 } #0085 #0086 BOOL CFrameWnd::Create() #0087 #0088 CreateEx(); #0089 return TRUE; #0090 } #0091 #0092 BOOL CFrameWnd::PreCreateWindow() #0093 #0094 return TRUE; #0095 } #0096 #0097 CWinApp* AfxGetApp() #0098 #0099 return theapp.m_pcurrentwinapp; #0100 } #0101 #0102 IMPLEMENT_DYNAMIC(CCmdTarget, CObject) #0103 IMPLEMENT_DYNAMIC(CWinThread, CCmdTarget) #0104 IMPLEMENT_DYNAMIC(CWinApp, CWinThread) #0105 IMPLEMENT_DYNAMIC(CDocument, CCmdTarget) #0106 IMPLEMENT_DYNCREATE(CWnd, CCmdTarget) #0107 IMPLEMENT_DYNAMIC(CView, CWnd) #0108 IMPLEMENT_DYNCREATE(CFrameWnd, CWnd) MY.H #0001 #include <iostream.h> #0002 #include "mfc.h" #0003 #0004 class CMyWinApp : public CWinApp #0005 #0006 public: #0007 CMyWinApp::CMyWinApp() 157
第 ㆒ 篇 勿 在 浮 砂 築 高 台 #0008 } #0009 CMyWinApp::~CMyWinApp() #0010 } #0011 #0012 virtual BOOL InitInstance(); #0013 }; #0014 #0015 class CMyFrameWnd : public CFrameWnd #0016 #0017 DECLARE_DYNCREATE(CMyFrameWnd) #0018 public: #0019 CMyFrameWnd(); #0020 ~CMyFrameWnd() #0021 } #0022 void SayHello() cout << "Hello CMyFrameWnd \n"; } #0023 }; #0024 #0025 class CMyDoc : public CDocument #0026 #0027 DECLARE_DYNCREATE(CMyDoc) #0028 public: #0029 CMyDoc::CMyDoc() #0030 cout << "CMyDoc Constructor \n"; #0031 } #0032 CMyDoc::~CMyDoc() #0033 } #0034 void SayHello() cout << "Hello CMyDoc \n"; } #0035 }; #0036 #0037 class CMyView : public CView #0038 #0039 DECLARE_DYNCREATE(CMyView) #0040 public: #0041 CMyView::CMyView() #0042 cout << "CMyView Constructor \n"; #0043 } #0044 CMyView::~CMyView() #0045 } #0046 void SayHello() cout << "Hello CMyView \n"; } #0047 }; #0048 #0049 // global function #0050 void AfxPrintAllClasses(); 158
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 MY.CPP #0001 #include "my.h" #0002 #0003 CMyWinApp theapp; #0004 #0005 BOOL CMyWinApp::InitInstance() #0006 #0007 m_pmainwnd = new CMyFrameWnd; #0008 return TRUE; #0009 } #0010 #0011 CMyFrameWnd::CMyFrameWnd() #0012 #0013 cout << "CMyFrameWnd Constructor \n"; #0014 Create(); #0015 } #0016 #0017 IMPLEMENT_DYNCREATE(CMyFrameWnd, CFrameWnd) #0018 IMPLEMENT_DYNCREATE(CMyDoc, CDocument) #0019 IMPLEMENT_DYNCREATE(CMyView, CView) #0020 #0021 void PrintAllClasses() #0022 #0023 CRuntimeClass* pclass; #0024 #0025 // just walk through the simple list of registered classes #0026 for (pclass = CRuntimeClass::pFirstClass; pclass!= NULL; #0027 pclass = pclass->m_pnextclass) #0028 #0029 cout << pclass->m_lpszclassname << "\n"; #0030 cout << pclass->m_nobjectsize << "\n"; #0031 cout << pclass->m_wschema << "\n"; #0032 } #0033 } #0034 //--------------------------------------------------------------- #0035 // main #0036 //--------------------------------------------------------------- #0037 void main() #0038 #0039 CWinApp* papp = AfxGetApp(); #0040 #0041 papp->initapplication(); #0042 papp->initinstance(); #0043 papp->run(); #0044 159
第 ㆒ 篇 勿 在 浮 砂 築 高 台 #0045 //Test Dynamic Creation #0046 CRuntimeClass* pclassref; #0047 CObject* pob; #0048 while(1) #0049 #0050 if ((pclassref = CRuntimeClass::Load()) == NULL) #0051 break; #0052 #0053 pob = pclassref->createobject(); #0054 if (pob!= NULL) #0055 pob->sayhello(); #0056 } #0057 } Persistence Persistence Power Document/View document MFC Serialize... >> << overload Serialize 160
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 Serialize Stroke CObject CObject CObList CObList CDWordArray CDWordArray CStroke CStroke CRectangle CRectangle CCircle CRect CRect CPoint CPoint CSize CSize CDocument CDocument CMyDoc CMyDoc CObList CDWordArray MFC CObject " CStroke CRectangle CCircle CObject class CMyDoc : public CDocument CObList m_graphlist; CSize m_sizedoc;... }; class CStroke : public CObject CDWordArray m_ptarray; // series of connected points... }; class CRectangle : public CObject CRect m_rect;... }; class CCircle : public CObject 161
第 ㆒ 篇 勿 在 浮 砂 築 高 台 }; CPoint m_center; UINT m_radius;... 3-3 Serialize 3-3 06 00 ;CObList elements count 07 00 ;class name string length 43 53 74 72 6F 6B 65 ;"CStroke" 02 00 ;DWordArray size 28 00 13 00 ;point 28 00 13 00 ;point 0A 00 ;class name string length 43 52 65 63 74 61 6E 67 6C 65 ;"CRectangle" 11 00 22 00 33 00 44 00 ;CRect 07 00 ;class name string length 43 43 69 72 63 6C 65 ;"CCircle" 55 00 66 00 77 00 ;CPoint & radius 07 00 ;class name string length 43 53 74 72 6F 6B 65 ;"CStroke" 02 00 ;DWordArray size 28 00 35 00 ;point 28 00 35 00 ;point 0A 00 ;class name string length 43 52 65 63 74 61 6E 67 6C 65 ;"CRectangle" 11 00 22 00 33 00 44 00 ;CRect 07 00 ;class name string length 43 43 69 72 63 6C 65 ;"CCircle" 55 00 66 00 77 00 ;CPoint & radius 100 50 80 230 162
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 CObList m_graphlist CObList m_graphlist 3-3 Serialization 163
第 ㆒ 篇 勿 在 浮 砂 築 高 台 20 03 84 03 ;Document Size 06 00 ;CObList elements count FF FF ;new class tag 02 00 ;schema 07 00 ;class name string length 43 53 74 72 6F 6B 65 ;"CStroke" 02 00 ;DWordArray size 28 00 13 00 ;point 28 00 13 00 ;point FF FF ;new class tag 01 00 ;schema 0A 00 ;class name string length 43 52 65 63 74 61 6E 67 6C 65 ;"CRectangle" 11 00 22 00 33 00 44 00 ;CRect FF FF ;new class tag 01 00 ;schema 07 00 ;class name string length 43 43 69 72 63 6C 65 ;"CCircle" 55 00 66 00 77 00 ;CPoint & radius 01 80 ;old class tag 02 00 ;DWordArray size 28 00 35 00 ;point 28 00 35 00 ;point 03 80 ;old class tag 11 00 22 00 33 00 44 00 ;CRect 05 80 ;old class tag 55 00 66 00 77 00 ;CPoint & radius Serialization Serialize Document CScribDoc void CScribDoc::Serialize(CArchive& ar) if (ar.isstoring()) ar << m_sizedoc; else ar >> m_sizedoc; m_graphlist.serialize(ar); } void CObList::Serialize(CArchive& ar) if (ar.isstoring()) 164
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 } ar << (WORD) m_ncount; for (CNode* pnode = m_pnodehead; pnode!= NULL; pnode = pnode->pnext) ar << pnode->data; } else WORD nnewcount; ar >> nnewcount; while (nnewcount--) CObject* newdata; ar >> newdata; AddTail(newData); } } void CStroke::Serialize(CArchive& ar) m_ptarray.serialize(ar); } void CDWordArray::Serialize(CArchive& ar) if (ar.isstoring()) ar << (WORD) m_nsize; for (int i = 0; i < m_nsize; i++) ar << m_pdata[i]; } else WORD noldsize; ar >> noldsize; for (int i = 0; i < m_nsize; i++) ar >> m_pdata[i]; } } void CRectangle::Serialize(CArchive& ar) if (ar.isstoring()) ar << m_rect; else ar >> m_rect; } void CCircle::Serialize(CArchive& ar) if (ar.isstoring()) 165
第 ㆒ 篇 勿 在 浮 砂 築 高 台 } ar << (WORD)m_center.x; ar << (WORD)m_center.y; ar << (WORD)m_radius; } else ar >> (WORD&)m_center.x; ar >> (WORD&)m_center.y; ar >> (WORD&)m_radius; } Serailize << >> archive archive 3-3 Serialize 3-4 CMyDoc::Serialize CObList::Serialize CStroke::Serialize CDWordArray::Serialize CRectangle::Serialize CCircle::Serialize 3-4 3-3 Serialize 166
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 DECLARE_SERIAL / IMPLEMENT_SERIAL << >> Serialize DECLARE_SERIAL IMPLEMENT _SERIAL #define DECLARE_SERIAL(class_name) \ DECLARE_DYNCREATE(class_name) \ friend CArchive& AFXAPI operator>>(carchive& ar, class_name* &pob); #define IMPLEMENT_SERIAL(class_name, base_class_name, wschema) \ CObject* PASCAL class_name::createobject() \ return new class_name; } \ _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wschema, \ class_name::createobject) \ CArchive& AFXAPI operator>>(carchive& ar, class_name* &pob) \ pob = (class_name*) ar.readobject(runtime_class(class_name)); \ return ar; } \ CRuntimeClass Load Store struct CRuntimeClass // Attributes LPCSTR m_lpszclassname; int m_nobjectsize; UINT m_wschema; // schema number of the loaded class CObject* (PASCAL* m_pfncreateobject)(); // NULL => abstract class CRuntimeClass* m_pbaseclass; CObject* CreateObject(); void Store(CArchive& ar) const; static CRuntimeClass* PASCAL Load(CArchive& ar, UINT* pwschemanum); }; // CRuntimeClass objects linked together in simple list static CRuntimeClass* pfirstclass; // start of class list CRuntimeClass* m_pnextclass; // linked list of registered classes 167
第 ㆒ 篇 勿 在 浮 砂 築 高 台 Load // Runtime class serialization code CRuntimeClass* PASCAL CRuntimeClass::Load(CArchive& ar, UINT* pwschemanum) WORD nlen; char szclassname[64]; CRuntimeClass* pclass; ar >> (WORD&)(*pwSchemaNum) >> nlen; if (nlen >= sizeof(szclassname) ar.read(szclassname, nlen)!= nlen) return NULL; szclassname[nlen] = '\0'; } for (pclass = pfirstclass; pclass!= NULL; pclass = pclass->m_pnextclass) if (lstrcmp(szclassname, pclass->m_lpszclassname) == 0) return pclass; } return NULL; // not found void CRuntimeClass::Store(CArchive& ar) const // stores a runtime class description WORD nlen = (WORD)lstrlenA(m_lpszClassName); ar << (WORD)m_wSchema << nlen; ar.write(m_lpszclassname, nlen*sizeof(char)); } 3-4 Serialization class CScribDoc : public CDocument DECLARE_DYNCREATE(CScribDoc)... }; class CStroke : public CObject DECLARE_SERIAL(CStroke) public: 168
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 void Serialize(CArchive&);... }; class CRectangle : public CObject DECLARE_SERIAL(CRectangle) public: void Serialize(CArchive&);... }; class CCircle : public CObject DECLARE_SERIAL(CCircle) public: void Serialize(CArchive&);... };.CPP IMPLEMENT_DYNCREATE(CScribDoc, CDocument) IMPLEMENT_SERIAL(CStroke, CObject, 2) IMPLEMENT_SERIAL(CRectangle, CObject, 1) IMPLEMENT_SERIAL(CCircle, CObject, 1) CStroke CRectangle CCircle Serialize MFC CObList CDWordArray // in header files class CDWordArray : public CObject DECLARE_SERIAL(CDWordArray) public: void Serialize(CArchive&);... }; class CObList : public CObject DECLARE_SERIAL(CObList) public: void Serialize(CArchive&);... }; // in implementation files 169
第 ㆒ 篇 勿 在 浮 砂 築 高 台 IMPLEMENT_SERIAL(CObList, CObject, 0) IMPLEMENT_SERIAL(CDWordArray, CObject, 0) CObject Serialize class CObject public: virtual void Serialize(CArchive& ar);... } DOS Serialization CFile CArchive CObList CDWordArray CRect CPoint Serialize... MFC Message Mapping Windows switch/case switch/case MFC CCmdTarget 170
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 CObject CObject CCmdTarget CCmdTarget CWinThread CWinThread CWnd CWnd CWinApp CWinApp CView CDocument CDocument CMyWinApp CMyWinApp CMyView CMyView CFrameWnd CFrameWnd CMyFrameWnd CMyFrameWnd CMyDoc CMyDoc MFC C++ application framework document/view document/view CObject CObject CCmdTarget CCmdTarget CWinThread CWinThread CWnd CWnd CWinApp CWinApp CView CDocument CDocument CMyWinApp CMyWinApp CMyView CMyView CFrameWnd CFrameWnd CMyFrameWnd CMyFrameWnd CMyDoc CMyDoc 171
第 ㆒ 篇 勿 在 浮 砂 築 高 台 Message Map Message Mapping RTTI Dynamic Creation DECLARE_DYNAMIC IMPLEMENT_DYNAMIC struct AFX_MSGMAP AFX_MSGMAP* pbasemessagemap; AFX_MSGMAP_ENTRY* lpentries; }; AFX_MSGMAP_ENTRY struct AFX_MSGMAP_ENTRY // MFC 4.0 format UINT nmessage; // windows message UINT ncode; // control code or WM_NOTIFY code UINT nid; // control ID (or 0 for windows messages) UINT nlastid; // used for entries specifying a range of control id's UINT nsig; // signature type (action) or pointer to message # AFX_PMSG pfn; // routine to call (or special value) }; AFX_PMSG typedef void (CCmdTarget::*AFX_PMSG)(void); #define DECLARE_MESSAGE_MAP() \ static AFX_MSGMAP_ENTRY _messageentries[]; \ static AFX_MSGMAP messagemap; \ virtual AFX_MSGMAP* GetMessageMap() const; 172
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 DECLARE_MESSAGE_MAP _messageentries[] nmessage, ncode, nid, nlastid, nsig, pfn pbasemessagemap lpentries messagemap #define BEGIN_MESSAGE_MAP(theClass, baseclass) \ AFX_MSGMAP* theclass::getmessagemap() const \ return &theclass::messagemap; } \ AFX_MSGMAP theclass::messagemap = \ &(baseclass::messagemap), \ (AFX_MSGMAP_ENTRY*) &(theclass::_messageentries) }; \ AFX_MSGMAP_ENTRY theclass::_messageentries[] = \ #define ON_COMMAND(id, memberfxn) \ WM_COMMAND, 0, (WORD)id, (WORD)id, AfxSig_vv, (AFX_PMSG)memberFxn }, #define END_MESSAGE_MAP() \ 0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } \ }; AfxSig_end enum AfxSig AfxSig_end = 0, AfxSig_vv, }; // [marks end of message map] AfxSig_xx memberfxn MFC p580 173
第 ㆒ 篇 勿 在 浮 砂 築 高 台 CView // in header file class CView : public CWnd public:... DECLARE_MESSAGE_MAP() }; // in implementation file #define CViewid 122... BEGIN_MESSAGE_MAP(CView, CWnd) ON_COMMAND(CViewid, 0) END_MESSAGE_MAP() // in header file class CView : public CWnd public:... static AFX_MSGMAP_ENTRY _messageentries[]; static AFX_MSGMAP messagemap; virtual AFX_MSGMAP* GetMessageMap() const; }; // in implementation file AFX_MSGMAP* CView::GetMessageMap() const return &CView::messageMap; } AFX_MSGMAP CView::messageMap = &(CWnd::messageMap), (AFX_MSGMAP_ENTRY*) &(CView::_messageEntries) }; AFX_MSGMAP_ENTRY CView::_messageEntries[] = WM_COMMAND, 0, (WORD)122, (WORD)122, 1, (AFX_PMSG)0 }, 0, 0, 0, 0, 0, (AFX_PMSG)0 } }; 174
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 CWnd::messageMap CView::_messageEntries[] WM_COMMAND, 0, 122, 122, 1, (AFX_PMSG)0 0, 0, 0, 0, 0, (AFX_PMSG)0 pbasemessagemap lpentries CView::messageMap ON_COMMAND MFC ON_WM _PAINT ON_WM_CREATE ON_WM_SIZE... Frame7 CCmdTarget // in header files class CObject... // CObject }; class CCmdTarget : public CObject... DECLARE_MESSAGE_MAP() }; class CWinThread : public CCmdTarget... // CWinThread }; class CWinApp : public CWinThread... DECLARE_MESSAGE_MAP() }; class CDocument : public CCmdTarget... DECLARE_MESSAGE_MAP() }; class CWnd : public CCmdTarget... DECLARE_MESSAGE_MAP() 175
第 ㆒ 篇 勿 在 浮 砂 築 高 台 }; class CFrameWnd : public CWnd... DECLARE_MESSAGE_MAP() }; class CView : public CWnd... DECLARE_MESSAGE_MAP() }; class CMyWinApp : public CWinApp... DECLARE_MESSAGE_MAP() }; class CMyFrameWnd : public CFrameWnd... DECLARE_MESSAGE_MAP() }; class CMyDoc : public CDocument... DECLARE_MESSAGE_MAP() }; class CMyView : public CView... DECLARE_MESSAGE_MAP() }; ON_COMMAND // in implementation files BEGIN_MESSAGE_MAP(CWnd, CCmdTarget) ON_COMMAND(CWndid, 0) END_MESSAGE_MAP() BEGIN_MESSAGE_MAP(CFrameWnd, CWnd) ON_COMMAND(CFrameWndid, 0) END_MESSAGE_MAP() BEGIN_MESSAGE_MAP(CDocument, CCmdTarget) 176
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 ON_COMMAND(CDocumentid, 0) END_MESSAGE_MAP() BEGIN_MESSAGE_MAP(CView, CWnd) ON_COMMAND(CViewid, 0) END_MESSAGE_MAP() BEGIN_MESSAGE_MAP(CWinApp, CCmdTarget) ON_COMMAND(CWinAppid, 0) END_MESSAGE_MAP() BEGIN_MESSAGE_MAP(CMyWinApp, CWinApp) ON_COMMAND(CMyWinAppid, 0) END_MESSAGE_MAP() BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd) ON_COMMAND(CMyFrameWndid, 0) END_MESSAGE_MAP() BEGIN_MESSAGE_MAP(CMyDoc, CDocument) ON_COMMAND(CMyDocid, 0) END_MESSAGE_MAP() BEGIN_MESSAGE_MAP(CMyView, CView) ON_COMMAND(CMyViewid, 0) END_MESSAGE_MAP() CCmdTarget AFX_MSGMAP CCmdTarget::messageMap = NULL, &CCmdTarget::_messageEntries[0] }; AFX_MSGMAP_ENTRY CCmdTarget::_messageEntries[] = 0, 0, CCmdTargetid, 0, AfxSig_end, 0 } }; 3-5 177
第 ㆒ 篇 勿 在 浮 砂 築 高 台 CWinThread CWinApp CMyWinApp,, 111,,,,, 1111,,, CCmdTarget,, 1,,, 0,0,0,0,0,0 0,0,0,0,0,0 0,0,0,0,0,0 CWnd CFrameWnd CMyFrameWnd,, 12,,, 0,0,0,0,0,0,, 121,,, 0,0,0,0,0,0,, 1211,,, 0,0,0,0,0,0 CView,, 122,,, 0,0,0,0,0,0 CMyView,, 1221,,, 0,0,0,0,0,0 m e s s a g e CDocument CMyDocument,, 13,,, 0,0,0,0,0,0,, 131,,, 0,0,0,0,0,0 3-5 Frame7 Message ON_COMMAND(Classid, 0) Classid MFC main CMyWinApp CMyFrameWnd CMyDoc CMyView CMyWinApp theapp; // theapp CMyWinApp void main() CWinApp* papp = AfxGetApp(); papp->initapplication(); papp->initinstance(); // CMyFrameWnd papp->run(); 178
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 } CMyDoc* pmydoc = new CMyDoc; // CMyDoc CMyView* pmyview = new CMyView; // CMyView CFrameWnd* pmyframe = (CFrameWnd*)pApp->m_pMainWnd;... void main()... AFX_MSGMAP* pmessagemap = pmyview->getmessagemap(); cout << endl << "CMyView Message Map : " << endl; MsgMapPrinting(pMessageMap); pmessagemap = pmydoc->getmessagemap(); cout << endl << "CMyDoc Message Map : " << endl; MsgMapPrinting(pMessageMap); pmessagemap = pmyframe->getmessagemap(); cout << endl << "CMyFrameWnd Message Map : " << endl; MsgMapPrinting(pMessageMap); } pmessagemap = papp->getmessagemap(); cout << endl << "CMyWinApp Message Map : " << endl; MsgMapPrinting(pMessageMap); classid void MsgMapPrinting(AFX_MSGMAP* pmessagemap) for(; pmessagemap!= NULL; pmessagemap = pmessagemap->pbasemessagemap) AFX_MSGMAP_ENTRY* lpentry = pmessagemap->lpentries; printlpentries(lpentry); } } void printlpentries(afx_msgmap_entry* lpentry) struct int classid; char* classname; } classinfo[] = CCmdTargetid, "CCmdTarget", CWinThreadid, "CWinThread", 179
第 ㆒ 篇 勿 在 浮 砂 築 高 台 }; CWinAppid, "CWinApp", CMyWinAppid, "CMyWinApp", CWndid, "CWnd", CFrameWndid, "CFrameWnd", CMyFrameWndid, "CMyFrameWnd", CViewid, "CView", CMyViewid, "CMyView", CDocumentid, "CDocument", CMyDocid, "CMyDoc", 0, " " for (int i=0; classinfo[i].classid!= 0; i++) if (classinfo[i].classid == lpentry->nid) cout << lpentry->nid << " "; cout << classinfo[i].classname << endl; break; } } } Frame7 cl my.cpp mfc.cpp <Enter> Frame7 CMyView Message Map : 1221 CMyView 122 CView 12 CWnd 1 CCmdTarget CMyDoc Message Map : 131 CMyDoc 13 CDocument 1 CCmdTarget CMyFrameWnd Message Map : 1211 CMyFrameWnd 121 CFrameWnd 12 CWnd 180
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 1 CCmdTarget CMyWinApp Message Map : 1111 CMyWinApp 111 CWinApp 1 CCmdTarget Frame7 MFC.H #0001 #define TRUE 1 #0002 #define FALSE 0 #0003 #0004 typedef char* LPSTR; #0005 typedef const char* LPCSTR; #0006 #0007 typedef unsigned long DWORD; #0008 typedef int BOOL; #0009 typedef unsigned char BYTE; #0010 typedef unsigned short WORD; #0011 typedef int INT; #0012 typedef unsigned int UINT; #0013 typedef long LONG; #0014 #0015 #define WM_COMMAND 0x0111 #0016 #define CObjectid 0xffff #0017 #define CCmdTargetid 1 #0018 #define CWinThreadid 11 #0019 #define CWinAppid 111 #0020 #define CMyWinAppid 1111 #0021 #define CWndid 12 #0022 #define CFrameWndid 121 #0023 #define CMyFrameWndid 1211 #0024 #define CViewid 122 #0025 #define CMyViewid 1221 #0026 #define CDocumentid 13 #0027 #define CMyDocid 131 #0028 #0029 #include <iostream.h> #0030 #0031 ///////////////////////////////////////////////////////////////// #0032 // Window message map handling #0033 181
第 ㆒ 篇 勿 在 浮 砂 築 高 台 #0034 struct AFX_MSGMAP_ENTRY; // declared below after CWnd #0035 #0036 struct AFX_MSGMAP #0037 #0038 AFX_MSGMAP* pbasemessagemap; #0039 AFX_MSGMAP_ENTRY* lpentries; #0040 }; #0041 #0042 #define DECLARE_MESSAGE_MAP() \ #0043 static AFX_MSGMAP_ENTRY _messageentries[]; \ #0044 static AFX_MSGMAP messagemap; \ #0045 virtual AFX_MSGMAP* GetMessageMap() const; #0046 #0047 #define BEGIN_MESSAGE_MAP(theClass, baseclass) \ #0048 AFX_MSGMAP* theclass::getmessagemap() const \ #0049 return &theclass::messagemap; } \ #0050 AFX_MSGMAP theclass::messagemap = \ #0051 &(baseclass::messagemap), \ #0052 (AFX_MSGMAP_ENTRY*) &(theclass::_messageentries) }; \ #0053 AFX_MSGMAP_ENTRY theclass::_messageentries[] = \ #0054 #0055 #0056 #define END_MESSAGE_MAP() \ #0057 0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } \ #0058 }; #0059 #0060 // Message map signature values and macros in separate header #0061 #include "afxmsg_.h" #0062 #0063 class CObject #0064 #0065 public: #0066 CObject::CObject() #0067 } #0068 CObject::~CObject() #0069 } #0070 }; #0071 #0072 class CCmdTarget : public CObject #0073 #0074 public: #0075 CCmdTarget::CCmdTarget() #0076 } #0077 CCmdTarget::~CCmdTarget() #0078 } #0079 DECLARE_MESSAGE_MAP() // base class - no }} macros 182
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 #0080 }; #0081 #0082 typedef void (CCmdTarget::*AFX_PMSG)(void); #0083 #0084 struct AFX_MSGMAP_ENTRY // MFC 4.0 #0085 #0086 UINT nmessage; // windows message #0087 UINT ncode; // control code or WM_NOTIFY code #0088 UINT nid; // control ID (or 0 for windows messages) #0089 UINT nlastid; // used for entries specifying a range of control id's #0090 UINT nsig; // signature type (action) or pointer to message # #0091 AFX_PMSG pfn; // routine to call (or special value) #0092 }; #0093 #0094 class CWinThread : public CCmdTarget #0095 #0096 public: #0097 CWinThread::CWinThread() #0098 } #0099 CWinThread::~CWinThread() #0100 } #0101 #0102 virtual BOOL InitInstance() #0103 cout << "CWinThread::InitInstance \n"; #0104 return TRUE; #0105 } #0106 virtual int Run() #0107 cout << "CWinThread::Run \n"; #0108 return 1; #0109 } #0110 }; #0111 #0112 class CWnd; #0113 #0114 class CWinApp : public CWinThread #0115 #0116 public: #0117 CWinApp* m_pcurrentwinapp; #0118 CWnd* m_pmainwnd; #0119 #0120 public: #0121 CWinApp::CWinApp() #0122 m_pcurrentwinapp = this; #0123 } #0124 CWinApp::~CWinApp() #0125 } 183
第 ㆒ 篇 勿 在 浮 砂 築 高 台 #0126 #0127 virtual BOOL InitApplication() #0128 cout << "CWinApp::InitApplication \n"; #0129 return TRUE; #0130 } #0131 virtual BOOL InitInstance() #0132 cout << "CWinApp::InitInstance \n"; #0133 return TRUE; #0134 } #0135 virtual int Run() #0136 cout << "CWinApp::Run \n"; #0137 return CWinThread::Run(); #0138 } #0139 #0140 DECLARE_MESSAGE_MAP() #0141 }; #0142 #0143 typedef void (CWnd::*AFX_PMSGW)(void); #0144 // like 'AFX_PMSG' but for CWnd derived classes only #0145 #0146 class CDocument : public CCmdTarget #0147 #0148 public: #0149 CDocument::CDocument() #0150 } #0151 CDocument::~CDocument() #0152 } #0153 DECLARE_MESSAGE_MAP() #0154 }; #0155 #0156 class CWnd : public CCmdTarget #0157 #0158 public: #0159 CWnd::CWnd() #0160 } #0161 CWnd::~CWnd() #0162 } #0163 #0164 virtual BOOL Create(); #0165 BOOL CreateEx(); #0166 virtual BOOL PreCreateWindow(); #0167 #0168 DECLARE_MESSAGE_MAP() #0169 }; #0170 #0171 class CFrameWnd : public CWnd 184
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 #0172 #0173 public: #0174 CFrameWnd::CFrameWnd() #0175 } #0176 CFrameWnd::~CFrameWnd() #0177 } #0178 BOOL Create(); #0179 virtual BOOL PreCreateWindow(); #0180 #0181 DECLARE_MESSAGE_MAP() #0182 }; #0183 #0184 class CView : public CWnd #0185 #0186 public: #0187 CView::CView() #0188 } #0189 CView::~CView() #0190 } #0191 DECLARE_MESSAGE_MAP() #0192 }; #0193 #0194 // global function #0195 CWinApp* AfxGetApp(); AFXMSG_.H #0001 enum AfxSig #0002 #0003 AfxSig_end = 0, // [marks end of message map] #0004 AfxSig_vv, #0005 }; #0006 #0007 #define ON_COMMAND(id, memberfxn) \ #0008 WM_COMMAND, 0, (WORD)id, (WORD)id, AfxSig_vv, (AFX_PMSG)memberFxn }, MFC.CPP #0001 #include "my.h" // #0002 #0003 extern CMyWinApp theapp; #0004 #0005 BOOL CWnd::Create() #0006 #0007 cout << "CWnd::Create \n"; 185
第 ㆒ 篇 勿 在 浮 砂 築 高 台 #0008 return TRUE; #0009 } #0010 #0011 BOOL CWnd::CreateEx() #0012 #0013 cout << "CWnd::CreateEx \n"; #0014 PreCreateWindow(); #0015 return TRUE; #0016 } #0017 #0018 BOOL CWnd::PreCreateWindow() #0019 #0020 cout << "CWnd::PreCreateWindow \n"; #0021 return TRUE; #0022 } #0023 #0024 BOOL CFrameWnd::Create() #0025 #0026 cout << "CFrameWnd::Create \n"; #0027 CreateEx(); #0028 return TRUE; #0029 } #0030 #0031 BOOL CFrameWnd::PreCreateWindow() #0032 #0033 cout << "CFrameWnd::PreCreateWindow \n"; #0034 return TRUE; #0035 } #0036 #0037 CWinApp* AfxGetApp() #0038 #0039 return theapp.m_pcurrentwinapp; #0040 } #0041 #0042 AFX_MSGMAP* CCmdTarget::GetMessageMap() const #0043 #0044 return &CCmdTarget::messageMap; #0045 } #0046 #0047 AFX_MSGMAP CCmdTarget::messageMap = #0048 #0049 NULL, #0050 &CCmdTarget::_messageEntries[0] #0051 }; #0052 #0053 AFX_MSGMAP_ENTRY CCmdTarget::_messageEntries[] = 186
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 #0054 #0055 // 0, 0, 0, 0, AfxSig_end, 0 } // nothing here #0056 0, 0, CCmdTargetid, 0, AfxSig_end, 0 } #0057 #0058 }; #0059 #0060 BEGIN_MESSAGE_MAP(CWnd, CCmdTarget) #0061 ON_COMMAND(CWndid, 0) #0062 END_MESSAGE_MAP() #0063 #0064 BEGIN_MESSAGE_MAP(CFrameWnd, CWnd) #0065 ON_COMMAND(CFrameWndid, 0) #0066 END_MESSAGE_MAP() #0067 #0068 BEGIN_MESSAGE_MAP(CDocument, CCmdTarget) #0069 ON_COMMAND(CDocumentid, 0) #0070 END_MESSAGE_MAP() #0071 #0072 BEGIN_MESSAGE_MAP(CView, CWnd) #0073 ON_COMMAND(CViewid, 0) #0074 END_MESSAGE_MAP() #0075 #0076 BEGIN_MESSAGE_MAP(CWinApp, CCmdTarget) #0077 ON_COMMAND(CWinAppid, 0) #0078 END_MESSAGE_MAP() MY.H #0001 #include <iostream.h> #0002 #include "mfc.h" #0003 #0004 class CMyWinApp : public CWinApp #0005 #0006 public: #0007 CMyWinApp::CMyWinApp() #0008 } #0009 CMyWinApp::~CMyWinApp() #0010 } #0011 #0012 virtual BOOL InitInstance(); #0013 DECLARE_MESSAGE_MAP() #0014 }; #0015 #0016 class CMyFrameWnd : public CFrameWnd #0017 #0018 public: 187
第 ㆒ 篇 勿 在 浮 砂 築 高 台 #0019 CMyFrameWnd(); #0020 ~CMyFrameWnd() #0021 } #0022 DECLARE_MESSAGE_MAP() #0023 }; #0024 #0025 class CMyDoc : public CDocument #0026 #0027 public: #0028 CMyDoc::CMyDoc() #0029 } #0030 CMyDoc::~CMyDoc() #0031 } #0032 DECLARE_MESSAGE_MAP() #0033 }; #0034 #0035 class CMyView : public CView #0036 #0037 public: #0038 CMyView::CMyView() #0039 } #0040 CMyView::~CMyView() #0041 } #0042 DECLARE_MESSAGE_MAP() #0043 }; MY.CPP #0001 #include "my.h" #0002 #0003 CMyWinApp theapp; #0004 #0005 BOOL CMyWinApp::InitInstance() #0006 #0007 cout << "CMyWinApp::InitInstance \n"; #0008 m_pmainwnd = new CMyFrameWnd; #0009 return TRUE; #0010 } #0011 #0012 CMyFrameWnd::CMyFrameWnd() #0013 #0014 Create(); #0015 } #0016 #0017 BEGIN_MESSAGE_MAP(CMyWinApp, CWinApp) #0018 ON_COMMAND(CMyWinAppid, 0) 188
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 #0019 END_MESSAGE_MAP() #0020 #0021 BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd) #0022 ON_COMMAND(CMyFrameWndid, 0) #0023 END_MESSAGE_MAP() #0024 #0025 BEGIN_MESSAGE_MAP(CMyDoc, CDocument) #0026 ON_COMMAND(CMyDocid, 0) #0027 END_MESSAGE_MAP() #0028 #0029 BEGIN_MESSAGE_MAP(CMyView, CView) #0030 ON_COMMAND(CMyViewid, 0) #0031 END_MESSAGE_MAP() #0032 #0033 void printlpentries(afx_msgmap_entry* lpentry) #0034 #0035 struct #0036 int classid; #0037 char* classname; #0038 } classinfo[] = #0039 CCmdTargetid, "CCmdTarget", #0040 CWinThreadid, "CWinThread", #0041 CWinAppid, "CWinApp", #0042 CMyWinAppid, "CMyWinApp", #0043 CWndid, "CWnd", #0044 CFrameWndid, "CFrameWnd", #0045 CMyFrameWndid, "CMyFrameWnd", #0046 CViewid, "CView", #0047 CMyViewid, "CMyView", #0048 CDocumentid, "CDocument", #0049 CMyDocid, "CMyDoc", #0050 0, " " #0051 }; #0052 #0053 for (int i=0; classinfo[i].classid!= 0; i++) #0054 #0055 if (classinfo[i].classid == lpentry->nid) #0056 #0057 cout << lpentry->nid << " "; #0058 cout << classinfo[i].classname << endl; #0059 break; #0060 } #0061 } #0062 } #0063 #0064 void MsgMapPrinting(AFX_MSGMAP* pmessagemap) 189
第 ㆒ 篇 勿 在 浮 砂 築 高 台 #0065 #0066 for(; pmessagemap!= NULL; pmessagemap = pmessagemap->pbasemessagemap) #0067 AFX_MSGMAP_ENTRY* lpentry = pmessagemap->lpentries; #0068 printlpentries(lpentry); #0069 } #0070 } #0071 #0072 //--------------------------------------------------------------- #0073 // main #0074 //--------------------------------------------------------------- #0075 void main() #0076 #0077 #0078 CWinApp* papp = AfxGetApp(); #0079 #0080 papp->initapplication(); #0081 papp->initinstance(); #0082 papp->run(); #0083 #0084 CMyDoc* pmydoc = new CMyDoc; #0085 CMyView* pmyview = new CMyView; #0086 CFrameWnd* pmyframe = (CFrameWnd*)pApp->m_pMainWnd; #0087 #0088 // output Message Map construction #0089 AFX_MSGMAP* pmessagemap = pmyview->getmessagemap(); #0090 cout << endl << "CMyView Message Map : " << endl; #0091 MsgMapPrinting(pMessageMap); #0092 #0093 pmessagemap = pmydoc->getmessagemap(); #0094 cout << endl << "CMyDoc Message Map : " << endl; #0095 MsgMapPrinting(pMessageMap); #0096 #0097 pmessagemap = pmyframe->getmessagemap(); #0098 cout << endl << "CMyFrameWnd Message Map : " << endl; #0099 MsgMapPrinting(pMessageMap); #0100 #0101 pmessagemap = papp->getmessagemap(); #0102 cout << endl << "CMyWinApp Message Map : " << endl; #0103 MsgMapPrinting(pMessageMap); #0104 } 190
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 Command Routing Windows -- Message Map MFC C++ application framework document/view MFC Windows WM_xxx WM_COMMAND Frame 1. View 2. Frame 3. CWinApp View 1. View 本 身 2. Document Document 1. Document 本 身 2. Document Template Document Template 3-6 MFC WM_COMMAND 191
第 ㆒ 篇 勿 在 浮 砂 築 高 台 MFC MFC call stack 注 意 none AfxWndProc global none AfxCallWndProc global CCmdTarget OnCmdMsg virtual CDocument OnCmdMsg virtual CWnd WindowProc virtual OnCommand DefWindowProc virtual virtual CFrameWnd OnCommand virtual OnCmdMsg virtual CView OnCmdMsg virtual AfxWndProc CWinThread::Run main MFC AfxWndProc(0, WM_CREATE, 0, 0, pmyframe); pmyframe WM_CREATE AfxWndProc(0, WM_COMMAND, 0, 0, pmyview); pmyview WM_COMMAND 192
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 LRESULT AfxWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam, CWnd *pwnd) // last param. pwnd is added by JJHou. cout << "AfxWndProc()" << endl; return AfxCallWndProc(pWnd, hwnd, nmsg, wparam, lparam); } LRESULT AfxCallWndProc(CWnd* pwnd, HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam) cout << "AfxCallWndProc()" << endl; LRESULT lresult = pwnd->windowproc(nmsg, wparam, lparam); return lresult; } pwnd->windowproc pwnd -- WindowProc pwnd CMyFrameWnd CFrameWnd ::WindowProc CFrameWnd WindowProc CWnd::WindowProc pwnd CMyView CView ::WindowProc CView WindowProc CWnd::WindowProc CWnd::WindowProc WM _COMMAND AFX_MSGMAP_ENTRY AFX_MSGMAP_ENTRY Frame7 193
第 ㆒ 篇 勿 在 浮 砂 築 高 台 LRESULT CWnd::WindowProc(UINT nmsg, WPARAM wparam, LPARAM lparam) AFX_MSGMAP* pmessagemap; AFX_MSGMAP_ENTRY* lpentry; if (nmsg == WM_COMMAND) // special case for commands if (OnCommand(wParam, lparam)) ➊ return 1L; // command handled else return (LRESULT)DefWindowProc(nMsg, wparam, lparam); ➒ } pmessagemap = GetMessageMap(); } for (; pmessagemap!= NULL; pmessagemap = pmessagemap->pbasemessagemap) lpentry = pmessagemap->lpentries; printlpentries(lpentry); } return 0; // J.J.Hou: if find, should call lpentry->pfn, // otherwise should call DefWindowProc. // for simplification, we just return 0. WM _COMMAND CWnd::WindowProc OnCommand CWnd 1. this CMyFrameWnd CFrameWnd ::OnCommand 2. this CMyView CView ::OnCommand CView OnCommand CWnd::OnCommand ➊ 194
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 BOOL CFrameWnd::OnCommand(WPARAM wparam, LPARAM lparam) cout << "CFrameWnd::OnCommand()" << endl; //... // route as normal command return CWnd::OnCommand(wParam, lparam); ➋ } BOOL CWnd::OnCommand(WPARAM wparam, LPARAM lparam) cout << "CWnd::OnCommand()" << endl; //... return OnCmdMsg(0, 0); ➌ } CCmdTarget ➌ OnCmdMsg 1. this CMyFrameWnd CFrameWnd ::OnCmdMsg 2. this CMyView CView ::OnCmdMsg 3. this CMyDoc CDocument::OnCmdMsg 4. this CMyWinApp CWinApp::OnCmdMsg CWinApp OnCmdMsg CCmdTarget ::OnCmdMsg CFrameWnd::OnCmdMsg BOOL CFrameWnd::OnCmdMsg(UINT nid, int ncode) cout << "CFrameWnd::OnCmdMsg()" << endl; // pump through current view FIRST CView* pview = GetActiveView(); if (pview->oncmdmsg(nid, ncode)) ➍ return TRUE; // then pump through frame if (CWnd::OnCmdMsg(nID, ncode)) ➐ return TRUE; // last but not least, pump through app CWinApp* papp = AfxGetApp(); 195
第 ㆒ 篇 勿 在 浮 砂 築 高 台 if (papp->oncmdmsg(nid, ncode)) ➑ return TRUE; } return FALSE; 3-6 Frame WM _COMMAND ➍ pview->oncmdmsg BOOL CView::OnCmdMsg(UINT nid, int ncode) cout << "CView::OnCmdMsg()" << endl; if (CWnd::OnCmdMsg(nID, ncode)) ➎ return TRUE; } BOOL bhandled = FALSE; bhandled = m_pdocument->oncmdmsg(nid, ncode); ➏ return bhandled; 3-6 View _COMMAND WM ➎ CCmdTarget::OnCmdMsg: CWnd::OnCmdMsg CWnd OnCmdMsg BOOL CCmdTarget::OnCmdMsg(UINT nid, int ncode) cout << "CCmdTarget::OnCmdMsg()" << endl; // Now look through message map to see if it applies to us AFX_MSGMAP* pmessagemap; AFX_MSGMAP_ENTRY* lpentry; for (pmessagemap = GetMessageMap(); pmessagemap!= NULL; pmessagemap = pmessagemap->pbasemessagemap) lpentry = pmessagemap->lpentries; printlpentries(lpentry); } } return FALSE; // not handled 196
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 GetMessageMap DECLARE_MESSAGE_MAP pmyview pmyframe received a WM_COMMAND, routing path and call stack: AfxWndProc() AfxCallWndProc() CWnd::WindowProc() CFrameWnd::OnCommand() CWnd::OnCommand() CFrameWnd::OnCmdMsg() CFrameWnd::GetActiveView() CView::OnCmdMsg() CCmdTarget::OnCmdMsg() 1221 CMyView 122 CView 12 CWnd 1 CCmdTarget C ➏CDocument::OnCmdMsg: BOOL CDocument::OnCmdMsg(UINT nid, int ncode) cout << "CDocument::OnCmdMsg()" << endl; if (CCmdTarget::OnCmdMsg(nID, ncode)) return TRUE; } return FALSE; CDocument::OnCmdMsg() CCmdTarget::OnCmdMsg() 131 CMyDoc 13 CDocument 1 CCmdTarget 197
第 ㆒ 篇 勿 在 浮 砂 築 高 台 CCmdTarget::OnCmdMsg() 1211 CMyFrameWnd 121 CFrameWnd 12 CWnd 1 CCmdTarget ➐ CFrameWnd::OnCmdMsg CWnd::OnCmdMsg CCmdTarget::OnCmdMsg CFrameWnd::OnCmdMsg CWinApp::OnCmdMsg 1111 CMyWinApp 111 CWinApp 1 CCmdTarget ➑ CCmdTarget::OnCmdMsg ➒ CWnd::WindowProc CWnd::DefWindowProc MFC Windows ::DefWindowProc API Frame8 3-7 call 3-8 stack 198
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 AfxWndProc AfxCallWndProc CWnd::WindowProc WM_COMMAND general Windows message (WM_xxx) CFrameWnd::OnCommand CWnd::OnCommand CFrameWnd::OnCmdMsg CObject CObject CCmdTarget CCmdTarget CWinThread CWinThread CWnd CWnd CWinApp CWinApp CView CView CDocument CDocument CMyWinApp CMyWinApp CMyView CMyView CFrameWnd CFrameWnd CMyFrameWnd CMyFrameWnd CMyDoc CMyDoc ➍ ➊ ➌ ➋ AFX_MSGMAP* pmessagemap = GetMessageMap(); for(; for(; pmessagemap!=!= NULL;...)...... }} or or or CView::OnCmdMsg CWnd::OnCmdMsg ---> CCmdTarget::OnCmdMsg CWinApp::OnCmdMsg ---> CCmdTarget::OnCmdMsg CView::OnCmdMsg CWnd::OnCmdMsg ---> CCmdTarget::OnCmdMsg CDocument::OnCmdMsg CDocument::OnCmdMsg CCmdTarget::OnCmdMsg ---> CCmdTarget::OnCmdMsg CCmdTarget::OnCmdMsg(...) // // walking the the message map. AFX_MSGMAP* pmessagemap = GetMessageMap(); for(; for(; pmessagemap!=!= NULL;...)...}} ➊ ➌ ➍ ➋ 3-7 CMyFrameWnd WM_COMMAND Frame8 199
第 ㆒ 篇 勿 在 浮 砂 築 高 台 CObject CObject CCmdTarget CCmdTarget CWinThread CWinThread CWnd CWnd CWinApp CWinApp CView CView CDocument CDocument CMyWinApp CMyWinApp CMyView CMyView CFrameWnd CFrameWnd CMyFrameWnd CMyFrameWnd CMyDoc CMyDoc ➊ CObject CObject CCmdTarget CCmdTarget CWinThread CWinThread CWnd CWnd CWinApp CWinApp CView CView CDocument CDocument CMyWinApp CMyWinApp CMyView CMyView CFrameWnd CFrameWnd CMyFrameWnd CMyFrameWnd CMyDoc CMyDoc ➋ CObject CObject CCmdTarget CCmdTarget CWinThread CWinThread CWnd CWnd CWinApp CWinApp CView CView CDocument CDocument CMyWinApp CMyWinApp CMyView CMyView CFrameWnd CFrameWnd CMyFrameWnd CMyFrameWnd CMyDoc CMyDoc ➌ CObject CObject CCmdTarget CCmdTarget CWinThread CWinThread CWnd CWnd CWinApp CWinApp CView CView CDocument CDocument CMyWinApp CMyWinApp CMyView CMyView CFrameWnd CFrameWnd CMyFrameWnd CMyFrameWnd CMyDoc CMyDoc ➍ 3-8 CMyFrameWnd WM_COMMAND 200
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 Frame8 frame view Windows WM _COMMAND // test Message Routing AfxWndProc(0, WM_CREATE, 0, 0, pmyframe); AfxWndProc(0, WM_PAINT, 0, 0, pmyview); AfxWndProc(0, WM_COMMAND, 0, 0, pmyview); AfxWndProc(0, WM_COMMAND, 0, 0, pmyframe); Frame8 cl my.cpp mfc.cpp <Enter> Frame8 CWinApp::InitApplication CMyWinApp::InitInstance CFrameWnd::Create CWnd::CreateEx CFrameWnd::PreCreateWindow CWinApp::Run CWinThread::Run pmyframe received a WM_CREATE, routing path and call stack: AfxWndProc() AfxCallWndProc() CWnd::WindowProc() 1211 CMyFrameWnd 121 CFrameWnd 12 CWnd 1 CCmdTarget pmyview received a WM_PAINT, routing path and call stack: AfxWndProc() AfxCallWndProc() CWnd::WindowProc() 1221 CMyView 122 CView 12 CWnd 1 CCmdTarget pmyview received a WM_COMMAND, routing path and call stack: AfxWndProc() 201
第 ㆒ 篇 勿 在 浮 砂 築 高 台 AfxCallWndProc() CWnd::WindowProc() CWnd::OnCommand() CView::OnCmdMsg() CCmdTarget::OnCmdMsg() 1221 CMyView 122 CView 12 CWnd 1 CCmdTarget CDocument::OnCmdMsg() CCmdTarget::OnCmdMsg() 131 CMyDoc 13 CDocument 1 CCmdTarget CWnd::DefWindowProc() pmyframe received a WM_COMMAND, routing path and call stack: AfxWndProc() AfxCallWndProc() CWnd::WindowProc() CFrameWnd::OnCommand() CWnd::OnCommand() CFrameWnd::OnCmdMsg() CFrameWnd::GetActiveView() CView::OnCmdMsg() CCmdTarget::OnCmdMsg() 1221 CMyView 122 CView 12 CWnd 1 CCmdTarget CDocument::OnCmdMsg() CCmdTarget::OnCmdMsg() 131 CMyDoc 13 CDocument 1 CCmdTarget CCmdTarget::OnCmdMsg() 1211 CMyFrameWnd 121 CFrameWnd 12 CWnd 1 CCmdTarget CCmdTarget::OnCmdMsg() 1111 CMyWinApp 111 CWinApp 1 CCmdTarget CWnd::DefWindowProc() 202
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 Frame8 MFC.H #0001 #define TRUE 1 #0002 #define FALSE 0 #0003 #0004 typedef char* LPSTR; #0005 typedef const char* LPCSTR; #0006 #0007 typedef unsigned long DWORD; #0008 typedef int BOOL; #0009 typedef unsigned char BYTE; #0010 typedef unsigned short WORD; #0011 typedef int INT; #0012 typedef unsigned int UINT; #0013 typedef long LONG; #0014 #0015 typedef UINT WPARAM; #0016 typedef LONG LPARAM; #0017 typedef LONG LRESULT; #0018 typedef int HWND; #0019 #0020 #define WM_COMMAND 0x0111 #0021 #define WM_CREATE 0x0001 #0022 #define WM_PAINT 0x000F #0023 #define WM_NOTIFY 0x004E #0024 #0025 #define CObjectid 0xffff #0026 #define CCmdTargetid 1 #0027 #define CWinThreadid 11 #0028 #define CWinAppid 111 #0029 #define CMyWinAppid 1111 #0030 #define CWndid 12 #0031 #define CFrameWndid 121 #0032 #define CMyFrameWndid 1211 #0033 #define CViewid 122 #0034 #define CMyViewid 1221 #0035 #define CDocumentid 13 #0036 #define CMyDocid 131 #0037 #0038 #include <iostream.h> #0039 #0040 ///////////////////////////////////////////////////////////////// 203
第 ㆒ 篇 勿 在 浮 砂 築 高 台 #0041 // Window message map handling #0042 #0043 struct AFX_MSGMAP_ENTRY; // declared below after CWnd #0044 #0045 struct AFX_MSGMAP #0046 #0047 AFX_MSGMAP* pbasemessagemap; #0048 AFX_MSGMAP_ENTRY* lpentries; #0049 }; #0050 #0051 #define DECLARE_MESSAGE_MAP() \ #0052 static AFX_MSGMAP_ENTRY _messageentries[]; \ #0053 static AFX_MSGMAP messagemap; \ #0054 virtual AFX_MSGMAP* GetMessageMap() const; #0055 #0056 #define BEGIN_MESSAGE_MAP(theClass, baseclass) \ #0057 AFX_MSGMAP* theclass::getmessagemap() const \ #0058 return &theclass::messagemap; } \ #0059 AFX_MSGMAP theclass::messagemap = \ #0060 &(baseclass::messagemap), \ #0061 (AFX_MSGMAP_ENTRY*) &(theclass::_messageentries) }; \ #0062 AFX_MSGMAP_ENTRY theclass::_messageentries[] = \ #0063 #0064 #0065 #define END_MESSAGE_MAP() \ #0066 0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } \ #0067 }; #0068 #0069 // Message map signature values and macros in separate header #0070 #include "afxmsg_.h" #0071 #0072 class CObject #0073 #0074 public: #0075 CObject::CObject() #0076 } #0077 CObject::~CObject() #0078 } #0079 }; #0080 #0081 class CCmdTarget : public CObject #0082 #0083 public: #0084 CCmdTarget::CCmdTarget() #0085 } #0086 CCmdTarget::~CCmdTarget() 204
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 #0087 } #0088 #0089 virtual BOOL OnCmdMsg(UINT nid, int ncode); #0090 #0091 DECLARE_MESSAGE_MAP() // base class - no }} macros #0092 }; #0093 #0094 typedef void (CCmdTarget::*AFX_PMSG)(void); #0095 #0096 struct AFX_MSGMAP_ENTRY // MFC 4.0 #0097 #0098 UINT nmessage; // windows message #0099 UINT ncode; // control code or WM_NOTIFY code #0100 UINT nid; // control ID (or 0 for windows messages) #0101 UINT nlastid; // used for entries specifying a range of control id's #0102 UINT nsig; // signature type (action) or pointer to message # #0103 AFX_PMSG pfn; // routine to call (or special value) #0104 }; #0105 #0106 class CWinThread : public CCmdTarget #0107 #0108 public: #0109 CWinThread::CWinThread() #0110 } #0111 CWinThread::~CWinThread() #0112 } #0113 #0114 virtual BOOL InitInstance() #0115 cout << "CWinThread::InitInstance \n"; #0116 return TRUE; #0117 } #0118 virtual int Run() #0119 cout << "CWinThread::Run \n"; #0120 // AfxWndProc(...); #0121 return 1; #0122 } #0123 }; #0124 #0125 class CWnd; #0126 #0127 class CWinApp : public CWinThread #0128 #0129 public: #0130 CWinApp* m_pcurrentwinapp; #0131 CWnd* m_pmainwnd; #0132 205
第 ㆒ 篇 勿 在 浮 砂 築 高 台 #0133 public: #0134 CWinApp::CWinApp() #0135 m_pcurrentwinapp = this; #0136 } #0137 CWinApp::~CWinApp() #0138 } #0139 #0140 virtual BOOL InitApplication() #0141 cout << "CWinApp::InitApplication \n"; #0142 return TRUE; #0143 } #0144 virtual BOOL InitInstance() #0145 cout << "CWinApp::InitInstance \n"; #0146 return TRUE; #0147 } #0148 virtual int Run() #0149 cout << "CWinApp::Run \n"; #0150 return CWinThread::Run(); #0151 } #0152 #0153 DECLARE_MESSAGE_MAP() #0154 }; #0155 #0156 typedef void (CWnd::*AFX_PMSGW)(void); #0157 // like 'AFX_PMSG' but for CWnd derived classes only #0158 #0159 class CDocument : public CCmdTarget #0160 #0161 public: #0162 CDocument::CDocument() #0163 } #0164 CDocument::~CDocument() #0165 } #0166 #0167 virtual BOOL OnCmdMsg(UINT nid, int ncode); #0168 #0169 DECLARE_MESSAGE_MAP() #0170 }; #0171 #0172 class CWnd : public CCmdTarget #0173 #0174 public: #0175 CWnd::CWnd() #0176 } #0177 CWnd::~CWnd() #0178 } 206
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 #0179 #0180 virtual BOOL Create(); #0181 BOOL CreateEx(); #0182 virtual BOOL PreCreateWindow(); #0183 virtual LRESULT WindowProc(UINT nmsg, WPARAM wparam, LPARAM lparam); #0184 virtual LRESULT DefWindowProc(UINT message, WPARAM wparam, LPARAM lparam); #0185 virtual BOOL OnCommand(WPARAM wparam, LPARAM lparam); #0186 #0187 DECLARE_MESSAGE_MAP() #0188 }; #0189 #0190 class CView; #0191 #0192 class CFrameWnd : public CWnd #0193 #0194 public: #0195 CView* m_pviewactive; // current active view #0196 #0197 public: #0198 CFrameWnd::CFrameWnd() #0199 } #0200 CFrameWnd::~CFrameWnd() #0201 } #0202 BOOL Create(); #0203 CView* GetActiveView() const; #0204 virtual BOOL PreCreateWindow(); #0205 virtual BOOL OnCommand(WPARAM wparam, LPARAM lparam); #0206 virtual BOOL OnCmdMsg(UINT nid, int ncode); #0207 #0208 DECLARE_MESSAGE_MAP() #0209 #0210 friend CView; #0211 }; #0212 #0213 class CView : public CWnd #0214 #0215 public: #0216 CDocument* m_pdocument; #0217 #0218 public: #0219 CView::CView() #0220 } #0221 CView::~CView() #0222 } #0223 #0224 virtual BOOL OnCmdMsg(UINT nid, int ncode); 207
第 ㆒ 篇 勿 在 浮 砂 築 高 台 #0225 #0226 DECLARE_MESSAGE_MAP() #0227 #0228 friend CFrameWnd; #0229 }; #0230 #0231 // global function #0232 CWinApp* AfxGetApp(); #0233 LRESULT AfxWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam, #0234 CWnd* pwnd); // last param. pwnd is added by JJHOU. #0235 LRESULT AfxCallWndProc(CWnd* pwnd, HWND hwnd, UINT nmsg, WPARAM wparam, #0236 LPARAM lparam); AFXMSG_.H #0001 enum AfxSig #0002 #0003 AfxSig_end = 0, // [marks end of message map] #0004 AfxSig_vv, #0005 }; #0006 #0007 #define ON_COMMAND(id, memberfxn) \ #0008 WM_COMMAND, 0, (WORD)id, (WORD)id, AfxSig_vv, (AFX_PMSG)memberFxn }, MFC.CPP #0001 #include "my.h" // mfc.h extern CMyWinApp... #0002 #0003 extern CMyWinApp theapp; #0004 extern void printlpentries(afx_msgmap_entry* lpentry); #0005 #0006 BOOL CCmdTarget::OnCmdMsg(UINT nid, int ncode) #0007 #0008 // Now look through message map to see if it applies to us #0009 AFX_MSGMAP* pmessagemap; #0010 AFX_MSGMAP_ENTRY* lpentry; #0011 for (pmessagemap = GetMessageMap(); pmessagemap!= NULL; #0012 pmessagemap = pmessagemap->pbasemessagemap) #0013 #0014 lpentry = pmessagemap->lpentries; #0015 printlpentries(lpentry); #0016 } #0017 #0018 return FALSE; // not handled #0019 } 208
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 #0020 #0021 BOOL CWnd::Create() #0022 #0023 cout << "CWnd::Create \n"; #0024 return TRUE; #0025 } #0026 #0027 BOOL CWnd::CreateEx() #0028 #0029 cout << "CWnd::CreateEx \n"; #0030 PreCreateWindow(); #0031 return TRUE; #0032 } #0033 #0034 BOOL CWnd::PreCreateWindow() #0035 #0036 cout << "CWnd::PreCreateWindow \n"; #0037 return TRUE; #0038 } #0039 #0040 LRESULT CWnd::WindowProc(UINT nmsg, WPARAM wparam, LPARAM lparam) #0041 #0042 AFX_MSGMAP* pmessagemap; #0043 AFX_MSGMAP_ENTRY* lpentry; #0044 #0045 if (nmsg == WM_COMMAND) // special case for commands #0046 #0047 if (OnCommand(wParam, lparam)) #0048 return 1L; // command handled #0049 else #0050 return (LRESULT)DefWindowProc(nMsg, wparam, lparam); #0051 } #0052 #0053 pmessagemap = GetMessageMap(); #0054 #0055 for (; pmessagemap!= NULL; #0056 pmessagemap = pmessagemap->pbasemessagemap) #0057 #0058 lpentry = pmessagemap->lpentries; #0059 printlpentries(lpentry); #0060 } #0061 return 0; // add by JJHou. if find, should call lpentry->pfn, #0062 // otherwise should call DefWindowProc. #0063 } #0064 #0065 LRESULT CWnd::DefWindowProc(UINT message, WPARAM wparam, LPARAM lparam) 209
第 ㆒ 篇 勿 在 浮 砂 築 高 台 #0066 #0067 return TRUE; #0068 } #0069 #0070 BOOL CWnd::OnCommand(WPARAM wparam, LPARAM lparam) #0071 #0072 //... #0073 return OnCmdMsg(0, 0); #0074 } #0075 #0076 BOOL CFrameWnd::OnCommand(WPARAM wparam, LPARAM lparam) #0077 #0078 //... #0079 // route as normal command #0080 return CWnd::OnCommand(wParam, lparam); #0081 } #0082 #0083 BOOL CFrameWnd::Create() #0084 #0085 cout << "CFrameWnd::Create \n"; #0086 CreateEx(); #0087 return TRUE; #0088 } #0089 #0090 BOOL CFrameWnd::PreCreateWindow() #0091 #0092 cout << "CFrameWnd::PreCreateWindow \n"; #0093 return TRUE; #0094 } #0095 #0096 CView* CFrameWnd::GetActiveView() const #0097 #0098 return m_pviewactive; #0099 } #0100 #0101 BOOL CFrameWnd::OnCmdMsg(UINT nid, int ncode) #0102 #0103 // pump through current view FIRST #0104 CView* pview = GetActiveView(); #0105 if (pview->oncmdmsg(nid, ncode)) #0106 return TRUE; #0107 #0108 // then pump through frame #0109 if (CWnd::OnCmdMsg(nID, ncode)) #0110 return TRUE; #0111 210
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 #0112 // last but not least, pump through app #0113 CWinApp* papp = AfxGetApp(); #0114 if (papp->oncmdmsg(nid, ncode)) #0115 return TRUE; #0116 #0117 return FALSE; #0118 } #0119 #0120 BOOL CDocument::OnCmdMsg(UINT nid, int ncode) #0121 #0122 if (CCmdTarget::OnCmdMsg(nID, ncode)) #0123 return TRUE; #0124 #0125 return FALSE; #0126 } #0127 #0128 BOOL CView::OnCmdMsg(UINT nid, int ncode) #0129 #0130 if (CWnd::OnCmdMsg(nID, ncode)) #0131 return TRUE; #0132 #0133 BOOL bhandled = FALSE; #0134 bhandled = m_pdocument->oncmdmsg(nid, ncode); #0135 return bhandled; #0136 } #0137 #0138 AFX_MSGMAP* CCmdTarget::GetMessageMap() const #0139 #0140 return &CCmdTarget::messageMap; #0141 } #0142 #0143 AFX_MSGMAP CCmdTarget::messageMap = #0144 #0145 NULL, #0146 &CCmdTarget::_messageEntries[0] #0147 }; #0148 #0149 AFX_MSGMAP_ENTRY CCmdTarget::_messageEntries[] = #0150 #0151 #0152 0, 0, CCmdTargetid, 0, AfxSig_end, 0 } #0153 }; #0154 #0155 BEGIN_MESSAGE_MAP(CWnd, CCmdTarget) #0156 ON_COMMAND(CWndid, 0) #0157 END_MESSAGE_MAP() 211
第 ㆒ 篇 勿 在 浮 砂 築 高 台 #0158 #0159 BEGIN_MESSAGE_MAP(CFrameWnd, CWnd) #0160 ON_COMMAND(CFrameWndid, 0) #0161 END_MESSAGE_MAP() #0162 #0163 BEGIN_MESSAGE_MAP(CDocument, CCmdTarget) #0164 ON_COMMAND(CDocumentid, 0) #0165 END_MESSAGE_MAP() #0166 #0167 BEGIN_MESSAGE_MAP(CView, CWnd) #0168 ON_COMMAND(CViewid, 0) #0169 END_MESSAGE_MAP() #0170 #0171 BEGIN_MESSAGE_MAP(CWinApp, CCmdTarget) #0172 ON_COMMAND(CWinAppid, 0) #0173 END_MESSAGE_MAP() #0174 #0175 CWinApp* AfxGetApp() #0176 #0177 return theapp.m_pcurrentwinapp; #0178 } #0179 #0180 LRESULT AfxWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam, #0181 CWnd *pwnd) // last parameter pwnd is added by JJHou. #0182 #0183 //... #0184 return AfxCallWndProc(pWnd, hwnd, nmsg, wparam, lparam); #0185 } #0186 #0187 LRESULT AfxCallWndProc(CWnd* pwnd, HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam) #0188 #0189 LRESULT lresult = pwnd->windowproc(nmsg, wparam, lparam); #0190 return lresult; #0191 } MY.H #0001 #include <iostream.h> #0002 #include "mfc.h" #0003 #0004 class CMyWinApp : public CWinApp #0005 #0006 public: #0007 CMyWinApp::CMyWinApp() #0008 } 212
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 #0009 CMyWinApp::~CMyWinApp() #0010 } #0011 virtual BOOL InitInstance(); #0012 DECLARE_MESSAGE_MAP() #0013 }; #0014 #0015 class CMyFrameWnd : public CFrameWnd #0016 #0017 public: #0018 CMyFrameWnd(); #0019 ~CMyFrameWnd() #0020 } #0021 DECLARE_MESSAGE_MAP() #0022 }; #0023 #0024 class CMyDoc : public CDocument #0025 #0026 public: #0027 CMyDoc::CMyDoc() #0028 } #0029 CMyDoc::~CMyDoc() #0030 } #0031 DECLARE_MESSAGE_MAP() #0032 }; #0033 #0034 class CMyView : public CView #0035 #0036 public: #0037 CMyView::CMyView() #0038 } #0039 CMyView::~CMyView() #0040 } #0041 DECLARE_MESSAGE_MAP() #0042 }; MY.CPP #0001 #include "my.h" #0002 #0003 CMyWinApp theapp; // global object #0004 #0005 BOOL CMyWinApp::InitInstance() #0006 #0007 cout << "CMyWinApp::InitInstance \n"; #0008 m_pmainwnd = new CMyFrameWnd; #0009 return TRUE; 213
第 ㆒ 篇 勿 在 浮 砂 築 高 台 #0010 } #0011 #0012 CMyFrameWnd::CMyFrameWnd() #0013 #0014 Create(); #0015 } #0016 #0017 BEGIN_MESSAGE_MAP(CMyWinApp, CWinApp) #0018 ON_COMMAND(CMyWinAppid, 0) #0019 END_MESSAGE_MAP() #0020 #0021 BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd) #0022 ON_COMMAND(CMyFrameWndid, 0) #0023 END_MESSAGE_MAP() #0024 #0025 BEGIN_MESSAGE_MAP(CMyDoc, CDocument) #0026 ON_COMMAND(CMyDocid, 0) #0027 END_MESSAGE_MAP() #0028 #0029 BEGIN_MESSAGE_MAP(CMyView, CView) #0030 ON_COMMAND(CMyViewid, 0) #0031 END_MESSAGE_MAP() #0032 #0033 void printlpentries(afx_msgmap_entry* lpentry) #0034 #0035 struct #0036 int classid; #0037 char* classname; #0038 } classinfo[] = #0039 CCmdTargetid, "CCmdTarget ", #0040 CWinThreadid, "CWinThread ", #0041 CWinAppid, "CWinApp ", #0042 CMyWinAppid, "CMyWinApp ", #0043 CWndid, "CWnd ", #0044 CFrameWndid, "CFrameWnd ", #0045 CMyFrameWndid, "CMyFrameWnd ", #0046 CViewid, "CView ", #0047 CMyViewid, "CMyView ", #0048 CDocumentid, "CDocument ", #0049 CMyDocid, "CMyDoc ", #0050 0, " " #0051 }; #0052 #0053 for (int i=0; classinfo[i].classid!= 0; i++) #0054 #0055 if (classinfo[i].classid == lpentry->nid) 214
第 3 章 MFC 六 大 關 鍵 技 術 之 模 擬 #0056 #0057 cout << lpentry->nid << " "; #0058 cout << classinfo[i].classname << endl; #0059 break; #0060 } #0061 } #0062 } #0063 //--------------------------------------------------------------- #0064 // main #0065 //--------------------------------------------------------------- #0066 void main() #0067 #0068 CWinApp* papp = AfxGetApp(); #0069 #0070 papp->initapplication(); #0071 papp->initinstance(); #0072 papp->run(); #0073 #0074 CMyDoc* pmydoc = new CMyDoc; #0075 CMyView* pmyview = new CMyView; #0076 CFrameWnd* pmyframe = (CFrameWnd*)pApp->m_pMainWnd; #0077 pmyframe->m_pviewactive = pmyview; #0078 pmyview->m_pdocument = pmydoc; #0079 #0080 // test Message Routing #0081 cout << endl << "pmyframe received a WM_CREATE, routing path :" << endl; #0082 AfxWndProc(0, WM_CREATE, 0, 0, pmyframe); #0083 #0084 cout << endl << "pmyview received a WM_PAINT, routing path :" << endl; #0085 AfxWndProc(0, WM_PAINT, 0, 0, pmyview); #0086 #0087 cout << endl << "pmyview received a WM_COMMAND, routing path :" << endl; #0088 AfxWndProc(0, WM_COMMAND, 0, 0, pmyview); #0089 #0090 cout << endl << "pmyframe received a WM_COMMAND, routing path :" << endl; #0091 AfxWndProc(0, WM_COMMAND, 0, 0, pmyframe); #0092 } 215
第 ㆒ 篇 勿 在 浮 砂 築 高 台 MFC MFC C++ console Runtime Class Runtime Time Information Dynamic Creation Message Mapping Command Routing application framework Runtime Class Frame1~Frame8 MFC MFC Visual C++ 216