1.MFC:microsoft funcation class
2.新建一个MFC工程选择单文档-MFC标准类型的项目,产生出来直接编译就能产生一个窗口。所有的都是类,程序的入口Winmain在哪里呢?在VS安装目录下找到appmodul.cpp设置断点在_twWinMain处发现程序停止。所以新建的MFC程序会自动去调用这里的WinMain函数。
3.选择类视图可以看到:CTestView(窗口类),CTestDoc(文档类),CTesApp(应用程序类),CMainFrame(窗口类),CAboutDlg(窗口类).
打开CTestApp的构造函数:选择CTestApp。在左边框下方点击构造函数CTestApp()设置断点发现:程序先进入构造函数再进入WinMain函数。原因是因为在程序Test.cpp中定义了一个CTestApp类型的全局变量。因为全局变量在进入main之前就分配好了内存空间。
4.如何唯一的表示这个应用程序。在LESSON1中是通过WinMain中分配的实例号来唯一的表示应用程序。而这里是通过创建一个唯一的CTestApp全局对象来表示应用程序本身。用户编写的程序要实例化一个应用程序(全局变量)就必须要构造函数CTestApp(),构造这个子类时就要先构造基类CWinApp()。作为桥梁就使应用程序和微软提供的CWinApp和winmain联系了起来。
5.CWinApp:在appcore.cpp当中。创建一个CTestApp时,会调用基类的构造函数CWinApp(),这个构造函数中的this指针此时是指向派生类对象theApp的指针。因为这时调用的CWinApp()被看做是CTestApp的一部分。
6.AfxWinMain()在WINMAIN.cpp当中。Af:app framework,表示应用程序框架模型,使各个类有机的结合在一起。在主函数中调用initinstance结果会去调用子类的initinstance(),并且在这一部分实现窗口的注册创建,显示和更新。
AfxWinMain()
{...
CWinThread* pThread=AfxGetThread();
CWinApp* pApp=AfxGetApp();//获得一个指向CWinApp的指针,实际上就是指向theApp。
if (!pThread->InitInstance())//这里调用子类的InitInstance()
{
if (pThread->m_pMainWnd != NULL)
{
TRACE(traceAppMsg, 0, "Warning: Destroying non-NULL m_pMainWnd\n");
pThread->m_pMainWnd->DestroyWindow();
}
nReturnCode = pThread->ExitInstance();
goto InitFailure;
}
nReturnCode = pThread->Run();//调用消息循环
...
}
CTestApp::InitInstance()
{
if(!ProcessShellCommand(cmdInfo))//这一部分创建注册窗口
return FALSE;
m_pMainWnd->ShowWindow(SW_SHOW);//展示窗口
m_pMainWnd->UpdateWindow();//更新窗口
return TRUE;
}
7.在MAIN函数中会调用注册窗口类函数。
注册窗口类wincore.cpp当中有函数AfxEndDeferGegisterClass.
MFC已经内部自己定义好了不同的窗口类,并不需要用户自己去定义。只需要用户去注册对应的窗口类。
if (fToRegister & AFX_WNDFRAMEORVIEW_REG)
{
// SDI Frame or MDI Child windows or views - normal colors
wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
wndcls.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
if (_AfxRegisterWithIcon(&wndcls, _afxWndFrameOrView, AFX_IDI_STD_FRAME))
fRegisteredClasses |= AFX_WNDFRAMEORVIEW_REG;
}
8.产生窗口
CMainFrame:框架窗口,整个应用程序的窗口。另外还有CView窗口。他们都是从CWnd派生出来的,所以都是窗口类。
正常情况下会在preCreateWindow这里才注册,但因为是是单文档MFC所以注册窗口类提前了。
调用CFramewnd中的Create函数,会进一步调用CWND的CreateEX函数。
用户可以修改CREATESTRUCT结构体调用PreCreateWindow,在创建窗口之前可以有机会去修改默认的窗口外观。
9.消息循环:主函数当中的RUN();
thrdcore.cpp当中有CWinThread::Run()
int CWinThread::Run()
{
ASSERT_VALID(this);
_AFX_THREAD_STATE* pState = AfxGetThreadState();
// for tracking the idle time state
BOOL bIdle = TRUE;
LONG lIdleCount = 0;
// acquire and dispatch messages until a WM_QUIT message is received.
for (;;)
{...
// phase2: pump messages while available
do
{
// pump message, but quit on WM_QUIT
if (!PumpMessage())//Get Message, Translate Message,
return ExitInstance();
...
} while (::PeekMessage(&(pState->m_msgCur), NULL, NULL, NULL, PM_NOREMOVE));
}
}
10.消息循环:主函数当中的RUN();
11.窗口与窗口类
窗口类都是从CWnd派生来的。窗口类其实只是一个句柄。窗口销毁并不代表窗口类销毁。
#include <windows.h>
class CWnd
{
public:
BOOL CreateEx(
DWORD dwExStyle,//窗口的扩展风格
LPCTSTR lpClassName,//指向注册类名的指针
LPCTSTR lpWindowName,//指向窗口名称的指针
DWORD dwStyle,//窗口风格
int x,//窗口的水平位置
int y,//窗口的垂直位置
int nWidth,//窗口的宽度
int nHeight,//窗口的高度
HWND hWndParent,//父窗口的句柄
HMENU hMenu,//菜单的句柄或是子窗口的标识符
HINSTANCE hInstance,//应用程序实例的句柄
LPVOID lpParam//指向窗口的创建数据
);
BOOL ShowWindow(int nCmdShow);
BOOL UpdateWindow();
public:
HWND m_hWnd;
};
BOOL CWnd::CreateEx(DWORD dwExStyle,//窗口的扩展风格
LPCTSTR lpClassName,//指向注册类名的指针
LPCTSTR lpWindowName,//指向窗口名称的指针
DWORD dwStyle,//窗口风格
int x,//窗口的水平位置
int y,//窗口的垂直位置
int nWidth,//窗口的宽度
int nHeight,//窗口的高度
HWND hWndParent,//父窗口的句柄
HMENU hMenu,//菜单的句柄或是子窗口的标识符
HINSTANCE hInstance,//应用程序实例的句柄
LPVOID lpParam)//指向窗口的创建数据
{
m_hWnd = ::CreateWindowEx(dwExStyle,lpClassName,lpWindowName,dwStyle,x,y,nWidth,
nHeight,hWndParent,hMenu,hInstance,lpParam);
if(m_hWnd!=NULL)
return TRUE;
else
return FALSE;
}
BOOL CWnd::ShowWindow(int nCmdShow)
{
return ::ShowWindow(m_hWnd,nCmdShow);
}
BOOL CWnd::UpdateWindow()
{
return ::UpdateWindow(m_hWnd);
}
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
WNDCLASS wndcls;
wndcls.cbClsExtra=0;
wndcls.cbWndExtra=0;
...
RegisterClass(&wndcls);
CWnd wnd;
wnd.CreateEx(...);
wnd.ShowWindow(SW_SHOWNORMAL);
wnd.UpdateWindow();
...
}
在CMainFrame中添加一个新的成员:CButton m_btn;然后在On_Create()里产生副窗口。
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
if (!m_wndStatusBar.Create(this))
{
TRACE0("未能创建状态栏\n");
return -1; // 未能创建
}
m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT));
m_btn.Create(TEXT("nino"),WS_CHILD|BS_DEFPUSHBUTTON,CRect(0,0,100,100),this,9);
m_btn.ShowWindow(SW_SHOWNORMAL);
return 0;
}
如果要在CView里添加button,而CView里没有ON_Create成员函数(用来响应窗口创建消息的函数)。
在CView里右键选择类向导。在消息里选择WM_CREATE并且添加处理程序就在CView里添加了ON_Create函数。