此专栏为移动机器人知识体系下的编程语言中的 C {\rm C} C++从入门到深入的专栏,参考书籍:《深入浅出 C {\rm C} C++》(马晓锐)和《从 C {\rm C} C到 C {\rm C} C++精通面向对象编程》(曾凡锋等)。
14.API编程和MFC框架简介
14.1 API基础
-
视窗操作系统应用程序接口 ( W i n d o w s A P I , W i n A P I ) ({\rm Windows\ API,Win\ API}) (Windows API,Win API),是微软公司对于 W i n d o w s {\rm Windows} Windows操作系统中可用的内核应用程序编程接口的称法;
-
A P I {\rm API} API基本程序( W i n 32 A p p l i c a t i o n {\rm Win32\ Application} Win32 Application程序):用 V i s u a l S t u d i o {\rm Visual\ Studio} Visual Studio生成框架。
// Win32App.cpp : 定义应用程序的入口点。 //#include "framework.h" #include "Win32App.h"#define MAX_LOADSTRING 100// 全局变量: HINSTANCE hInst; // 当前实例 WCHAR szTitle[MAX_LOADSTRING]; // 标题栏文本 WCHAR szWindowClass[MAX_LOADSTRING]; // 主窗口类名// 此代码模块中包含的函数的前向声明: ATOM MyRegisterClass(HINSTANCE hInstance); BOOL InitInstance(HINSTANCE, int); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);int APIENTRY wWinMain(_In_ HINSTANCE hInstance,_In_opt_ HINSTANCE hPrevInstance,_In_ LPWSTR lpCmdLine,_In_ int nCmdShow) {UNREFERENCED_PARAMETER(hPrevInstance);UNREFERENCED_PARAMETER(lpCmdLine);// TODO: 在此处放置代码。// 初始化全局字符串LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);LoadStringW(hInstance, IDC_WIN32APP, szWindowClass, MAX_LOADSTRING);MyRegisterClass(hInstance);// 执行应用程序初始化:if (!InitInstance (hInstance, nCmdShow)){return FALSE;}HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WIN32APP));MSG msg;// 主消息循环:while (GetMessage(&msg, nullptr, 0, 0)){if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)){TranslateMessage(&msg);DispatchMessage(&msg);}}return (int) msg.wParam; }// // 函数: MyRegisterClass() // // 目标: 注册窗口类。 // ATOM MyRegisterClass(HINSTANCE hInstance) {WNDCLASSEXW wcex;wcex.cbSize = sizeof(WNDCLASSEX);wcex.style = CS_HREDRAW | CS_VREDRAW;wcex.lpfnWndProc = WndProc;wcex.cbClsExtra = 0;wcex.cbWndExtra = 0;wcex.hInstance = hInstance;wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WIN32APP));wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_WIN32APP);wcex.lpszClassName = szWindowClass;wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));return RegisterClassExW(&wcex); }// // 函数: InitInstance(HINSTANCE, int) // // 目标: 保存实例句柄并创建主窗口 // // 注释: // // 在此函数中,我们在全局变量中保存实例句柄并 // 创建和显示主程序窗口。 // BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) {hInst = hInstance; // 将实例句柄存储在全局变量中HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);if (!hWnd){return FALSE;}ShowWindow(hWnd, nCmdShow);UpdateWindow(hWnd);return TRUE; }// // 函数: WndProc(HWND, UINT, WPARAM, LPARAM) // // 目标: 处理主窗口的消息。 // // WM_COMMAND - 处理应用程序菜单 // WM_PAINT - 绘制主窗口 // WM_DESTROY - 发送退出消息并返回 // // LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {switch (message){case WM_COMMAND:{int wmId = LOWORD(wParam);// 分析菜单选择:switch (wmId){case IDM_ABOUT:DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);break;case IDM_EXIT:DestroyWindow(hWnd);break;default:return DefWindowProc(hWnd, message, wParam, lParam);}}break;case WM_PAINT:{PAINTSTRUCT ps;HDC hdc = BeginPaint(hWnd, &ps);// TODO: 在此处添加使用 hdc 的任何绘图代码...EndPaint(hWnd, &ps);}break;case WM_DESTROY:PostQuitMessage(0);break;default:return DefWindowProc(hWnd, message, wParam, lParam);}return 0; }// “关于”框的消息处理程序。 INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {UNREFERENCED_PARAMETER(lParam);switch (message){case WM_INITDIALOG:return (INT_PTR)TRUE;case WM_COMMAND:if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL){EndDialog(hDlg, LOWORD(wParam));return (INT_PTR)TRUE;}break;}return (INT_PTR)FALSE; }
-
W i n 32 A P I {\rm Win32\ API} Win32 API是 M i c r o s o f t W i n d o w s 32 {\rm Microsoft\ Windows\ 32} Microsoft Windows 32位平台的应用程序编程接口, M i c r o s o f t {\rm Microsoft} Microsoft提供了一系列 A P I {\rm API} API函数供程序开发者开发 W i n d o w s {\rm Windows} Windows应用程序;
-
W i n d o w s A P I {\rm Windows\ API} Windows API的分类:窗口管理、窗口通用控制、 S h e l l {\rm Shell} Shell特性、图形设备接口、系统服务、国际特性、网络服务,这些 A P I {\rm API} API提供了以下功能:
- 基础服务 ( b a s e s e r v i c e s ) ({\rm base\ services}) (base services) A P I {\rm API} API:对 W i n d o w s {\rm Windows} Windows系统的基础资源进行访问,如对文件系统、外部设备、进程、线程、注册表等的访问;
- 图形设备接口 ( G r a p h i c s D e v i c e I n t e r f a c e , G D I ) ({\rm Graphics\ Device\ Interface,GDI}) (Graphics Device Interface,GDI) A P I {\rm API} API:在显示器、打印机及其他外部输出设备上绘制图形;
- 图形化用户界面 ( G r a p h i c a l U s e r I n t e r f a c e , G U I ) ({\rm Graphical\ User\ Interface,GUI}) (Graphical User Interface,GUI) A P I {\rm API} API:建立与管理屏幕和大多数基本控件、接收鼠标和键盘输入等;
- 通用对话框链接库 ( c o m m o n d i a l o g b o x l i b r a r y ) ({\rm common\ dialog\ box\ library}) (common dialog box library) A P I {\rm API} API:提供应用程序标准的对话框,如打开/保存文件对话框、字体对话框等;
- 通用控件链接库 ( c o m m o n c o n t r o l l i b r a r y ) ({\rm common\ control\ library}) (common control library) A P I {\rm API} API:提供操作系统级别的高级控件,如状态栏、进度条、工具栏等;
- W i n d o w s {\rm Windows} Windows外壳 ( W i n d o w s S h e l l ) ({\rm Windows\ Shell}) (Windows Shell) A P I {\rm API} API:提供应用程序实现对操作系统的访问;
- 网络服务 ( n e t w o r k s e r v i c e s ) ({\rm network\ services}) (network services) A P I {\rm API} API:提供网络功能接口,如 N e t B I O S 、 W i n s o c k {\rm NetBIOS、Winsock} NetBIOS、Winsock等;
- W e b {\rm Web} Web相关 A P I {\rm API} API:为网页浏览器提供许多应用程序接口;
- 多媒体相关 A P I {\rm API} API:为多媒体服务和游戏服务提供接口;
- 程序通信 A P I {\rm API} API:提供不同应用程序的通信接口;
-
基本术语:
- 句柄:句柄本身是 W i n d o w s {\rm Windows} Windows在内存中的一个 4 4 4字节长的数值,用于标识应用程序中不同对象和相同对象的不同实例,常见的 A P I {\rm API} API句柄如下:
- H W N D {\rm HWND} HWND:窗口句柄;
- H I N S T A N C E {\rm HINSTANCE} HINSTANCE:类实例句柄;
- H C O U R S O R {\rm HCOURSOR} HCOURSOR:光标句柄;
- H M E N U {\rm HMENU} HMENU:菜单句柄;
- H F I L E {\rm HFILE} HFILE:文件句柄;
- 消息:指操作系统向某个程序发出的一个通知,告知应用程序某个事件发生了,如单击鼠标、按下键盘时, W i n d o w s {\rm Windows} Windows会发送一个消息给应用程序,告知应用程序这些事件发生了。
- 消息处理机制:指 W i n d o w s {\rm Windows} Windows处理消息的方法和规则, W i n d o w s {\rm Windows} Windows有一套完整的消息处理机制, W i n d o w s {\rm Windows} Windows的消息处理机制由以下三部分组成:
- 消息队列: W i n d o w s {\rm Windows} Windows为每个应用程序生成一个消息队列,应用程序只能从消息队列中获取消息,然后分派给某个窗口;
- 消息循环:通过循环机制,应用程序可以从消息队列中检索消息,再把消息分配给特定的窗口,之后继续从消息队列检索下一条消息,再分配给特定的窗口,只要消息队列中有消息,循环就一直执行;
- 窗口过程:每个窗口都有一个窗口过程来接收传递给窗口的消息,其任务是获取消息,然后进行响应,窗口过程是一个回调函数,回调函数对信息进行处理,处理完成后返回一个值给 W i n d o w s {\rm Windows} Windows;
- 句柄:句柄本身是 W i n d o w s {\rm Windows} Windows在内存中的一个 4 4 4字节长的数值,用于标识应用程序中不同对象和相同对象的不同实例,常见的 A P I {\rm API} API句柄如下:
-
W i n d o w s {\rm Windows} Windows典型的消息处理过程如下图:
- 增加消息:操作系统接收到应用程序的窗口消息,将消息保存到该应用程序的消息队列中;
- 取消息:应用程序从消息队列中取出一条消息,取出消息后,应用程序先对消息进行一些预处理,如是否放弃对此消息的处理等,然后进行下一步处理;
- 消息回传给操作系统:应用程序将消息再次传递给操作系统;
- 发送消息:操作系统把消息发送给应用程序,窗口过程对此消息进行响应;
14.2 MFC框架基础
- M F C {\rm MFC} MFC框架给开发者定义了一个应用程序的基本框架,并提供了许多用户和系统接口的标准实现方法,开发者只要完善预定义的接口,即可完成一个应用程序的编写;
- 众多由 C {\rm C} C++编写的 M F C {\rm MFC} MFC类库组成了 M F C {\rm MFC} MFC框架,这些类库封装了大量 W i n 32 {\rm Win32} Win32应用程序接口和概念,特点是具有很高的封装性;
- M F C {\rm MFC} MFC抽象出许多类的共同特性设计出一些具有普遍意义的基础类,这些类通过派生形成了许多实用的类;
- M F C {\rm MFC} MFC抽象类中, C O b j e c t {\rm CObject} CObject和 C C m d T a r g e t {\rm CCmdTarget} CCmdTarget是核心的类, C O b j e c t {\rm CObject} CObject是 M F C {\rm MFC} MFC所有类的基类, C C m d T a r g e t {\rm CCmdTarget} CCmdTarget是消息类的基类;
- 一个 M F C {\rm MFC} MFC程序由许多对象组成,常见的几个重要的对象:
- 窗口对象:基类是 C W n d {\rm CWnd} CWnd,负责处理窗口对象;
- 应用程序对象:基类是 C W i n T h r e a d {\rm CWinThread} CWinThread,负责处理应用程序对象;
- 文档对象:基类是 C D o c u m e n t {\rm CDocument} CDocument,负责处理应用程序的文档对象;
- M F C {\rm MFC} MFC通过封装、继承等技术为开发者提供了一整套应用程序开发模板,常用的几个模板:
- 单文档应用程序模板:只有一个文档区的应用程序,如: W i n d o w s {\rm Windows} Windows的画板程序属于单文档应用程序;
- 多文档应用程序模板:在一个程序中,可以产生多个文档区的应用程序( M i c r o s o f t {\rm Microsoft} Microsoft的 O f f i c e {\rm Office} Office产品中的 W o r d {\rm Word} Word应用程序属于多文档应用程序);
- 基于对话框应用程序模板:应用程序没有文档的概念,程序界面以对话框为基础;
- 单文档和多文档模板采用了以"文档-视图"为中心的思想,文档主要负责数据的保存和处理,视图负责数据的显示和编辑;