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前清空函数栈
写一个窗口程序主要分为
实际上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 // 鼠标附加值,左右键
- );
-
- //3、显示与更新窗口
- ShowWindow(hwnd, SW_SHOWNORMAL);
- UpdateWindow(hwnd);
-
首先需要明白消息的结构内容,消息定义如下
消息结构体
- #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
-
点击关闭窗口会调用DestroyWindow 进而触发WM_DESTROY消息,通过PostQuitMessage(0)才真正的关闭了窗口
- #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);//鼠标的x轴
- int y = HIWORD(lparam);//鼠标的y轴位置
- CString str;
- // 将坐标信息,通过字符串格式化
- str.Format(TEXT("弹出的消息:鼠标坐标x=%d,y=%d"),x,y);
- MessageBox(hwnd, str,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;
- }
-