在_tWinMain中有这样两条语句:
1 MainWindowDelegate delegate; 2 view::Window::CreateNativeWindow(NULL, gfx::Rect(), &delegate);
从这开始窗口相关的探索,目的就是要找到WNDCLASS注册与CreateWindow的地方。
Window类顾名思义就是的窗口。chromium对原始窗口做的封装。window相关的类主要有Window / WindowDelegate / WindowWin / Widget / WidgetDelegate / WidgetWin.
我的理解,Window为有标题栏和边框的窗口,Widget则为无标题栏的HWND。Window其实是特殊的在Widget上加了标题栏和边框相关处理的类。chromium已经在Window和Widget中加入默认消息处理,以及默认的窗口属性。我们自己的程序当然要有自己窗口属性和窗口行为,这时就需要继承Window或者Widget的嵌入类Delegate。
我在学习代码的时候画了一下类图,辅助自己理解。
按图索骥,从基类开始看起。
基类:MessageMapInterface
1 class MessageMapInterface 2 { 3 public: 4 virtual BOOL ProcessWindowMessage(HWND window, 5 UINT message, 6 WPARAM w_param, 7 LPARAM l_param, 8 LRESULT& result, 9 DWORD msg_mad_id = 0) = 0; 10 };
只有一个函数,主要用于处理消息,在消息响应函数(WndProc)中会调用此函数进行消息处理。
接下来就是WindowImpl类,WindowImpl中最重要的就是WndProc,这个函数就是我们注册在WNDCLASS里的消息响应函数。
1 class WindowImpl : public MessageMapInterface 2 { 3 private: 4 static LRESULT CALLBACK WndProc(HWND window, UINT message, 5 WPARAM w_param, LPARAM l_param); 6 };
WndProc会使用基类指针来调用基类的ProcessWindowMessage函数,消息的控制权就交给ProcessWindowMessage,多态行为。
再下来是widget基类,我们可以理解为是HWND的属性 行为的封装。
1 class Widget 2 { 3 public: 4 // Delegate类在这被加入 5 virtual WidgetDelegate* GetWidgetDelegate() = 0; 6 virtual void SetWidgetDelegate(WidgetDelegate* delegate) = 0; 7 8 9 // 这都是HWND的常规属性与行为 10 virtual void GetBounds(gfx::Rect* out, bool including_frame) const = 0; 11 virtual void SetBounds(const gfx::Rect& bounds) = 0; 12 virtual void MoveAbove(Widget* widget) = 0; 13 virtual void SetShape(HRGN shape) = 0; 14 virtual void Close() = 0; 15 virtual void CloseNow() = 0; 16 virtual void Show() = 0; 17 virtual void Hide() = 0; 18 virtual void SetAlwaysOnTop(bool on_top) = 0; 19 virtual bool IsVisible() const = 0; 20 virtual bool IsActive() const = 0; 21 22 // tooltip、主题管理、焦点管理 23 virtual TooltipManager* GetTooltipManager() = 0; 24 virtual bool GetAccelerator(int cmd_id, MenuAccelerator* accelerator) = 0; 25 virtual ThemeProvider* GetThemeProvider() const = 0; 26 virtual ThemeProvider* GetDefaultThemeProvider() const = 0; 27 virtual FocusManager* GetFocusManager() = 0; 28 29 // 更新界面函数 30 virtual void PaintNow(const gfx::Rect& update_rect) = 0; 31 };
widget的实现类为WidgetWin,平台相关Win,就是windows平台的widget子类。
1 class WidgetWin : public gfx::WindowImpl, 2 public Widget, 3 public MessageLoopForUI::Observer, 4 public FocusTraversable 5 { 6 public: 7 VIEW_BEGIN_MSG_MAP_EX(WidgetWin) 8 // Range handlers must go first! 9 VIEW_MESSAGE_RANGE_HANDLER_EX(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseRange) 10 VIEW_MESSAGE_RANGE_HANDLER_EX(WM_NCMOUSEMOVE, WM_NCMOUSEMOVE, OnMouseRange) 11 12 // Reflected message handler 13 VIEW_MESSAGE_HANDLER_EX(kReflectedMessage, OnReflectedMessage) 14 15 // CustomFrameWindow hacks 16 VIEW_MESSAGE_HANDLER_EX(WM_NCUAHDRAWCAPTION, OnNCUAHDrawCaption) 17 VIEW_MESSAGE_HANDLER_EX(WM_NCUAHDRAWFRAME, OnNCUAHDrawFrame) 18 19 // Vista and newer 20 VIEW_MESSAGE_HANDLER_EX(WM_DWMCOMPOSITIONCHANGED, OnDwmCompositionChanged) 21 22 // Non-atlcrack.h handlers 23 VIEW_MESSAGE_HANDLER_EX(WM_GETOBJECT, OnGetObject) 24 VIEW_MESSAGE_HANDLER_EX(WM_NCMOUSELEAVE, OnNCMouseLeave) 25 VIEW_MESSAGE_HANDLER_EX(WM_MOUSELEAVE, OnMouseLeave) 26 VIEW_MESSAGE_HANDLER_EX(WM_MOUSEWHEEL, OnMouseWheel) 27 28 // This list is in _ALPHABETICAL_ order! OR I WILL HURT YOU. 29 VIEW_MSG_WM_ACTIVATE(OnActivate) 30 VIEW_MSG_WM_ACTIVATEAPP(OnActivateApp) 31 VIEW_MSG_WM_APPCOMMAND(OnAppCommand) 32 VIEW_MSG_WM_CANCELMODE(OnCancelMode) 33 VIEW_MSG_WM_CAPTURECHANGED(OnCaptureChanged) 34 VIEW_MSG_WM_CLOSE(OnClose) 35 VIEW_MSG_WM_COMMAND(OnCommand) 36 VIEW_MSG_WM_CREATE(OnCreate) 37 VIEW_MSG_WM_DESTROY(OnDestroy) 38 39 VIEW_MSG_WM_SETTEXT(OnSetText) 40 VIEW_MSG_WM_SETTINGCHANGE(OnSettingChange) 41 VIEW_MSG_WM_SIZE(OnSize) 42 VIEW_MSG_WM_SYSCOMMAND(OnSysCommand) 43 VIEW_MSG_WM_THEMECHANGED(OnThemeChanged) 44 VIEW_MSG_WM_VSCROLL(OnVScroll) 45 VIEW_MSG_WM_WINDOWPOSCHANGING(OnWindowPosChanging) 46 VIEW_MSG_WM_WINDOWPOSCHANGED(OnWindowPosChanged) 47 VIEW_END_MSG_MAP() 48 49 // Overridden from Widget: 50 // Overridden from MessageLoop::Observer: 51 // Overridden from FocusTraversable: 52 53 54 protected: 55 virtual void OnActivate(UINT action, BOOL minimized, HWND window); 56 virtual void OnActivateApp(BOOL active, DWORD thread_id); 57 virtual LRESULT OnAppCommand(HWND window, short app_command, WORD device, 58 int keystate); 59 virtual void OnCancelMode(); 60 virtual void OnCaptureChanged(HWND hwnd); 61 virtual void OnClose(); 62 virtual void OnCommand(UINT notification_code, int command_id, HWND window); 63 virtual LRESULT OnCreate(CREATESTRUCT* create_struct); 64 // WARNING: If you override this be sure and invoke super, otherwise we'll 65 // leak a few things. 66 virtual void OnDestroy(); 67 68 virtual LRESULT OnSetText(const wchar_t* text); 69 virtual void OnSettingChange(UINT flags, const wchar_t* section); 70 virtual void OnSize(UINT param, const gfx::Size& size); 71 virtual void OnSysCommand(UINT notification_code, gfx::Point click); 72 virtual void OnThemeChanged(); 73 virtual void OnVScroll(int scroll_type, short position, HWND scrollbar); 74 virtual void OnWindowPosChanging(WINDOWPOS* window_pos); 75 virtual void OnWindowPosChanged(WINDOWPOS* window_pos); 76 77 // deletes this window as it is destroyed, override to provide different 78 // behavior. 79 virtual void OnFinalMessage(HWND window); 80 };
从继承关系widget_win不仅实现了widget,而且还加入了消息处理相关,焦点处理等的内容。
从类的接口看,确实是在处理消息了,这就是windows消息的默认处理类了。消息是怎么传送到这里的呢?
回到祖父类,ProcessWindowMessage消息处理总函数, 再看看WidgetWin中的VIEW_BEGIN_MSG_MAP_EX宏,
1 #define VIEW_BEGIN_MSG_MAP_EX(theClass) 2 public: 3 BOOL m_bMsgHandled; 4 /* "handled" management for cracked handlers */ 5 BOOL IsMsgHandled() const 6 { 7 return m_bMsgHandled; 8 } 9 void SetMsgHandled(BOOL bHandled) 10 { 11 m_bMsgHandled = bHandled; 12 } 13 BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID = 0) 14 { 15 BOOL bOldMsgHandled = m_bMsgHandled; 16 BOOL bRet = _ProcessWindowMessage(hWnd, uMsg, wParam, lParam, lResult, dwMsgMapID); 17 m_bMsgHandled = bOldMsgHandled; 18 return bRet; 19 } 20 BOOL _ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID) 21 { 22 BOOL bHandled = TRUE; 23 hWnd; 24 uMsg; 25 wParam; 26 lParam; 27 lResult; 28 bHandled; 29 switch(dwMsgMapID) 30 { 31 case 0:
已经看到ProcessWindowMessage的身影了,ProcessWindowMessage是虚函数重载,WndProc实际会把消息传送到这里,ProcessWindowMessage会调用_ProcessWindowMessage接下来就是switch case处理分发了,这应该是借鉴了WTL框架,
回看1.1的win32典型程序的消息处理函数,都是switch case 来分发消息,这里只是用宏伪装,用类进行了包装而已。
window类封装了title name,最大/小化支持等等一些窗口的属性和行为,这些都是纯虚的函数,最重要的就是在main.cpp被调用的static函数。
1 class Window 2 { 3 public: 4 virtual ~Window() {} 5 6 // Creates an instance of an object implementing this interface. 7 // TODO(beng): create a version of this function that takes a HWND, for 8 // constrained windows. 9 static Window* CreateNativeWindow(HWND parent, 10 const gfx::Rect& bounds, WindowDelegate* window_delegate); 11 };
1 // static 2 Window* Window::CreateNativeWindow(HWND parent, 3 const gfx::Rect& bounds, 4 WindowDelegate* window_delegate) 5 { 6 WindowWin* window = new WindowWin(window_delegate); // 1. new出子类 7 window->GetNonClientView()->SetFrameView(window->CreateFrameViewForWindow()); 8 window->Init(parent, bounds); //2.调用WindowWin::Init 9 return window; 10 }
1 void WindowImpl::Init(HWND parent, const Rect& bounds) 2 { 3 if(window_style_ == 0) 4 { 5 window_style_ = parent ? kWindowDefaultChildStyle : kWindowDefaultStyle; 6 } 7 8 if(parent && !::IsWindow(parent)) 9 { 10 NOTREACHED() << "invalid parent window specified."; 11 parent = NULL; 12 } 13 14 int x, y, width, height; 15 if(bounds.IsEmpty()) 16 { 17 x = y = width = height = CW_USEDEFAULT; 18 } 19 else 20 { 21 x = bounds.x(); 22 y = bounds.y(); 23 width = bounds.width(); 24 height = bounds.height(); 25 } 26 27 hwnd_ = CreateWindowEx(window_ex_style_, GetWindowClassName().c_str(), NULL, 28 window_style_, x, y, width, height, parent, NULL, NULL, this); // 这里就是创建窗口了 29 DCHECK(hwnd_); 30 }
到此,窗口的创建,消息的分发都已经展现出来了,剩下的就是消息循环了。
WindowWin继承自widget,重载了NC消息的处理。又继承了window类,实现窗口的行为及属性。
WindowDelegate则是window的委派,实质上应该是Window子类WindowWin的委派。我们要修改窗口的属性行为以及如何构建窗口也只需要继承WindowDelegate,重载windowDelegate的行为函数即可。main.cpp中就是这么干的,MainWindowDelegate就是继承WindowDelegate。