创建窗口过程:
1. AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow); //MFC消息入口函数
2. AfxWinMain()
3. if (!pThread->InitInstance()) 线程初始化 进去
4. pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME, //单文档模板 ,1.菜单名称,2.文档,3框架,4视图
RUNTIME_CLASS(CDemoDoc),
RUNTIME_CLASS(CMainFrame), // 主 SDI 框架窗口
RUNTIME_CLASS(CDemoView));
5. CDocTemplate::CDocTemplate 进去 然后按F11进基类的构造函数
6. LoadTemplate(); 装载文档模板
7. void CDocTemplate::LoadTemplate() 跳出 逃到了第4步的继续
8. 现在在BOOL CDemoApp::InitInstance()里面 是第4步的继续 --> if (!ProcessShellCommand(cmdInfo)) 调度命令,相当于点击word打开 默认filenew新建 不让nothing
====F1进去
注册在这里!!
9. 在CWinApp::ProcessShellCommand(CCommandLineInfo& rCmdInfo)里面 找到 if (!AfxGetApp()->OnCmdMsg(ID_FILE_NEW, 0, NULL, NULL))
这句话是发送一条消息,这条消息最终调用了OnFileNew();
10. void CWinApp::OnFileNew() --> m_pDocManager->OnFileNew();进去
11. void CDocManager::OnFileNew()
12. pTemplate->OpenDocumentFile(NULL); 进去
13. CDocument* CSingleDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName,
14. pDocument = CreateNewDocument(); 创建了文档!! 以后有用
15. pFrame = CreateNewFrame(pDocument, NULL); 创建框架 进去
16. 在CDocTemplate::CreateNewFrame(CDocument* pDoc, CFrameWnd* pOther)里面
CFrameWnd* pFrame = (CFrameWnd*)m_pFrameClass->CreateObject();创建框架类对象 进入构造函数
17. CFrameWnd::CFrameWnd() 出去
CMainFrame::CMainFrame() 我们可以确定在16里面创建的是CMainFrame这个对象,然后出去
18. 在CDocTemplate::CreateNewFrame(里面找到代码,其实是16的继续
if (!pFrame->LoadFrame(m_nIDResource,WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, NULL, &context)) 进去
19. BOOL CFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle,CWnd* pParentWnd, CCreateContext* pContext)
20. LPCTSTR lpszClass = GetIconWndClass(dwDefaultStyle, nIDResource); 进去 作用:在这个函数里面注册了窗口类,然后把窗口类的名称返回
21. HICON hIcon = ::LoadIcon(hInst, ATL_MAKEINTRESOURCE(nIDResource)); 加载图标
22. PreCreateWindow(cs); 因为这个方法是个虚函数,所以我们得根据this是谁才能判断调用的是哪个函数 现在的this是CMainFrame
23. BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) 将来我们可以在这个函数里面设置窗口类的属性 很重要!!!
24. BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT& cs) 在这个函数里面设置了默认的样式,然后跳出,然后跳出,回到了第20步的继续
25. 在LPCTSTR CFrameWnd::GetIconWndClass(DWORD dwDefaultStyle,里面有代码 -->
WNDCLASS wndcls;
看这里:AfxCtxGetClassInfo(AfxGetInstanceHandle(), cs.lpszClass, &wndcls) && 判断类是否存在 进去找了一遍,没有发现注册的代码,继续往下走
26. 看这里:AfxRegisterWndClass(wndcls.style,wndcls.hCursor, wndcls.hbrBackground, hIcon);
27. LPCTSTR AFXAPI AfxRegisterWndClass(UINT nClassStyle,
HCURSOR hCursor, HBRUSH hbrBackground, HICON hIcon)
28. if (::AfxCtxGetClassInfo(hInst, lpszName, &wndcls)) 制作窗口类的类名
29. 窗口注册的代码!! 终于找到了
wndcls.style = nClassStyle;
wndcls.lpfnWndProc = DefWindowProc;
wndcls.cbClsExtra = wndcls.cbWndExtra = 0;
wndcls.hInstance = hInst;
wndcls.hIcon = hIcon;
wndcls.hCursor = hCursor;
wndcls.hbrBackground = hbrBackground;
wndcls.lpszMenuName = NULL;
wndcls.lpszClassName = lpszName;
30. if (!AfxRegisterClass(&wndcls)) 进去
31. BOOL AFXAPI AfxRegisterClass(WNDCLASS* lpWndClass)
32. if (!::AfxCtxRegisterClass(lpWndClass)) 注册窗口类
这里的注册跟win32里面的注册有一些区别!!! 终于找到了窗口类的注册的全部代码
33. 注册成功,开始穿越(穿越的时候把窗口类的名字带回去了)
BOOL CFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle,
CWnd* pParentWnd, CCreateContext* pContext)
LPCTSTR lpszClass = GetIconWndClass(dwDefaultStyle, nIDResource);
------------------------------------------------------------------------------------------------------------------
34. if (!Create(lpszClass, strTitle, dwDefaultStyle, rectDefault,
pParentWnd, ATL_MAKEINTRESOURCE(nIDResource), 0L, pContext)) 进去看窗口创建的过程
35. BOOL CFrameWnd::Create(LPCTSTR lpszClassName,
36. if (!CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle, 进去
37. BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName, //创建工具菜单状态条之类的
38. CREATESTRUCT cs;
cs.dwExStyle = dwExStyle;
cs.lpszClass = lpszClassName;
cs.lpszName = lpszWindowName;
cs.style = dwStyle;
cs.x = x;
cs.y = y;
cs.cx = nWidth;
cs.cy = nHeight;
cs.hwndParent = hWndParent;
cs.hMenu = nIDorHMenu;
cs.hInstance = AfxGetInstanceHandle();
cs.lpCreateParams = lpParam;
这里的信息是用于创建窗口的!!!
39. if (!PreCreateWindow(cs)) 第2次调用了CMainFrame::PreCreateWindow 为什么要两次调用PreCreateWindow? //预创造窗口
第一次调用: cs用于窗口类注册
第二次调用: cs用于改变窗口风格调用一次
39. AfxHookWindowCreate(this); 在这里下了窗口的钩子,最后把窗口的消息都钩到了AfxWndProc里面去处理了
40. HWND hWnd = ::AfxCtxCreateWindowEx(cs.dwExStyle, cs.lpszClass,
窗口已经创建成功!!!!
重要:cs参数包含了窗口注册和窗口创建的基本信息
消息走向:
1. AfxWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam) MFC消息的入口点
2. CWnd* pWnd = CWnd::FromHandlePermanent(hWnd); 把句柄变成对象
3. AfxCallWndProc(pWnd, hWnd, nMsg, wParam, lParam); 调用处理函数
4. LRESULT AFXAPI AfxCallWndProc(CWnd* pWnd, HWND hWnd, UINT nMsg,
5. lResult = pWnd->WindowProc(nMsg, wParam, lParam); 消息从这里开始就面向对象了
6. LRESULT CWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
7. if (!OnWndMsg(message, wParam, lParam, &lResult))
8. BOOL CWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
9. if (message == WM_COMMAND)
10. if (message == WM_NOTIFY)
11. 标准消息怎么办 while(){for(){}}
命令传递
1. if (OnCommand(wParam, lParam))
2. BOOL CWnd::OnCommand(WPARAM wParam, LPARAM lParam) 命令消息都会走这个,命令消息的对象可能是FrameWnd
3. OnCmdMsg(nID, CN_UPDATE_COMMAND_UI, &state, NULL); 这个方法是一个虚函数,他会调用谁了
4. BOOL CFrameWnd::OnCmdMsg(UINT nID, int nCode, void* pExtra, 首先走了CFrameWnd::OnCmdMsg
5. 有三个分支
5.1 CView* pView = GetActiveView(); View
5.2 if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) --> CCmdTarget::OnCmdMsg
5.3 if (pApp != NULL && pApp->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
6. 走CView::OnCmdMsg 有两个分支
6.1 if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) 自己
6.2 return m_pDocument->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
7. 走CDocument::OnCmdMsg 有两个分支
7.1 if (CCmdTarget::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) 自己
7.2 m_pDocTemplate->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
命令消息的传递过程: CView --> CDocument --> CDocTemplate --> CFrameWnd --> CWinApp
1. AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow); //MFC消息入口函数
2. AfxWinMain()
3. if (!pThread->InitInstance()) 线程初始化 进去
4. pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME, //单文档模板 ,1.菜单名称,2.文档,3框架,4视图
RUNTIME_CLASS(CDemoDoc),
RUNTIME_CLASS(CMainFrame), // 主 SDI 框架窗口
RUNTIME_CLASS(CDemoView));
5. CDocTemplate::CDocTemplate 进去 然后按F11进基类的构造函数
6. LoadTemplate(); 装载文档模板
7. void CDocTemplate::LoadTemplate() 跳出 逃到了第4步的继续
8. 现在在BOOL CDemoApp::InitInstance()里面 是第4步的继续 --> if (!ProcessShellCommand(cmdInfo)) 调度命令,相当于点击word打开 默认filenew新建 不让nothing
====F1进去
注册在这里!!
9. 在CWinApp::ProcessShellCommand(CCommandLineInfo& rCmdInfo)里面 找到 if (!AfxGetApp()->OnCmdMsg(ID_FILE_NEW, 0, NULL, NULL))
这句话是发送一条消息,这条消息最终调用了OnFileNew();
10. void CWinApp::OnFileNew() --> m_pDocManager->OnFileNew();进去
11. void CDocManager::OnFileNew()
12. pTemplate->OpenDocumentFile(NULL); 进去
13. CDocument* CSingleDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName,
14. pDocument = CreateNewDocument(); 创建了文档!! 以后有用
15. pFrame = CreateNewFrame(pDocument, NULL); 创建框架 进去
16. 在CDocTemplate::CreateNewFrame(CDocument* pDoc, CFrameWnd* pOther)里面
CFrameWnd* pFrame = (CFrameWnd*)m_pFrameClass->CreateObject();创建框架类对象 进入构造函数
17. CFrameWnd::CFrameWnd() 出去
CMainFrame::CMainFrame() 我们可以确定在16里面创建的是CMainFrame这个对象,然后出去
18. 在CDocTemplate::CreateNewFrame(里面找到代码,其实是16的继续
if (!pFrame->LoadFrame(m_nIDResource,WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, NULL, &context)) 进去
19. BOOL CFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle,CWnd* pParentWnd, CCreateContext* pContext)
20. LPCTSTR lpszClass = GetIconWndClass(dwDefaultStyle, nIDResource); 进去 作用:在这个函数里面注册了窗口类,然后把窗口类的名称返回
21. HICON hIcon = ::LoadIcon(hInst, ATL_MAKEINTRESOURCE(nIDResource)); 加载图标
22. PreCreateWindow(cs); 因为这个方法是个虚函数,所以我们得根据this是谁才能判断调用的是哪个函数 现在的this是CMainFrame
23. BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) 将来我们可以在这个函数里面设置窗口类的属性 很重要!!!
24. BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT& cs) 在这个函数里面设置了默认的样式,然后跳出,然后跳出,回到了第20步的继续
25. 在LPCTSTR CFrameWnd::GetIconWndClass(DWORD dwDefaultStyle,里面有代码 -->
WNDCLASS wndcls;
看这里:AfxCtxGetClassInfo(AfxGetInstanceHandle(), cs.lpszClass, &wndcls) && 判断类是否存在 进去找了一遍,没有发现注册的代码,继续往下走
26. 看这里:AfxRegisterWndClass(wndcls.style,wndcls.hCursor, wndcls.hbrBackground, hIcon);
27. LPCTSTR AFXAPI AfxRegisterWndClass(UINT nClassStyle,
HCURSOR hCursor, HBRUSH hbrBackground, HICON hIcon)
28. if (::AfxCtxGetClassInfo(hInst, lpszName, &wndcls)) 制作窗口类的类名
29. 窗口注册的代码!! 终于找到了
wndcls.style = nClassStyle;
wndcls.lpfnWndProc = DefWindowProc;
wndcls.cbClsExtra = wndcls.cbWndExtra = 0;
wndcls.hInstance = hInst;
wndcls.hIcon = hIcon;
wndcls.hCursor = hCursor;
wndcls.hbrBackground = hbrBackground;
wndcls.lpszMenuName = NULL;
wndcls.lpszClassName = lpszName;
30. if (!AfxRegisterClass(&wndcls)) 进去
31. BOOL AFXAPI AfxRegisterClass(WNDCLASS* lpWndClass)
32. if (!::AfxCtxRegisterClass(lpWndClass)) 注册窗口类
这里的注册跟win32里面的注册有一些区别!!! 终于找到了窗口类的注册的全部代码
33. 注册成功,开始穿越(穿越的时候把窗口类的名字带回去了)
BOOL CFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle,
CWnd* pParentWnd, CCreateContext* pContext)
LPCTSTR lpszClass = GetIconWndClass(dwDefaultStyle, nIDResource);
------------------------------------------------------------------------------------------------------------------
34. if (!Create(lpszClass, strTitle, dwDefaultStyle, rectDefault,
pParentWnd, ATL_MAKEINTRESOURCE(nIDResource), 0L, pContext)) 进去看窗口创建的过程
35. BOOL CFrameWnd::Create(LPCTSTR lpszClassName,
36. if (!CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle, 进去
37. BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName, //创建工具菜单状态条之类的
38. CREATESTRUCT cs;
cs.dwExStyle = dwExStyle;
cs.lpszClass = lpszClassName;
cs.lpszName = lpszWindowName;
cs.style = dwStyle;
cs.x = x;
cs.y = y;
cs.cx = nWidth;
cs.cy = nHeight;
cs.hwndParent = hWndParent;
cs.hMenu = nIDorHMenu;
cs.hInstance = AfxGetInstanceHandle();
cs.lpCreateParams = lpParam;
这里的信息是用于创建窗口的!!!
39. if (!PreCreateWindow(cs)) 第2次调用了CMainFrame::PreCreateWindow 为什么要两次调用PreCreateWindow? //预创造窗口
第一次调用: cs用于窗口类注册
第二次调用: cs用于改变窗口风格调用一次
39. AfxHookWindowCreate(this); 在这里下了窗口的钩子,最后把窗口的消息都钩到了AfxWndProc里面去处理了
40. HWND hWnd = ::AfxCtxCreateWindowEx(cs.dwExStyle, cs.lpszClass,
窗口已经创建成功!!!!
重要:cs参数包含了窗口注册和窗口创建的基本信息
消息走向:
1. AfxWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam) MFC消息的入口点
2. CWnd* pWnd = CWnd::FromHandlePermanent(hWnd); 把句柄变成对象
3. AfxCallWndProc(pWnd, hWnd, nMsg, wParam, lParam); 调用处理函数
4. LRESULT AFXAPI AfxCallWndProc(CWnd* pWnd, HWND hWnd, UINT nMsg,
5. lResult = pWnd->WindowProc(nMsg, wParam, lParam); 消息从这里开始就面向对象了
6. LRESULT CWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
7. if (!OnWndMsg(message, wParam, lParam, &lResult))
8. BOOL CWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
9. if (message == WM_COMMAND)
10. if (message == WM_NOTIFY)
11. 标准消息怎么办 while(){for(){}}
命令传递
1. if (OnCommand(wParam, lParam))
2. BOOL CWnd::OnCommand(WPARAM wParam, LPARAM lParam) 命令消息都会走这个,命令消息的对象可能是FrameWnd
3. OnCmdMsg(nID, CN_UPDATE_COMMAND_UI, &state, NULL); 这个方法是一个虚函数,他会调用谁了
4. BOOL CFrameWnd::OnCmdMsg(UINT nID, int nCode, void* pExtra, 首先走了CFrameWnd::OnCmdMsg
5. 有三个分支
5.1 CView* pView = GetActiveView(); View
5.2 if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) --> CCmdTarget::OnCmdMsg
5.3 if (pApp != NULL && pApp->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
6. 走CView::OnCmdMsg 有两个分支
6.1 if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) 自己
6.2 return m_pDocument->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
7. 走CDocument::OnCmdMsg 有两个分支
7.1 if (CCmdTarget::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) 自己
7.2 m_pDocTemplate->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
命令消息的传递过程: CView --> CDocument --> CDocTemplate --> CFrameWnd --> CWinApp