. 今天分析第五行代码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到底干了什么。