windows底层 API 是由C语言写的,而MFC则是在此基础上通过C++进行了封装。
要想利用MFC进行编程,那么就得从main方法开始
MFC的main函数C的写法是
温馨小提示:函数变量名如果带有p的一般都是指针,入参的时候的传地址
#include <Windows.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPTSTR lpCmdLine, int nShowCmd) {
// 主程序内容。。。
}
下面是c++的写法
#include <Windows.h>
extern "C" int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPTSTR lpCmdLine, int nShowCmd) {
// 主程序内容。。。
}
需要注意的是MFC的函数得加上 宏定义WINAPI
表示参数的传递顺序,参数从右到左依次入栈,函数return前清空函数栈
- hInstance 当前音乐实例句柄
- hPrevInstance 上一个音乐程序句柄,在win32环境下一般为NULL
- lpCmdLine 类型LPTSTR 等同于 char* args[]
- nShowCmd 显示的命令 最大化、最小化、正常
写一个窗口程序主要分为
- 设计窗口
- 注册窗口
- 创建窗口
- 显示和更新
- 循环获取消息
- 处理消息
一、设计一个窗口
实际上windows已经把窗口封装成了一个结构体WNDCLASS
,我们只需要对这个结构体内容进行补充,一个窗口类的信息就设置好了。
通过宏定义调整过去会发现结构体有下面这些内容
重复的内容不做额外解释
typedef struct tagWNDCLASSA {
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCSTR lpszMenuName;
LPCSTR lpszClassName;
} WNDCLASSA, *PWNDCLASSA, NEAR *NPWNDCLASSA, FAR *LPWNDCLASSA;
typedef struct tagWNDCLASSW {
UINT style; // 显示的风格(最大化、最小化、0 是默认值)
WNDPROC lpfnWndProc;// ==>窗口过程的回调函数(消息回调)
int cbClsExtra; // 类的额外的内存
int cbWndExtra; // 窗口额外的内存
HINSTANCE hInstance; // 应用程序实例句柄
HICON hIcon; // 窗口上方的图标
HCURSOR hCursor; // 光标,wc.hCursor = LoadCursor(NULL,IDC_HAND);第一个参数为NULL表示使用系统光标,第二个参数表示鼠标的形状(指针,小手等)
HBRUSH hbrBackground; // 背景,一般使用白色刷(HBRUSH) GetStockObject(WHITE_BRUSH);
LPCWSTR lpszMenuName; // 指定窗口类名称
LPCWSTR lpszClassName; // 指定才当名称
} WNDCLASSW, *PWNDCLASSW, NEAR *NPWNDCLASSW, FAR *LPWNDCLASSW;
#ifdef UNICODE
typedef WNDCLASSW WNDCLASS;
typedef PWNDCLASSW PWNDCLASS;
typedef NPWNDCLASSW NPWNDCLASS;
typedef LPWNDCLASSW LPWNDCLASS;
#else
typedef WNDCLASSA WNDCLASS;
typedef PWNDCLASSA PWNDCLASS;
typedef NPWNDCLASSA NPWNDCLASS;
typedef LPWNDCLASSA LPWNDCLASS;
#endif // UNICODE
二、注册窗口
温馨提示:在调用API的时候会发现有些方法带W 或 A,是由于编码导致API 不同所致,W是Unicode编码的、A是Ascii码编码的,实际上在使用的过程中没有太大区别
WNDCLASS wc;
wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);// 设置背景
// 注册窗口类
RegisterClass(&wc);
三、创建窗口
创建窗口的函数定义如下,这几个方法名称很相似,实际上使用起来基本上一直
W 与 A 的区别就子啊与编码的不同而已
#define CreateWindowA(lpClassName, lpWindowName, dwStyle, x, y,\
nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam)\
CreateWindowExA(0L, lpClassName, lpWindowName, dwStyle, x, y,\
nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam)
#define CreateWindowW(lpClassName, lpWindowName, dwStyle, x, y,\
nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam)\
CreateWindowExW(0L, lpClassName, lpWindowName, dwStyle, x, y,\
nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam)
#ifdef UNICODE
#define CreateWindow CreateWindowW
#else
#define CreateWindow CreateWindowA
#endif // !UNICODE
通过点击CreateWindow跳转过去会找到完整的定义
HWND CreateWindowW(
[in, optional] lpClassName, // 窗口类名字(带p表示指针),字符串char *
[in, optional] lpWindowName,// 窗口的名称(带p表示指针),字符串char *
[in] dwStyle, // WS_OVERLAPPEDWINDOW 风格
[in] x, // 显示窗口的坐标 CW_USEDEFAULT
[in] y, // (x,y)是窗口左上角那个点
[in] nWidth, // 窗口宽
[in] nHeight, // 窗口高
[in, optional] hWndParent, // 父窗口句柄,NULL
[in, optional] hMenu, // 窗口菜单句柄,NULL
[in, optional] hInstance, // 实例句柄hInstance(winMain传进来的那个)
[in, optional] lpParam // 鼠标附加值,左右键
);
四、显示和更新窗口
五、循环获取消息
首先需要明白消息的结构内容,消息定义如下
消息结构体
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES)
/*
* Message structure
*/
typedef struct tagMSG {
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
#ifdef _MAC
DWORD lPrivate;
#endif
} MSG, *PMSG, NEAR *NPMSG, FAR *LPMSG;
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES) */
获取消息的函数
WINUSERAPI
BOOL
WINAPI
GetMessageA(
_Out_ LPMSG lpMsg,
_In_opt_ HWND hWnd,
_In_ UINT wMsgFilterMin,
_In_ UINT wMsgFilterMax);
WINUSERAPI
BOOL
WINAPI
GetMessageW(
_Out_ LPMSG lpMsg, // 返回的消息
_In_opt_ HWND hWnd, // 捕获哪一个窗口的消息,如果为NULL则是捕获所有窗口消息,并且 min 和 max 为0
_In_ UINT wMsgFilterMin,// 想要捕获所有消息则 min 和 max 都设置为0
_In_ UINT wMsgFilterMax);
#ifdef UNICODE
#define GetMessage GetMessageW
#else
#define GetMessage GetMessageA
#endif // !UNICODE
完整的通过MFC创建一个窗口并且弹出一条消息
#include <afx.h>
#include <Windows.h>
// 消息处理函数
LRESULT CALLBACK Wndproc(
HWND hwnd, // 消息所属的窗口句柄
UINT uMsg, // 具体消息名称 WM_XXXX 消息名
WPARAM wparam,// 键盘附加消息
LPARAM lparam // 鼠标附加消息
) {
switch (uMsg) {
//点击关闭窗口的按钮,会发送一条WM_DESTROY消息
case WM_CLOSE:
DestroyWindow(hwnd);
break;
//处理销毁消息
case WM_DESTROY:
PostQuitMessage(0);//放弃后面所有消息(有结束窗口的含义)
break;
//鼠标左键弹起
case WM_LBUTTONUP:
//int x = LOWORD(lparam);
//int y = HIWORD(lparam);
//弹出一条消息对话框
MessageBox(hwnd, TEXT("弹出的消息"), TEXT("弹出框的标题"),MB_OK);
break;
}
// 默认的消息处理
return DefWindowProc(hwnd,uMsg,wparam,lparam);
}
extern "C" int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/,
LPTSTR /*lpCmdLine*/, int nShowCmd) {
//1、定义窗口
WNDCLASS wc;
wc.lpszClassName = TEXT("WINDEMO");
wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
wc.hCursor = LoadCursor(NULL, IDC_HAND);
wc.hIcon = LoadIcon(NULL, IDI_ERROR);
wc.hInstance = hInstance;
wc.style = 0;
wc.lpszMenuName = NULL;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.lpfnWndProc = Wndproc;
//2、注册窗口
RegisterClass(&wc);
// 创建窗口,宽高都为300,窗口标题为demo
HWND hwnd = CreateWindowW(wc.lpszClassName, TEXT("demo"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
300, 300, NULL, NULL, hInstance, NULL);
//3、显示与更新窗口
ShowWindow(hwnd, SW_SHOWNORMAL);
UpdateWindow(hwnd);
//4、循环获取消息
MSG msg;
while (true) {
if (GetMessage(&msg, NULL, 0, 0) == FALSE) {
break;
}
// 翻译消息
TranslateMessage(&msg);
// 分发消息
DispatchMessage(&msg);
}
return 0;
}