1. 首先,贴一个简单的Win32的Hello World程序,这是学MFC的基础。
如果没有学过Win32,请自行补充相关知识。
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nShowCmd)
{
static TCHAR lpszAppName[] = TEXT("HelloWin");
HWND hwnd;
MSG msg;
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = lpszAppName;
// 注册窗口类
if (!RegisterClass(&wc))
{
MessageBox(NULL, TEXT("This program requires Windows NT!"),
lpszAppName, MB_ICONERROR);
return 0;
}
// 创建应用程序主窗口
hwnd = CreateWindow(lpszAppName,
TEXT("The Hello Program"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
// 显示窗口
ShowWindow(hwnd, nShowCmd);
UpdateWindow(hwnd);
// 消息循环
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
//
// 窗口过程函数
//
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
RECT rect;
switch (message)
{
case WM_CREATE:
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &rect);
DrawText(hdc, TEXT("Hello World!"), -1, &rect,
DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
2. MFC其实是微软对Win32 API的一个封装。
创建一个简单的MFC程序如Test后,整个程序的初始化及运行流程大致下:
CTestApp中定义theApp全局对象
—>执行父类CWinApp构造函数
—>执行子类本身构造函数
—>调用AfxWinMain函数
—>Afx函数中调用initInstance函数,包括注册窗口类、创建窗口、显示窗口等
—>进行消息循环
3. 程序框架
建立一个单文档MFC示例程序,程序就会包含:
CTestApp——应用程序类
CMainFrame、CTestView——窗体类,后者可看做前者的子类
CTestDoc——文档类
4. 注意事项:
MFC其实是对Win32 API函数的一些封装,比如CWnd类,我们自己也可以模拟这个封装过程。
下面是我自己写的一个模拟封装程序:
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
class CMyWnd
{
public:
BOOL MyCreateWindow(
LPCTSTR lpClassName,
LPCTSTR lpWindowName,
DWORD dwStyle,
int x,
int y,
int nWidth,
int nHeight,
HWND hWndParent,
HMENU hMenu,
HANDLE hInstance,
PVOID lpParam
);
BOOL MyShowWindow(int nCmdShow);
BOOL MyUpdateWindow();
HWND GetHwnd();
private:
HWND m_hwnd;
};
BOOL CMyWnd::MyCreateWindow(LPCTSTR lpClassName, LPCTSTR lpWindowName, DWORD dwStyle,
int x,int y, int nWidth, int nHeight,
HWND hWndParent, HMENU hMenu, HANDLE hInstance, LPVOID lpParam)
{
m_hwnd = ::CreateWindow(lpClassName,lpWindowName,dwStyle,
x,y,nWidth,nHeight,hWndParent,hMenu,(HINSTANCE)hInstance,lpParam);
if(NULL == m_hwnd)
return FALSE;
else
return TRUE;
}
BOOL CMyWnd::MyShowWindow(int nCmdShow)
{
return ::ShowWindow(m_hwnd, nCmdShow);
}
BOOL CMyWnd::MyUpdateWindow()
{
return ::UpdateWindow(m_hwnd);
}
HWND CMyWnd::GetHwnd()
{
return this->m_hwnd;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd )
{
MSG msg;
WNDCLASS wndclass;
CMyWnd wnd;
TCHAR szName[] = TEXT("Class Test");
//HWND hwnd;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hInstance = hInstance;
wndclass.lpfnWndProc = WndProc;
wndclass.lpszClassName = szName;
wndclass.lpszMenuName = NULL;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
if(!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("Need Window NT"), TEXT("Title"), MB_OK);
return 0;
}
//wnd = new CMyWnd;
wnd.MyCreateWindow(szName, TEXT("Window Test"), WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
NULL, NULL, hInstance, NULL);
//hwnd = wnd->GetHwnd();
wnd.MyShowWindow(nShowCmd);
wnd.MyUpdateWindow();
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
可见,CMyWnd窗口类其实 与 窗口无直接关系,他们之间的联系其实只是m_hwnd的存在;
窗口被销毁,并不会影响窗口类,微软MFC封装的CWnd类也是一样;
当然,我们这里只是简单的模拟,并不完善,当窗口类销毁时,MFC中会把相应的窗口也销毁。
5. 向MFC程序添加控件
这个比较简单,可以再CMainFrame类中定义一个CButton的对象,然后在该类的构造函数中初始化这个成员对象。
当然,也可以在CTestView类写,可以给它写个相应WM_CRAETE的OnCreate函数即可;
首先在CTestView头文件中添加:
private:
CButton m_btn;
然后在CTestView定义文件中添加:
// CTest1View message handlers
int CTest1View::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
m_btn.Create(TEXT("World"), WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, CRect(0,0,50,20), this, 124);
return 0;
}
这个过程其实可以使用VC自带的生成工具来写,不用我们完全手动编辑。