我們知道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和消息映射相關的代碼。
測試了下,這個窗口框架基本上只有2個核心文件,完全獨立, 可以直接放到任何現有框架中使用(ATL/WTL中使用可能要改下內部一些類名, 但是用了ATL/WTL肯定就不用這個框架了)。
posted on 2013-09-08 14:47
Richard Wei 閱讀(4394)
評論(11) 編輯 收藏 引用 所屬分類:
windows desktop