咱們知道Windows的窗口消息處理函數是C方式, 面向過程的, 因此窗口框架的基本任務就是將它轉成面向對象的方式, 確切的說如何將消息處理函數第一參數HWND轉成對象指針。
關於這個問題, 其實網上你們已經說濫了, 這裏只是簡單記錄一下。
Map方式:MFC就是採用這種方式, 就是創建一張從HWND到CWindow*的映射表, 每次收到消息都從Map中根據HWND找到CWindow*, 再進行調用
UserData的方式:
CreateWindow
時將最後一個附加數據設置爲對象CWindow* 指針, 當收到第一個消息WM_NCCREATE時, 取出傳過來的附加數據指針, 將該指針設置成窗口的UserData, SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast(pThis))
, 後面收到任何消息就能夠直接調用GetWindowLongPtr(hWnd, GWLP_USERDATA)
取出窗口指針, 進行面向對象方式的調用。
Thunk方式:這是ATL採用的方式,經過彙編代碼,直接將窗口消息處理函數的第一個參數HWND改寫成CWindow*, 而後進行面向對象方式的調用, 原理能夠見我之前寫的
理解ATL中的一些彙編代碼
最近工做中要寫一些簡單窗口相關的代碼, 考慮用什麼方式封裝窗口過程:
MFC確定不引入, map方式也不考慮。
UserData方式過低效 ,並且窗口的UserData讓框架用了,咱們其餘地方可能還要用呢。
ATL的Thunk方式不錯, 可是咱們不想引入COM, 也不想用ATL的庫和代碼。
原始的 C API方式, 依賴性和效率都最佳, 惋惜就是否是面向對象的。
各有優缺,怎樣才能熊掌和魚翅兼得?
最後決定把ATL中窗口Thunk相關的核心代碼剝離出來, 作一個徹底獨立的最基本窗口框架。咱們框架的基本目標是可讓咱們方便的開發一些簡單的窗口, 因此去掉了ATL窗口中一些不經常使用或是可替代的東西, 只留下必須和最有用的。簡單說來,把ATL中的CWindow給去掉了,它只是窗口API的封裝, 咱們能夠直接調用API來實現;把CWinTraits給去掉了,由於它只是窗口風格的封裝; 把SubClass和SuperClass也去掉了, 咱們的簡單窗口用不到這個特性; 把Dialog, Container和COM相關的都去掉了, 這些都不是窗口的核心部分。最後只留下,窗口註冊建立, thunk和消息映射相關的代碼。html
測試了下,這個窗口框架基本上只有2個核心文件,徹底獨立, 能夠直接放到任何現有框架中使用(ATL/WTL中使用可能要改下內部一些類名, 可是用了ATL/WTL確定就不用這個框架了)。