在_tWinMain中有这样两条语句:

 MainWindowDelegate delegate;
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

 class MessageMapInterface
{
public:
virtual BOOL ProcessWindowMessage(HWND window,
UINT message,
WPARAM w_param,
LPARAM l_param,
LRESULT& result,
DWORD msg_mad_id = ) = ;
};

只有一个函数,主要用于处理消息,在消息响应函数(WndProc)中会调用此函数进行消息处理。

接下来就是WindowImpl类,WindowImpl中最重要的就是WndProc,这个函数就是我们注册在WNDCLASS里的消息响应函数。

 class WindowImpl : public MessageMapInterface
{
private:
static LRESULT CALLBACK WndProc(HWND window, UINT message,
WPARAM w_param, LPARAM l_param);
};

WndProc会使用基类指针来调用基类的ProcessWindowMessage函数,消息的控制权就交给ProcessWindowMessage,多态行为。

再下来是widget基类,我们可以理解为是HWND的属性 行为的封装。

 class Widget
{
public:
// Delegate类在这被加入
virtual WidgetDelegate* GetWidgetDelegate() = ;
virtual void SetWidgetDelegate(WidgetDelegate* delegate) = ; // 这都是HWND的常规属性与行为
virtual void GetBounds(gfx::Rect* out, bool including_frame) const = ;
virtual void SetBounds(const gfx::Rect& bounds) = ;
virtual void MoveAbove(Widget* widget) = ;
virtual void SetShape(HRGN shape) = ;
virtual void Close() = ;
virtual void CloseNow() = ;
virtual void Show() = ;
virtual void Hide() = ;
virtual void SetAlwaysOnTop(bool on_top) = ;
virtual bool IsVisible() const = ;
virtual bool IsActive() const = ; // tooltip、主题管理、焦点管理
virtual TooltipManager* GetTooltipManager() = ;
virtual bool GetAccelerator(int cmd_id, MenuAccelerator* accelerator) = ;
virtual ThemeProvider* GetThemeProvider() const = ;
virtual ThemeProvider* GetDefaultThemeProvider() const = ;
virtual FocusManager* GetFocusManager() = ; // 更新界面函数
virtual void PaintNow(const gfx::Rect& update_rect) = ;
};

widget的实现类为WidgetWin,平台相关Win,就是windows平台的widget子类。

     class WidgetWin : public gfx::WindowImpl,
public Widget,
public MessageLoopForUI::Observer,
public FocusTraversable
{
public:
VIEW_BEGIN_MSG_MAP_EX(WidgetWin)
// Range handlers must go first!
VIEW_MESSAGE_RANGE_HANDLER_EX(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseRange)
VIEW_MESSAGE_RANGE_HANDLER_EX(WM_NCMOUSEMOVE, WM_NCMOUSEMOVE, OnMouseRange) // Reflected message handler
VIEW_MESSAGE_HANDLER_EX(kReflectedMessage, OnReflectedMessage) // CustomFrameWindow hacks
VIEW_MESSAGE_HANDLER_EX(WM_NCUAHDRAWCAPTION, OnNCUAHDrawCaption)
VIEW_MESSAGE_HANDLER_EX(WM_NCUAHDRAWFRAME, OnNCUAHDrawFrame) // Vista and newer
VIEW_MESSAGE_HANDLER_EX(WM_DWMCOMPOSITIONCHANGED, OnDwmCompositionChanged) // Non-atlcrack.h handlers
VIEW_MESSAGE_HANDLER_EX(WM_GETOBJECT, OnGetObject)
VIEW_MESSAGE_HANDLER_EX(WM_NCMOUSELEAVE, OnNCMouseLeave)
VIEW_MESSAGE_HANDLER_EX(WM_MOUSELEAVE, OnMouseLeave)
VIEW_MESSAGE_HANDLER_EX(WM_MOUSEWHEEL, OnMouseWheel) // This list is in _ALPHABETICAL_ order! OR I WILL HURT YOU.
VIEW_MSG_WM_ACTIVATE(OnActivate)
VIEW_MSG_WM_ACTIVATEAPP(OnActivateApp)
VIEW_MSG_WM_APPCOMMAND(OnAppCommand)
VIEW_MSG_WM_CANCELMODE(OnCancelMode)
VIEW_MSG_WM_CAPTURECHANGED(OnCaptureChanged)
VIEW_MSG_WM_CLOSE(OnClose)
VIEW_MSG_WM_COMMAND(OnCommand)
VIEW_MSG_WM_CREATE(OnCreate)
VIEW_MSG_WM_DESTROY(OnDestroy) VIEW_MSG_WM_SETTEXT(OnSetText)
VIEW_MSG_WM_SETTINGCHANGE(OnSettingChange)
VIEW_MSG_WM_SIZE(OnSize)
VIEW_MSG_WM_SYSCOMMAND(OnSysCommand)
VIEW_MSG_WM_THEMECHANGED(OnThemeChanged)
VIEW_MSG_WM_VSCROLL(OnVScroll)
VIEW_MSG_WM_WINDOWPOSCHANGING(OnWindowPosChanging)
VIEW_MSG_WM_WINDOWPOSCHANGED(OnWindowPosChanged)
VIEW_END_MSG_MAP() // Overridden from Widget:
// Overridden from MessageLoop::Observer:
// Overridden from FocusTraversable: protected:
virtual void OnActivate(UINT action, BOOL minimized, HWND window);
virtual void OnActivateApp(BOOL active, DWORD thread_id);
virtual LRESULT OnAppCommand(HWND window, short app_command, WORD device,
int keystate);
virtual void OnCancelMode();
virtual void OnCaptureChanged(HWND hwnd);
virtual void OnClose();
virtual void OnCommand(UINT notification_code, int command_id, HWND window);
virtual LRESULT OnCreate(CREATESTRUCT* create_struct);
// WARNING: If you override this be sure and invoke super, otherwise we'll
// leak a few things.
virtual void OnDestroy(); virtual LRESULT OnSetText(const wchar_t* text);
virtual void OnSettingChange(UINT flags, const wchar_t* section);
virtual void OnSize(UINT param, const gfx::Size& size);
virtual void OnSysCommand(UINT notification_code, gfx::Point click);
virtual void OnThemeChanged();
virtual void OnVScroll(int scroll_type, short position, HWND scrollbar);
virtual void OnWindowPosChanging(WINDOWPOS* window_pos);
virtual void OnWindowPosChanged(WINDOWPOS* window_pos); // deletes this window as it is destroyed, override to provide different
// behavior.
virtual void OnFinalMessage(HWND window);
};

从继承关系widget_win不仅实现了widget,而且还加入了消息处理相关,焦点处理等的内容。
从类的接口看,确实是在处理消息了,这就是windows消息的默认处理类了。消息是怎么传送到这里的呢?
回到祖父类,ProcessWindowMessage消息处理总函数, 再看看WidgetWin中的VIEW_BEGIN_MSG_MAP_EX宏,

 #define VIEW_BEGIN_MSG_MAP_EX(theClass) \
public: \
BOOL m_bMsgHandled; \
/* "handled" management for cracked handlers */ \
BOOL IsMsgHandled() const \
{ \
return m_bMsgHandled; \
} \
void SetMsgHandled(BOOL bHandled) \
{ \
m_bMsgHandled = bHandled; \
} \
BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID = ) \
{ \
BOOL bOldMsgHandled = m_bMsgHandled; \
BOOL bRet = _ProcessWindowMessage(hWnd, uMsg, wParam, lParam, lResult, dwMsgMapID); \
m_bMsgHandled = bOldMsgHandled; \
return bRet; \
} \
BOOL _ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID) \
{ \
BOOL bHandled = TRUE; \
hWnd; \
uMsg; \
wParam; \
lParam; \
lResult; \
bHandled; \
switch(dwMsgMapID) \
{ \
case :

已经看到ProcessWindowMessage的身影了,ProcessWindowMessage是虚函数重载,WndProc实际会把消息传送到这里,ProcessWindowMessage会调用_ProcessWindowMessage接下来就是switch case处理分发了,这应该是借鉴了WTL框架,

回看1.1的win32典型程序的消息处理函数,都是switch case 来分发消息,这里只是用宏伪装,用类进行了包装而已。

window类封装了title name,最大/小化支持等等一些窗口的属性和行为,这些都是纯虚的函数,最重要的就是在main.cpp被调用的static函数。

     class Window
{
public:
virtual ~Window() {} // Creates an instance of an object implementing this interface.
// TODO(beng): create a version of this function that takes a HWND, for
// constrained windows.
static Window* CreateNativeWindow(HWND parent,
const gfx::Rect& bounds, WindowDelegate* window_delegate);
};
     // static
Window* Window::CreateNativeWindow(HWND parent,
const gfx::Rect& bounds,
WindowDelegate* window_delegate)
{
WindowWin* window = new WindowWin(window_delegate); // 1. new出子类
window->GetNonClientView()->SetFrameView(window->CreateFrameViewForWindow());
window->Init(parent, bounds); //2.调用WindowWin::Init
return window;
}
     void WindowImpl::Init(HWND parent, const Rect& bounds)
{
if(window_style_ == )
{
window_style_ = parent ? kWindowDefaultChildStyle : kWindowDefaultStyle;
} if(parent && !::IsWindow(parent))
{
NOTREACHED() << "invalid parent window specified.";
parent = NULL;
} int x, y, width, height;
if(bounds.IsEmpty())
{
x = y = width = height = CW_USEDEFAULT;
}
else
{
x = bounds.x();
y = bounds.y();
width = bounds.width();
height = bounds.height();
} hwnd_ = CreateWindowEx(window_ex_style_, GetWindowClassName().c_str(), NULL,
window_style_, x, y, width, height, parent, NULL, NULL, this); // 这里就是创建窗口了
DCHECK(hwnd_);
}

到此,窗口的创建,消息的分发都已经展现出来了,剩下的就是消息循环了。

WindowWin继承自widget,重载了NC消息的处理。又继承了window类,实现窗口的行为及属性。

WindowDelegate则是window的委派,实质上应该是Window子类WindowWin的委派。我们要修改窗口的属性行为以及如何构建窗口也只需要继承WindowDelegate,重载windowDelegate的行为函数即可。main.cpp中就是这么干的,MainWindowDelegate就是继承WindowDelegate。

1.3. chromium源代码分析 - chromiumframe - 窗口系列的更多相关文章

  1. 1.4. chromium源代码分析 - chromiumframe - 消息系列

    Message framework 是对消息循环的封装和扩展,Chromium在消息循环中增加处理内部任务的工作.将内部工作处理寄生在Windows的消息循环中,会有一个问题,就是没有Windows自 ...

  2. 1.2. chromium源代码分析 - chromiumframe - 入口函数

    ChromiumFrame的入口函数在main.cpp中,打开main.cpp.中包含3个类和_tWinMain函数._tWinMain就是我们要找的入口函数.我做了部分注释: int APIENTR ...

  3. 1.1. chromium源代码分析 - chromiumframe - 介绍

    本人能力有效,面对chromium庞大的代码就头大.还是先由前辈的chromiumFrame入手. 1. chromeFrame概貌 chromiumFrame是前辈的心血之作,以最小化的方式抽出ch ...

  4. 0. chromium源代码分析 - 序

    本打算在CSDN写完这系列文字,却因为在CSDN中误删了一篇blog,该篇blog被移到了回收站.然而CSDN居然没有从回收站撤销删除的操作方法.联想到之前CSDN泄密的问题,其可靠性值得怀疑.随转向 ...

  5. SDL2源代码分析2:窗口(SDL_Window)

    ===================================================== SDL源代码分析系列文章列表: SDL2源代码分析1:初始化(SDL_Init()) SDL ...

  6. MyBatis架构设计及源代码分析系列(一):MyBatis架构

    如果不太熟悉MyBatis使用的请先参见MyBatis官方文档,这对理解其架构设计和源码分析有很大好处. 一.概述 MyBatis并不是一个完整的ORM框架,其官方首页是这么介绍自己 The MyBa ...

  7. Spark SQL 源代码分析系列

    从决定写Spark SQL文章的源代码分析,到现在一个月的时间,一个又一个几乎相同的结束很快,在这里也做了一个综合指数,方便阅读,下面是读取顺序 :) 第一章 Spark SQL源代码分析之核心流程 ...

  8. Java集合系列之TreeMap源代码分析

    一.概述 TreeMap是基于红黑树实现的.因为TreeMap实现了java.util.sortMap接口,集合中的映射关系是具有一定顺序的,该映射依据其键的自然顺序进行排序或者依据创建映射时提供的C ...

  9. SDL2源代码分析8:视频显示总结

    ===================================================== SDL源代码分析系列文章列表: SDL2源代码分析1:初始化(SDL_Init()) SDL ...

随机推荐

  1. Delphi中运行时改变panel的位置及大小(WM_SysCommand消息配合参数使用,很奇妙) good

    procedure TForm1.pnl1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Inte ...

  2. Android程序的入口点

    原文:Android程序的入口点 android应用程序,由一到多个Activity组成.每个Activity没有很紧密的联系,因为我们可以在自己的程序中调用其它Activity,特别是调用自己的代码 ...

  3. 嵌入式davinci电路元素基础和PWM模块

    1,DAC_OUT和DAC_OUTB是AD9912输出的差分信号. 2,电容器储存电荷的能力,常用的单位是F.uF.nF.pFUF大了好还是UF小了好,要根据电路自身需要而设计, 要看电路滤波是在高频 ...

  4. 发布MFC ActiveX控件并实现自动更新

    一.        引言 上一篇我们讲了如何使用 VC 2005来开发 MFC ActiveX控件,我们开发 ActiveX控件最终目的是将 ActiveX控件发布出来并嵌入在 Web网页中,随着控件 ...

  5. JAVA Layout

    /**  * baidu :组件不会直接放到框架上,而是放在若干个面板上,这些面板再放到窗格上?  * 实际上在JFrame上可直接添加Jbutton  *   * BorderLayout Flow ...

  6. struts2的初步认识!

    struts2的jar包会完成一些工作,让你的数据和显示很好的联系在一起.     开始的时候,主要通过三个点来完成Struts2的工作          1,JAVA类     2,struts.x ...

  7. TabHost 简单用法

    package com.google.tabhost;    import android.app.TabActivity;  import android.os.Bundle;  import an ...

  8. EasyUI中datagrid实现显示、增加、 删除、 修改、 查询操作(后台代码C#)

    菜鸟进入,高手请绕道! +++++++++++++++++++++++++++++++++++++++ 一.数据的显示 1新建HtmlPage2.html页面,引入相关文件.如下所示 <scri ...

  9. select2简单例子

    1.html中静态值 html <%--multiple 为多选--%> <select multiple id="e1"> <option>& ...

  10. windows下设置/删除Tomcat的开机自启动

    绿色版tomcat在配置好Java环境以后直接运行bin下面的startup.bat就能够正常启动,但是在客户这里很多时候都 需要tomcat开机自动启动.下面简单介绍一如何在windows下面开机自 ...