最新消息:想得多,做的少。一天到晚瞎鸡巴搞。

duilib源码剖析 day2 pFrame->Create()做了什么

曲径通幽 阿虚 305浏览 0评论

.      今天分析第五行代码pFrame->Create()做了什么。

//创建窗体
pFrame->Create(
    NULL, 
    _T("这是一个最简单的测试用exe,修改test1.xml就可以看到效果"), 
    UI_WNDSTYLE_FRAME|WS_CLIPCHILDREN, 
    WS_EX_WINDOWEDGE);

.      此处下断点后F11跟进可以看到Create函数是基类CWindowWnd的成员函数。这个函数并只有6行代码。

HWND CWindowWnd::Create(HWND hwndParent, LPCTSTR pstrName, DWORD dwStyle, 
    DWORD dwExStyle, int x, int y, int cx, int cy, HMENU hMenu)
{
    if( GetSuperClassName() != NULL && !RegisterSuperclass() ) 
        return NULL;
    if( GetSuperClassName() == NULL && !RegisterWindowClass() ) 
        return NULL;
m_hWnd = ::CreateWindowEx(
    dwExStyle, GetWindowClassName(), pstrName, dwStyle, x, y, cx, cy,
    hwndParent, hMenu, CPaintManagerUI::GetInstance(), this); 
    return m_hWnd;
}

.      在1~2行代码GetSuperClassName()这个虚函数在CWindowWnd类中暂时返回的是NULL值,RegisterSuperclass()函数是针对控件子类化使用的,在当前调用的Create中我们需要创建的是窗口。

if( GetSuperClassName() != NULL && !RegisterSuperclass() ) 
    return NULL;

.      在3~4行中的RegisterWindowClass()成员函数只做了一件事情,注册窗口类。其中需要知道的是窗口类的消息循环为CWindowWnd::__WndProc静态函数。

if( GetSuperClassName() == NULL && !RegisterWindowClass() ) 
        return NULL;
bool CWindowWnd::RegisterWindowClass()
{
    WNDCLASS wc = { 0 };
    wc.style = GetClassStyle();
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hIcon = NULL;
    wc.lpfnWndProc = CWindowWnd::__WndProc;
    wc.hInstance = CPaintManagerUI::GetInstance();
    wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = NULL;
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = GetWindowClassName();
    ATOM ret = ::RegisterClass(&wc);
    ASSERT(ret!=NULL || ::GetLastError()==ERROR_CLASS_ALREADY_EXISTS);
    return ret != NULL || ::GetLastError() == ERROR_CLASS_ALREADY_EXISTS;
}

.      第五行代码就是调用来创建窗口了。但是Windows会在CreateWindowEx函数中产生一个条WM_CREATE的消息事件。所以我们可以再第六行下一个断点和CWindowWnd::__WndProc中函数头下一个断点。

//创建窗口时会发送WM_CREATE消息
m_hWnd = ::CreateWindowEx(
    dwExStyle, 
    GetWindowClassName(), pstrName, dwStyle,x, y, 
    cx, cy, hwndParent, hMenu, CPaintManagerUI::GetInstance(), this);

.      在函数中并没有找到需要的WM_CREATE消息而且和窗体消息相关的只有两个NCCREATE非客户去窗体创建和WM_NCDESTROY非客户区窗体销毁。但是在17行可以看到pThis->HandleMessage(uMsg, wParam, lParam);函数中找到WM_CREATE消息事件的处理。因为HandleMessage()是虚函数且CFrameWindowWnd中实现了的HandleMessage()覆盖所以你需要单步进去或者直接找到CFrameWindowWnd的HandleMessage实现WM_CREATE的过程处理中下断点!

LRESULT CALLBACK CWindowWnd::__WndProc(
    HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    CWindowWnd* pThis = NULL;
    if( uMsg == WM_NCCREATE ) 
    {
        //........
    } 
    else 
    {
        //........
        if( uMsg == WM_NCDESTROY && pThis != NULL ) 
        {
            //........
        }
    }
    if( pThis != NULL ) 
    {
        return pThis->HandleMessage(uMsg, wParam, lParam);
    } 
    //........
}

.      下面是CFrameWindowWnd的HandleMessage对事件WM_CREATE响应处理逻辑,这几部分看起来比较复杂。m_pm为CPaintManagerUI类、CDialogBuilder、CControlUI新看的类。以下是无责任逻辑瞎胡乱猜测注释。

if( uMsg == WM_CREATE ) 
{
    //移除CPaintManagerUI类所有控件
    m_pm.Init(m_hWnd);
    //构造了一个新的类
    CDialogBuilder builder;
    //加载XML资源
    CControlUI* pRoot = builder.Create(
    _T("test1.xml"), (UINT)0, NULL, &m_pm); 
    //附加根节点
    m_pm.AttachDialog(pRoot);
    //添加通知
    m_pm.AddNotifier(this);
    //又new了一个新类,不知道干啥。
    m_pWndShadow = new CWndShadow;
    m_pWndShadow->Create(m_hWnd);
    RECT rcCorner = {3,3,4,4};
    RECT rcHoleOffset = {0,0,0,0};
    m_pWndShadow->SetImage(_T("LeftWithFill.png"), rcCorner, rcHoleOffset);
    //这又是啥?
    DWMNCRENDERINGPOLICY ncrp = DWMNCRP_ENABLED;
    SetWindowAttribute(
    m_hWnd, DWMWA_TRANSITIONS_FORCEDISABLED, &ncrp, sizeof(ncrp));
    //Init好像是空函数
    Init();
    return 0;
}

.      pFrame->Create()做了什么?两件事情,注册窗体,然后在创建窗体。没了。完。下部分再继续写WM_CREATE到底干了什么。

转载请注明:虚无 » duilib源码剖析 day2 pFrame->Create()做了什么

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址