MFC与Windows编程

Windows编程基础

MFC:Microsoft Foundation Classes,它封装了WIN32/WIN64功能,在MFC应用程序中,可以使用一组标准类,它们把我们与Windows API隔离开。

Windows API称为WINAPI或WIN32/WIN64。直接使用WINAPI是最费力的开发应用程序的方法。

任何Windows应用程序与Windows本身之间的所有通信,都要使用Windows应用程序编程接口,称作WindowsAPI。

Windows程序是事件驱动的,因此Windows程序要等待某个事件发生。

WndProc()或WindowProc(),Windows消息处理函数。

Windows数据类型

MFC与Windows编程_第1张图片

变量前缀

MFC与Windows编程_第2张图片

窗口,左上角(0,0),水平向右是x+,垂直向下是y-。


Windows程序的结构

最简单仅使用Windows API的Windows程序而言,需要编写两个函数。

  • WinMain()
  • WindowProc()

MFC与Windows编程_第3张图片

 WinMain()

WinMain function (winbase.h) - Win32 apps | Microsoft DocsThe user-provided entry point for a graphical Windows-based application.https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-winmain

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow);
hInstance         是一种称为“实例句柄”或“模块句柄”的东西。操作系统在将可执行文件 (EXE) 加载到内存时使用此值来识别它。某些 Windows 功能需要实例句柄,例如,加载图标或位图。
hPrevInstance   没有任何意义。它曾在 16 位 Windows 中使用,但现在始终为零。
pCmdLine 包含作为 Unicode 字符串的命令行参数。
nCmdShow 是一个标志,它表明主应用程序窗口是最小化、最大化还是正常显示。

MFC与Windows编程_第4张图片

 MFC与Windows编程_第5张图片

创建窗口的种类(WNDCLASSEXA structure)

WNDCLASSEXA (winuser.h) - Win32 apps | Microsoft DocsContains window class information.https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexa

typedef struct tagWNDCLASSEXA {
  UINT      cbSize;
  UINT      style;
  WNDPROC   lpfnWndProc;
  int       cbClsExtra;
  int       cbWndExtra;
  HINSTANCE hInstance;
  HICON     hIcon;
  HCURSOR   hCursor;
  HBRUSH    hbrBackground;
  LPCSTR    lpszMenuName;
  LPCSTR    lpszClassName;
  HICON     hIconSm;
} WNDCLASSEXA, *PWNDCLASSEXA, *NPWNDCLASSEXA, *LPWNDCLASSEXA;
cbSize 此结构的大小(以字节为单位)。 将此成员设置为 sizeof(WNDCLASSEX)。 请务必在调用 GetClassInfoEx 函数之前设置此成员。
style 窗口行为风格。 该成员可以是类样式的任意组合。每个选项都是以CS_开头,可以用 | 组合。
lpfnWndProc 指向窗口消息处理函数的指针,必须使用  CallWindowProc 函数来调用Windows消息处理函数。 有关详细信息,请参阅 WindowProc。
cbClsExtra 按照窗口类结构分配的额外字节数。 系统将字节初始化为零。
cbWndExtra

在窗口实例之后分配的额外字节数。 系统将字节初始化为零。

如果应用程序使用 WNDCLASSEX 在资源文件中注册使用 CLASS 指令创建的对话框,则必须将此成员设置为 DLGWINDOWEXTRA。

hInstance 包含当前应用程序实例的句柄。
hIcon 类图标的句柄。 此成员必须是图标资源的句柄。 如果此成员为 NULL,则系统提供默认图标。
hCursor

类游标的句柄。 此成员必须是游标资源的句柄。

如果此成员为 NULL,则应用程序必须在鼠标移入应用程序窗口时显式设置光标形状。

hbrBackground

类背景画笔的句柄。

该成员可以是用于绘制背景的画笔的句柄,也可以是颜色值。

 颜色值必须是以下标准系统颜色之一(必须将值 1 添加到所选颜色)。

 如果给定了颜色值,则必须将其转换为以下 HBRUSH 类型之一(j见下文)。

使用 UnregisterClass 注销Class时,系统会自动删除班级背景画笔。

应用程序不应删除这些画笔。

当此成员为 NULL 时,每当请求在其客户区中绘制时,应用程序都必须绘制自己的背景。

要确定是否必须绘制背景,应用程序可以处理 WM_ERASEBKGND 消息或测试由 BeginPaint 函数填充的 PAINTSTRUCT 结构的 fErase 成员。

lpszMenuName

指向以空字符结尾的字符串的指针,该字符串指定类菜单的资源名称,因为该名称出现在资源文件中。

如果您使用整数来标识菜单,请使用 MAKEINTRESOURCE  宏。

如果此成员为 NULL,则属于此类的窗口没有默认菜单。

lpszClassName

窗口名,指向以 null 结尾的字符串的指针,或者是一个原子。
如果此参数是原子,则它必须是由先前调用  RegisterClass或 RegisterClassEx 函数创建的类原子。
原子必须在 lpszClassName 的低位字中; 高位字必须为零。

如果 lpszClassName 是一个字符串,它指定窗口类名。
类名可以是使用 RegisterClass或  RegisterClassEx注册的任何名称,也可以是任何预定义的控件类名称。

lpszClassName 的最大长度为 256。如果 lpszClassName 大于最大长度, RegisterClassEx函数将失败。

hIconSm 与窗口类关联的小图标的句柄。
如果该成员为NULL,则系统在hIcon成员指定的图标资源中搜索合适大小的图标作为小图标使用。

Window Class Styles

常数/值 描述

CS_BYTEALIGNCLIENT

0x1000

在字节边界上对齐窗口的客户区(在 x 方向)。 此样式会影响窗口的宽度及其在显示器上的水平位置。

CS_BYTEALIGNWINDOW

0x2000

在字节边界上对齐窗口(在 x 方向上)。 此样式会影响窗口的宽度及其在显示器上的水平位置。

CS_CLASSDC

0x0040

分配一个设备上下文以供类中的所有窗口共享。 因为窗口类是特定于进程的,所以一个应用程序的多个线程可以创建同一个类的窗口。 线程也有可能同时尝试使用设备上下文。 发生这种情况时,系统只允许一个线程成功完成其绘图操作。

CS_DBLCLKS

0x0008

当光标在属于该类的窗口内时,当用户双击鼠标时,向窗口过程发送双击消息。

CS_DROPSHADOW

0x00020000

在窗口上启用阴影效果。 效果通过 SPI_SETDROPSHADOW 打开和关闭。

通常,这对小型、短存活期的窗口(例如菜单)启用,以强调它们与其他窗口的 Z 顺序关系。

从具有这种样式的类创建的窗口必须是顶级窗口; 它们可能不是子窗口。

CS_GLOBALCLASS

0x4000

指示窗口类是应用程序全局类。

详细信息, 见  About Window Classes的"Application Global Classes"部分。

CS_HREDRAW

0x0002

如果移动或大小调整改变了客户区的宽度,则重绘整个窗口。

CS_NOCLOSE

0x0200

在窗口菜单上禁用关闭。

CS_OWNDC

0x0020

为类中的每个窗口分配一个唯一的设备上下文。

CS_PARENTDC

0x0080

将子窗口的剪切矩形设置为父窗口的剪切矩形,以便子窗口可以在父窗口上绘图。

具有 CS_PARENTDC 样式位的窗口从系统的设备上下文缓存中接收常规设备上下文。

它不会给子类 父设备上下文或设备上下文设置。

指定 CS_PARENTDC 可提高应用程序的性能。

CS_SAVEBITS

0x0800

将屏幕图像中被此类窗口遮挡的部分保存为位图。

当窗口被移除时,系统使用保存的位图来恢复屏幕图像,包括其他被遮挡的窗口。

因此,如果位图使用的内存没有被丢弃并且其他屏幕操作没有使存储的图像无效,系统不会向被遮挡的窗口发送 WM_PAINT 消息。

这种风格对于短暂显示且在其他屏幕活动发生之前删除的小窗口(例如,菜单或对话框)很有用。

这种样式增加了显示窗口所需的时间,因为系统必须首先分配内存来存储位图。

CS_VREDRAW

0x0001

如果移动或大小调整改变了客户区的高度,则重绘整个窗口。

HBRUSH 类型

  • COLOR_ACTIVEBORDER
  • COLOR_ACTIVECAPTION
  • COLOR_APPWORKSPACE
  • COLOR_BACKGROUND
  • COLOR_BTNFACE
  • COLOR_BTNSHADOW
  • COLOR_BTNTEXT
  • COLOR_CAPTIONTEXT
  • COLOR_GRAYTEXT
  • COLOR_HIGHLIGHT
  • COLOR_HIGHLIGHTTEXT
  • COLOR_INACTIVEBORDER
  • COLOR_INACTIVECAPTION
  • COLOR_MENU
  • COLOR_MENUTEXT
  • COLOR_SCROLLBAR
  • COLOR_WINDOW
  • COLOR_WINDOWFRAME
  • COLOR_WINDOWTEXT

创建程序窗口

注册窗口类

RegisterClassExA function (winuser.h) - Win32 apps | Microsoft DocsRegisters a window class for subsequent use in calls to the CreateWindow or CreateWindowEx function.https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-registerclassexa

ATOM RegisterClassExW(
  [in] const WNDCLASSEXW *unnamedParam1
);
ATOM RegisterClassExA(
  [in] const WNDCLASSEXA *unnamedParam1
);
[in] unnamedParam1 指向 WNDCLASSEX 结构的指针。
在将结构传递给函数之前,您必须使用适当的类属性填充结构。

返回值

如果函数成功,则返回值是唯一标识正在注册的类的类原子。

该原子只能由 CreateWindow, CreateWindowEx, GetClassInfo, GetClassInfoEx, FindWindow, FindWindowEx, 和UnregisterClass 函数和 IActiveIMMap::FilterClientWindows 方法使用。

如果函数失败,则返回值为零。 要获取扩展错误信息,请调用 GetLastError。

创建窗口

CreateWindowA macro (winuser.h) - Win32 apps | Microsoft DocsCreates an overlapped, pop-up, or child window.https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-createwindowa

HWND CreateWindowW(
  [in, optional]  lpClassName,
  [in, optional]  lpWindowName,
  [in]            dwStyle,
  [in]            x,
  [in]            y,
  [in]            nWidth,
  [in]            nHeight,
  [in, optional]  hWndParent,
  [in, optional]  hMenu,
  [in, optional]  hInstance,
  [in, optional]  lpParam
);
void CreateWindowA(
  [in, optional]  lpClassName,
  [in, optional]  lpWindowName,
  [in]            dwStyle,
  [in]            x,
  [in]            y,
  [in]            nWidth,
  [in]            nHeight,
  [in, optional]  hWndParent,
  [in, optional]  hMenu,
  [in, optional]  hInstance,
  [in, optional]  lpParam
);

CreateWindowExA function (winuser.h) - Win32 apps | Microsoft DocsCreates an overlapped, pop-up, or child window with an extended window style; otherwise, this function is identical to the CreateWindow function.https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-createwindowexa

HWND CreateWindowExW(
  [in]           DWORD     dwExStyle,
  [in, optional] LPCWSTR   lpClassName,
  [in, optional] LPCWSTR   lpWindowName,
  [in]           DWORD     dwStyle,
  [in]           int       X,
  [in]           int       Y,
  [in]           int       nWidth,
  [in]           int       nHeight,
  [in, optional] HWND      hWndParent,
  [in, optional] HMENU     hMenu,
  [in, optional] HINSTANCE hInstance,
  [in, optional] LPVOID    lpParam
);
HWND CreateWindowExA(
  [in]           DWORD     dwExStyle,
  [in, optional] LPCSTR    lpClassName,
  [in, optional] LPCSTR    lpWindowName,
  [in]           DWORD     dwStyle,
  [in]           int       X,
  [in]           int       Y,
  [in]           int       nWidth,
  [in]           int       nHeight,
  [in, optional] HWND      hWndParent,
  [in, optional] HMENU     hMenu,
  [in, optional] HINSTANCE hInstance,
  [in, optional] LPVOID    lpParam
);
[in] dwExStyle 正在创建的窗口的扩展窗口样式。 有关可能值的列表,请参阅Extended Window Styles。
[in, optional] lpClassName

由先前调用 RegisterClass 或 RegisterClassEx 函数创建的以 null 结尾的字符串或类原子。

原子必须在 lpClassName 的低位字中; 高位字必须为零。

如果 lpClassName 是一个字符串,它指定窗口类名。

类名可以是通过RegisterClass 或RegisterClassEx 注册的任何名称,前提是注册类的模块也是创建窗口的模块。类名也可以是任何预定义的系统类名。

[in, optional] lpWindowName

窗口名称。 如果窗口样式指定了标题栏,则 lpWindowName 指向的窗口标题显示在标题栏中。

使用 CreateWindow 创建控件时,例如按钮、复选框和静态控件,使用 lpWindowName 来指定控件的文本。

当使用 SS_ICON 样式创建静态控件时,使用 lpWindowName 来指定图标名称或标识符。

要指定标识符,请使用语法“#num”。

[in] dwStyle 正在创建的窗口的样式。
此参数可以是window style values组合值,以及备注部分中指示的控件样式的组合。
[in] X

窗口的初始水平位置。

对于重叠或弹出窗口,x 参数是窗口左上角的初始 x 坐标,以屏幕坐标表示。

对于子窗口,x 是窗口左上角相对于父窗口客户区左上角的 x 坐标。

如果 x 设置为 CW_USEDEFAULT,则系统选择窗口左上角的默认位置并忽略 y 参数。 CW_USEDEFAULT 仅对重叠窗口有效;

如果为弹出窗口或子窗口指定,则 x 和 y 参数设置为零。

[in] Y

窗口的初始垂直位置。

对于重叠或弹出窗口,y 参数是窗口左上角的初始 y 坐标,以屏幕坐标表示。

对于子窗口,y 是子窗口左上角相对于父窗口客户区左上角的初始 y 坐标。

对于列表框,y 是列表框客户区左上角相对于父窗口客户区左上角的初始 y 坐标。

如果创建重叠窗口时设置了 WS_VISIBLE 样式位并且 x 参数设置为 CW_USEDEFAULT,则 y 参数确定窗口的显示方式。

如果 y 参数是 CW_USEDEFAULT,则窗口管理器在创建窗口后调用带有 SW_SHOW 标志的 ShowWindow 。

如果 y 参数是其他值,则窗口管理器调用 ShowWindow 并将该值作为 nCmdShow 参数。

[in] nWidth

窗口的宽度(以设备为单位)。
对于重叠的窗口,nWidth 是窗口的宽度,以屏幕坐标表示,或 CW_USEDEFAULT。
如果 nWidth 为 CW_USEDEFAULT,则系统选择窗口的默认宽度和高度; 默认宽度从初始 x 坐标延伸到屏幕的右边缘; 默认高度从初始 y 坐标延伸到图标区域的顶部。

CW_USEDEFAULT 仅对重叠窗口有效; 如果为弹出窗口或子窗口指定了 CW_USEDEFAULT,则 nWidth 和 nHeight 参数设置为零。

[in] nHeight 窗口的高度(以设备为单位)。
对于重叠的窗口,nHeight 是窗口的高度,以屏幕坐标表示。
如果 nWidth 参数设置为 CW_USEDEFAULT,系统将忽略 nHeight。
[in, optional] hWndParent 正在创建的窗口的父窗口或所有者窗口的句柄。
要创建子窗口或拥有的窗口,请提供有效的窗口句柄。 该参数对于弹出窗口是可选的。
要创建 message-only window,请提供 HWND_MESSAGE 或现有仅消息窗口的句柄。
[in, optional] hMenu 菜单句柄,或指定子窗口标识符,具体取决于窗口样式。
对于重叠或弹出窗口,hMenu 标识要与窗口一起使用的菜单; 如果要使用类菜单,它可以为 NULL。
对于子窗口,hMenu 指定子窗口标识符,一个整数值,对话框控件用于通知其父级事件。
应用程序确定子窗口标识符; 对于具有相同父窗口的所有子窗口,它必须是唯一的。
[in, optional] hInstance 要与窗口关联的模块实例的句柄。
[in, optional] lpParam 指向要通过 WM_CREATE 消息的 lParam 参数指向的 CREATESTRUCT 结构(lpCreateParams 成员)传递给窗口的值的指针。
此消息在返回之前由该函数发送到创建的窗口。
如果应用程序调用  CreateWindow 来创建 MDI 客户端窗口,lpParam 应该指向 CLIENTCREATESTRUCT 结构。
如果一个 MDI 客户窗口调用 CreateWindow 来创建一个 MDI 子窗口,lpParam 应该指向一个MDICREATESTRUCT 结构。
如果不需要其他数据,lpParam 可能为 NULL。

Return value

如果函数成功,则返回值是新窗口的句柄。
如果函数失败,则返回值为 NULL。 要获取扩展错误信息,请调用 GetLastError。
此功能通常由于以下原因之一失败:

  • 无效的参数值
  • 系统类由不同的模块注册
  • 安装 WH_CBT 挂钩并返回失败代码
  • 如果对话框模板中的控件之一未注册,或者其窗口窗口过程失败 WM_CREATE 或 WM_NCCREATE。

显示窗口

ShowWindow function (winuser.h) - Win32 apps | Microsoft DocsSets the specified window's show state.https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow

BOOL ShowWindow(
  [in] HWND hWnd,
  [in] int  nCmdShow
);
[in] hWnd 窗口的句柄。
[in] nCmdShow 控制窗口的显示方式。
如果启动应用程序的程序提供  STARTUPINFO 结构,则该参数在应用程序第一次调用 ShowWindow 时将被忽略。
否则,第一次调用 ShowWindow 时,该值应该是 WinMain函数在其 nCmdShow 参数中获取的值。
在后续调用中,此参数可以是以下值之一。

意义
SW_HIDE
0
隐藏窗口并激活另一个窗口
SW_SHOWNORMAL
SW_NORMAL
1
激活并显示一个窗口。 如果窗口被最小化或最大化,系统会将其恢复到原来的大小和位置。 应用程序应在第一次显示窗口时指定此标志。
SW_SHOWMINIMIZED
2
激活窗口并将其显示为最小化窗口。
SW_SHOWMAXIMIZED
SW_MAXIMIZE
3
激活窗口并将其显示为最大化窗口。
SW_SHOWNOACTIVATE
4
以最近的大小和位置显示窗口。 该值与 SW_SHOWNORMAL 类似,只是窗口未激活。
SW_SHOW
5
激活窗口并以其当前大小和位置显示它。
SW_MINIMIZE
6
最小化指定窗口并激活 Z 顺序中的下一个顶级窗口。
SW_SHOWMINNOACTIVE
7
将窗口显示为最小化窗口。 此值类似于 SW_SHOWMINIMIZED,但未激活窗口。
SW_SHOWNA
8
以当前大小和位置显示窗口。 该值与 SW_SHOW 类似,只是窗口未激活。
SW_RESTORE
9
激活并显示窗口。 如果窗口被最小化或最大化,系统会将其恢复到原来的大小和位置。应用程序在恢复最小化窗口时应指定此标志。
SW_SHOWDEFAULT
10
根据启动应用程序的程序传递给 CreateProcess函数的 STARTUPINFO结构中指定的 SW_ 值设置显示状态。​
SW_FORCEMINIMIZE
11
最小化一个窗口,即使拥有该窗口的线程没有响应。 只有在最小化来自不同线程的窗口时才应使用此标志。

返回值
类型:布尔

如果窗口先前可见,则返回值非零。

如果窗口先前被隐藏,则返回值为零。

初始化程序窗口

重画窗口工作区

UpdateWindow function (winuser.h) - Win32 apps | Microsoft DocsThe UpdateWindow function updates the client area of the specified window by sending a WM_PAINT message to the window if the window's update region is not empty.https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-updatewindow

BOOL UpdateWindow(
  [in] HWND hWnd
);
[in] hWnd 处理要更新的窗口。

返回值
如果函数成功,则返回值非零。如果函数失败,则返回值为零。

处理Windows消息

MFC与Windows编程_第6张图片

 MFC与Windows编程_第7张图片

包含来自线程的消息队列的消息信息

typedef struct tagMSG {
  HWND   hwnd;
  UINT   message;
  WPARAM wParam;
  LPARAM lParam;
  DWORD  time;
  POINT  pt;
  DWORD  lPrivate;
} MSG, *PMSG, *NPMSG, *LPMSG;

//包含来自线程的消息队列的消息信息。

hwnd 窗口过程接收消息的窗口句柄。 当消息是线程消息时,此成员为 NULL。
message 消息标识符。 应用程序只能使用低位字; 高位字由系统保留。
wParam 有关消息的附加信息。 确切的含义取决于消息成员的ID值。
lParam 有关消息的附加信息。 确切的含义取决于消息成员的ID值
time 发布消息的时间。
pt 发布消息时的光标位置,以屏幕坐标表示。
lPrivate

消息ID

MFC与Windows编程_第8张图片

 从调用线程的消息队列中检索消息。该函数分派传入的已发送消息,直到发布的消息可用于检索。

BOOL GetMessage(
  [out]          LPMSG lpMsg,
  [in, optional] HWND  hWnd,
  [in]           UINT  wMsgFilterMin,
  [in]           UINT  wMsgFilterMax
);
[out] lpMsg 指向从线程的消息队列接收消息信息的 MSG 结构的指针。
[in, optional] hWnd

要检索其消息的窗口的句柄。 窗口必须属于当前线程。

如果 hWnd 为 NULL,GetMessage 检索属于当前线程的任何窗口的消息,以及当前线程的消息队列中 hwnd 值为 NULL 的任何消息(参见 MSG结构)。 因此,如果 hWnd 为 NULL,则窗口消息和线程消息都会被处理。

如果 hWnd 为 -1,GetMessage 只检索当前线程的消息队列中 hwnd 值为 NULL 的消息,即 PostMessage(当 hWnd 参数为 NULL 时)或  PostThreadMessage发布的线程消息。

[in] wMsgFilterMin

要检索的最低消息值的整数值。 使用 WM_KEYFIRST (0x0100) 指定第一条键盘消息或 WM_MOUSEFIRST (0x0200) 指定第一条鼠标消息。

在此处和 wMsgFilterMax 中使用 WM_INPUT仅指定 WM_INPUT 消息。

如果 wMsgFilterMin 和 wMsgFilterMax 都为零,则 GetMessage 返回所有可用消息(即不执行范围过滤)。

[in] wMsgFilterMax

要检索的最高消息值的整数值。 使用 WM_KEYLAST 指定最后一个键盘消息或 WM_MOUSELAST 指定最后一个鼠标消息。

在此处和 wMsgFilterMin 中使用 WM_INPUT仅指定 WM_INPUT 消息。

如果 wMsgFilterMin 和 wMsgFilterMax 都为零,则 GetMessage 返回所有可用消息(即不执行范围过滤)。

返回值

如果函数检索 WM_QUIT以外的消息,则返回值非零。如果函数检索到 WM_QUIT消息,则返回值为零。

如果有错误,返回值为-1。 例如,如果 hWnd 是无效的窗口句柄或 lpMsg 是无效的指针,则函数将失败。 要获取扩展错误信息,请调用 GetLastError。

因为返回值可以是非零、零或 -1,所以避免使用这样的代码:

while (GetMessage( lpMsg, hWnd, 0, 0)) ...

在 hWnd 是无效参数的情况下(例如引用已经被销毁的窗口)可能返回 -1 值,这意味着此类代码可能导致致命的应用程序错误。 相反,使用这样的代码:

BOOL bRet;

while( (bRet = GetMessage( &msg, hWnd, 0, 0 )) != 0)
{ 
    if (bRet == -1)
    {
        // handle the error and possibly exit
    }
    else
    {
        TranslateMessage(&msg); 
        DispatchMessage(&msg); 
    }
}

MFC与Windows编程_第9张图片

 MFC与Windows编程_第10张图片

MFC与Windows编程_第11张图片


 WinMain()函数范例

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
    _In_opt_ HINSTANCE hPrevInstance,
    _In_ LPWSTR    lpCmdLine,
    _In_ int       nCmdShow)
{
    //创建窗口的种类
    tagWNDCLASSEXW wcex;    //决定窗口种类的结构    
    wcex.cbSize = sizeof(tagWNDCLASSEXW);   //结构大小(单位字节)
    wcex.style = CS_HREDRAW | CS_VREDRAW;   //窗口风格
    wcex.lpfnWndProc = WindowProc;      //消息处理函数
    wcex.cbClsExtra = 0;    //窗口结构的额外字节
    wcex.cbWndExtra = 0;    //窗口实例的额外字节
    wcex.hInstance = hInstance; //当前应用程序实例的句柄(wWinMaind的_In_ HINSTANCE hInstance)
    wcex.hIcon = LoadIcon(nullptr,IDI_APPLICATION); //图标的句柄
    wcex.hCursor = LoadCursorW(nullptr,IDC_ARROW);  //游标的句柄
    wcex.hbrBackground = static_cast(GetStockObject(GRAY_BRUSH));   //背景画笔的句柄
    wcex.lpszMenuName = nullptr;    //窗口菜单
    static LPCTSTR szAppName{ _T("WndClsName") };    //窗口名
    wcex.lpszClassName = szAppName; //窗口类名称
        wcex.hIconSm = nullptr;     //与窗口类关联的小图标的句柄。

    //注册窗口
    RegisterClassEx(&wcex);

    //创建窗口
    HWND hWnd;  //Window handle
    hWnd = CreateWindowEx(WS_EX_STATICEDGE, //窗口的扩展窗口样式
                        szAppName,    //窗口类名称
                        _T("WinTitle"), //窗口名称
                        WS_OVERLAPPEDWINDOW,    //正在创建的窗口的样式
                        CW_USEDEFAULT,      //X
                        CW_USEDEFAULT,      //Y
                        CW_USEDEFAULT,      //nWidth
                        CW_USEDEFAULT,      //nHeight
                        nullptr,    //所有者窗口的句柄
                        nullptr,    //菜单句柄
                        hInstance,  //要与窗口关联的模块实例的句柄。(wWinMaind的_In_ HINSTANCE hInstance)
                        nullptr     //​指向要通过 WM_CREATE 消息的 lParam 参数指向的 CREATESTRUCT 结构(lpCreateParams 成员)传递给窗口的值的指针。如果不需要其他数据,lpParam 可能为 NULL。
       );


    //显示窗口
    ShowWindow(hWnd,nCmdShow);  //nCmdShow:wWinMain的_In_ int  nCmdShow

    //重画窗口工作区
    UpdateWindow(hWnd);

    //包含来自线程的消息队列的消息信息
    MSG msg;

    // 主消息循环:
    while (GetMessage(&msg, nullptr, 0, 0))     //​ 如果函数检索 WM_QUIT以外的消息,则返回值非零。如果函数检索到 WM_QUIT消息,则返回值为零。        ​
    {
        TranslateMessage(&msg);     //对检索的消息执行任何必要的转换
        DispatchMessage(&msg);      //使Windows调用应用程序的WindowProc()函数来处理消息
    }

    return static_cast(msg.wParam);
}

LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
   
    }
    return 0;
}

处理Windows消息

WindowProc()函数

LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

返回类型LRESULT是一个Windows类型,通常等价于long类型。

该函数是Windows通过指针(该指针是在WinMain()函数的WNDCLASSEX结构中用WindowProc()函数的地址设置的)调用的,所以需要将该函数限定为CALLBACK。

MFC与Windows编程_第12张图片

解码Windows消息

    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);
    }

 

 MFC与Windows编程_第13张图片

BeginPaint BeginPaint function (winuser.h) - Win32 apps | Microsoft Docshttps://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-beginpaintBeginPaint 函数准备指定的窗口进行绘画,并用有关绘画的信息填充 PAINTSTRUCT 结构。

HDC BeginPaint(
  [in]  HWND          hWnd,
  [out] LPPAINTSTRUCT lpPaint
);
[in] hWnd 处理要重绘的窗口。
[out] lpPaint 指向将接收绘画信息的 PAINTSTRUCT结构的指针。

 返回值
如果函数成功,则返回值是指定窗口的显示设备上下文的句柄。如果函数失败,返回值为NULL,表示没有可用的显示设备上下文。

PAINTSTRUCT

PAINTSTRUCT (winuser.h) - Win32 apps | Microsoft DocsThe PAINTSTRUCT structure contains information for an application. This information can be used to paint the client area of a window owned by that application.https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-paintstructPAINTSTRUCT 结构包含应用程序的信息。 此信息可用于绘制该应用程序拥有的窗口的客户区。

typedef struct tagPAINTSTRUCT {
  HDC  hdc;
  BOOL fErase;
  RECT rcPaint;
  BOOL fRestore;
  BOOL fIncUpdate;
  BYTE rgbReserved[32];
} PAINTSTRUCT, *PPAINTSTRUCT, *NPPAINTSTRUCT, *LPPAINTSTRUCT;
hdc 用于绘画的显示 DC 的句柄。
fErase

指示是否必须删除背景。

如果应用程序应该擦除背景,则此值非零。

如果在没有背景画笔的情况下创建窗口类,则应用程序负责擦除背景。

有关详细信息,请参阅 WNDCLASS结构的 hbrBackground 成员的说明。

rcPaint 一个 RECT结构,它指定请求绘画的矩形的左上角和右下角,以相对于客户区左上角的设备单位表示。

fRestore

预留的; 系统内部使用。
fIncUpdate 预留的; 系统内部使用。
rgbReserved 预留的; 系统内部使用。

RECTRECT (windef.h) - Win32 apps | Microsoft DocsThe RECT structure defines a rectangle by the coordinates of its upper-left and lower-right corners.https://docs.microsoft.com/en-us/windows/win32/api/windef/ns-windef-rectRECT 结构通过其左上角和右下角的坐标定义一个矩形。

typedef struct tagRECT {
  LONG left;
  LONG top;
  LONG right;
  LONG bottom;
} RECT, *PRECT, *NPRECT, *LPRECT;
left 指定矩形左上角的 x 坐标。
top 指定矩形左上角的 y 坐标。
right 指定矩形右下角的 x 坐标。
bottom 指定矩形右下角的 y 坐标。

GetClientRectGetClientRect function (winuser.h) - Win32 apps | Microsoft Docshttps://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getclientrect检索窗口客户区的坐标。 客户坐标指定客户区的左上角和右下角。 因为客户坐标是相对于窗口客户区的左上角的,所以左上角的坐标是(0,0)。

BOOL GetClientRect(
  [in]  HWND   hWnd,
  [out] LPRECT lpRect
);
[in] hWnd 处理要重绘的窗口。
[out] lpPaint 指向接收客户端坐标的RECT 结构的指针。 左侧和顶部成员为零。 右侧和底部成员包含窗口的宽度和高度。

返回值
如果函数成功,则返回值非零。如果函数失败,则返回值为零。 要获取扩展错误信息,请调用  GetLastError。

SetBkModeSetBkMode function (wingdi.h) - Win32 apps | Microsoft DocsThe SetBkMode function sets the background mix mode of the specified device context. The background mix mode is used with text, hatched brushes, and pen styles that are not solid lines.https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-setbkmodeSetBkMode 函数设置指定设备上下文的背景混合模式。 背景混合模式用于文本、阴影画笔和非实线的笔样式。

int SetBkMode(
  [in] HDC hdc,
  [in] int mode
);
[in] hdc 设备上下文的句柄。
[in] mode

背景模式。 此参数可以是以下值之一。

值         含义
OPAQUE 在绘制text、hatched brush或pen之前,使用当前背景颜色填充背景。
TRANSPARENT 背景保持不变。

返回值
如果函数成功,返回值指定之前的后台模式。如果函数失败,则返回值为零。

DrawText & DrawTextExDrawText function (winuser.h) - Win32 apps | Microsoft DocsThe DrawText function draws formatted text in the specified rectangle. It formats the text according to the specified method (expanding tabs, justifying characters, breaking lines, and so forth).https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-drawtextDrawTextExA function (winuser.h) - Win32 apps | Microsoft DocsThe DrawTextEx function draws formatted text in the specified rectangle.https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-drawtextexaDrawText 函数在指定的矩形中绘制格式化文本。 它根据指定的方法(扩展制表符、对齐字符、换行等)格式化文本。

要指定其他格式选项,请使用  DrawTextEx 函数。

int DrawText(
  [in]      HDC     hdc,
  [in, out] LPCTSTR lpchText,
  [in]      int     cchText,
  [in, out] LPRECT  lprc,
  [in]      UINT    format
);

DrawTextEx 函数在指定的矩形中绘制格式化文本。

int DrawTextExA(
  [in]      HDC              hdc,
  [in, out] LPSTR            lpchText,
  [in]      int              cchText,
  [in, out] LPRECT           lprc,
  [in]      UINT             format,
  [in]      LPDRAWTEXTPARAMS lpdtp
);
[in] hdc 设备上下文的句柄。
[in, out] lpchText

指向指定要绘制的文本的字符串的指针。

如果 nCount 参数为 -1,则字符串必须以 null 结尾。

如果 uFormat 包含 DT_MODIFYSTRING,该函数最多可以向该字符串添加四个附加字符。

包含字符串的缓冲区应该足够大以容纳这些额外的字符。

[in] cchText

字符串的长度(以字符为单位)。

如果 nCount 为 -1,则假定 lpchText 参数是指向以 null 结尾的字符串的指针,并且 DrawText 会自动计算字符数。

[in, out] lprc 指向  RECT 结构的指针,该结构包含要在其中格式化文本的矩形(在逻辑坐标中)
[in] format 格式化文本的方法。 该参数可以是以下一个或多个值。

format

含义

DT_BOTTOM

将文本对齐到矩形的底部。 此值仅与 DT_SINGLELINE 值一起使用。.

DT_CALCRECT

确定矩形的宽度和高度。

如果有多行文本,DrawText 使用 lpRect 参数指向的矩形的宽度,并扩展矩形的底部以绑定最后一行文本。

如果最大的单词比矩形宽,则宽度会扩大。

如果文本小于矩形的宽度,则宽度会减小。

如果只有一行文本,DrawText 会修改矩形的右侧,使其与行中的最后一个字符相接。

无论哪种情况,DrawText 都会返回格式化文本的高度,但不会绘制文本。

DT_CENTER

在矩形中水平居中文本。

DT_EDITCONTROL

复制多行编辑控件的文本显示特征。 具体来说,平均字符宽度的计算方式与编辑控件相同,并且该函数不显示部分可见的最后一行。

DT_END_ELLIPSIS

对于显示的文本,如果字符串的结尾不适合矩形,则会将其截断并添加省略号。

如果不在字符串末尾的单词超出了矩形的范围,则将其截断而没有省略号。
除非指定 DT_MODIFYSTRING 标志,否则不会修改字符串。

与 DT_PATH_ELLIPSIS 和 DT_WORD_ELLIPSIS 进行比较。

DT_EXPANDTABS

扩展制表符。

每个制表符的默认字符数为 8。

DT_WORD_ELLIPSIS、DT_PATH_ELLIPSIS 和 DT_END_ELLIPSIS 值不能与 DT_EXPANDTABS 值一起使用。

DT_EXTERNALLEADING

包括字体外部行高前导。 通常,外部行距不包括在一行文本的高度中。

DT_HIDEPREFIX

忽略文本中的 & 前缀字符。 后面的字母不会加下划线,但仍会处理其他助记符前缀字符。
例子:

输入字符串:“A&bc&&d”

正常:“Abc&d”

DT_HIDEPREFIX: "Abc&d"与 DT_NOPREFIX 和 DT_PREFIXONLY 进行比较。

DT_INTERNAL

使用系统字体来计算文本度量。

DT_LEFT

将文本左对齐。

DT_MODIFYSTRING

修改指定的字符串以匹配显示的文本。

除非指定 DT_END_ELLIPSIS 或 DT_PATH_ELLIPSIS,否则此值无效。

DT_NOCLIP

无需剪裁即可绘制。

使用 DT_NOCLIP 时,DrawText 会更快一些。

DT_NOFULLWIDTHCHARBREAK

防止在 DBCS(双宽字符串)处换行,因此换行规则等同于 SBCS 字符串。

例如,这可以在韩语窗口中使用,以提高图标标签的可读性。

除非指定 DT_WORDBREAK,否则此值无效。

DT_NOPREFIX

关闭前缀字符的处理。

通常,DrawText 将助记符前缀字符 & 解释为下划线字符的指令,并将助记符前缀字符 && 解释为打印单个 & 的指令。

通过指定 DT_NOPREFIX,此处理被关闭。 
例子:

输入字符串:“A&bc&&d”

正常:“Abc&d”

DT_NOPREFIX: "A&bc&&d"

与 DT_HIDEPREFIX 和 DT_PREFIXONLY 进行比较。

DT_PATH_ELLIPSIS

对于显示的文本,用省略号替换字符串中间的字符,以便结果适合指定的矩形。

如果字符串包含反斜杠 (\\) 字符,DT_PATH_ELLIPSIS 会尽可能多地保留最后一个反斜杠之后的文本。

除非指定 DT_MODIFYSTRING 标志,否则不会修改字符串。

与 DT_END_ELLIPSIS 和 DT_WORD_ELLIPSIS 进行比较。

DT_PREFIXONLY

仅在与号 (&) 前缀字符之后的字符位置绘制下划线。 不在字符串中绘制任何其他字符。 例如,
例子:

输入字符串:“A&bc&&d”n

正常:“Abc&d”

DT_PREFIXONLY:“_”

与 DT_HIDEPREFIX 和 DT_NOPREFIX 进行比较。

DT_RIGHT

将文本右对齐。

DT_RTLREADING

当在 hdc 中选择的字体是希伯来语或阿拉伯语字体时,双向文本按从右到左的阅读顺序布局。

所有文本的默认阅读顺序是从左到右。

DT_SINGLELINE

仅在单行上显示文本。

回车和换行不会中断行。

DT_TABSTOP

设置制表位。

uFormat 参数的第 15-8 位(低位字的高位字节)指定每个制表符的字符数。

每个制表符的默认字符数为 8。

DT_CALCRECT、DT_EXTERNALEADING、DT_INTERNAL、DT_NOCLIP 和 DT_NOPREFIX 值不能与 DT_TABSTOP 值一起使用。

DT_TOP

将文本对齐到矩形的顶部。

DT_VCENTER

垂直居中文本。

此值仅与 DT_SINGLELINE 值一起使用。

DT_WORDBREAK

Breaks words。

如果单词超出 lpRect 参数指定的矩形边缘,则单词之间会自动换行。 回车换行序列也会换行。
如果未指定,则输出为一行。

DT_WORD_ELLIPSIS

截断任何不适合矩形的单词并添加省略号。

与 DT_END_ELLIPSIS 和 DT_PATH_ELLIPSIS 进行比较。

返回值
如果函数成功,则返回值是以逻辑单位表示的文本高度。 如果指定了 DT_VCENTER 或 DT_BOTTOM,则返回值是从 lpRect->top 到绘制文本底部的偏移量。如果函数失败,则返回值为零。

MFC与Windows编程_第14张图片

 EndPaintEndPaint function (winuser.h) - Win32 apps | Microsoft DocsThe EndPaint function marks the end of painting in the specified window. This function is required for each call to the BeginPaint function, but only after painting is complete.https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-endpaintEndPaint 函数标记指定窗口中绘画的结束。 每次调用 BeginPaint函数时都需要此函数,但仅在绘制完成之后。

BOOL EndPaint(
  [in] HWND              hWnd,
  [in] const PAINTSTRUCT *lpPaint
);
[in] hWnd 处理已重绘的窗口。
[in] lpPaint 指向包含由 BeginPaint检索的绘画信息的 PAINTSTRUCT结构的指针。

返回值
返回值始终为非零。

结束程序

PostQuitMessage

向系统指示线程已请求终止(退出)。 它通常用于响应 WM_DESTROY消息。

void PostQuitMessage(
  [in] int nExitCode
);
[in] nExitCode 应用程序退出代码。 该值用作 WM_QUIT 消息的 wParam 参数。

返回值

DefWindowProc

DefWindowProcA

DefWindowProcA function (winuser.h) - Win32 apps | Microsoft Docshttps://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-defwindowproca调用默认窗口过程为应用程序未处理的任何窗口消息提供默认处理。 此功能可确保处理每条消息。 DefWindowProc 使用与窗口过程接收的相同参数调用。

LRESULT DefWindowProcW(
  [in] HWND   hWnd,
  [in] UINT   Msg,
  [in] WPARAM wParam,
  [in] LPARAM lParam
);

DefWindowProcW

调用默认窗口过程为应用程序未处理的任何窗口消息提供默认处理。 此功能可确保处理每条消息。 DefWindowProc 使用与窗口过程接收的相同参数调用。

LRESULT DefWindowProcW(
  [in] HWND   hWnd,
  [in] UINT   Msg,
  [in] WPARAM wParam,
  [in] LPARAM lParam
);
[in] hWnd 接收消息的窗口过程的句柄。
[in] Msg 消息。
[in] wParam 附加消息信息。 该参数的内容取决于 Msg 参数的值。
[in] lParam 附加消息信息。 该参数的内容取决于 Msg 参数的值。

返回值

返回值是消息处理的结果,取决于消息。

完整的WindowProc()函数

LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_PAINT:      //当系统或其他应用程序发出绘制应用程序窗口部分的请求时,将发送 WM_PAINT 消息。
        HDC hDC;    //处理将与新的Graphics::Graphics对象关联的设备上下文。
        PAINTSTRUCT PaintSt;    //此信息可用于绘制该应用程序拥有的窗口的客户区。
        RECT aRect; //RECT 结构通过其左上角和右下角的坐标定义一个矩形。
        hDC = BeginPaint(hWnd,&PaintSt); //准备指定的窗口进行绘画,并用有关绘画的信息填充 PAINTSTRUCT 结构。

        GetClientRect(hWnd,&aRect);       //检索窗口客户区的坐标。
        SetBkMode(hDC, TRANSPARENT);    //指定设备上下文的背景混合模式。TRANSPARENT	背景保持不变。

         //函数在指定的矩形中绘制格式化文本。
        DrawText( hDC,
            _T("DrawText lpchText"), //指向指定要绘制的文本的字符串的指针。
            -1,                     //表示以空字符结尾的字符串
            &aRect,                 //该结构包含要在其中格式化文本的矩形(在逻辑坐标中)
            DT_SINGLELINE | DT_CENTER | DT_VCENTER); //格式化文本的方法。

        EndPaint(hWnd, &PaintSt);    //标记指定窗口中绘画的结束。
        return 0;

    case WM_DESTROY:    //此消息在窗口被销毁时发送
        PostQuitMessage(WM_QUIT);   //向系统指示线程已请求终止(退出)。
        return 0;
   
    }
    return  DefWindowProc(hWnd, message, wParam, lParam);
}

VS创建的窗口程序

#include "pch.h"
#include "framework.h"
#include "WNDAPP.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 展开传递的参数或表达式。其目的是避免编译器关于未引用参数的警告。
    UNREFERENCED_PARAMETER(lpCmdLine);

    // TODO: 在此处放置代码。

    // 初始化全局字符串
    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);     //LoadStringW:从与指定模块关联的可执行文件中加载字符串资源,并将字符串复制到带有终止空字符的缓冲区中,或者返回指向字符串资源本身的只读指针。
    LoadStringW(hInstance, IDC_WNDAPP, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance); //注册窗口类

    // 执行应用程序初始化:
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }

    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WNDAPP));  //加载指定的快捷键表。
    MSG msg;        //包含来自线程的消息队列的消息信息

    // 主消息循环:
    while (GetMessage(&msg, nullptr, 0, 0))     //​ 如果函数检索 WM_QUIT以外的消息,则返回值非
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))     //处理菜单命令的accelerator keys。
        {
            TranslateMessage(&msg); //对检索的消息执行任何必要的转换
            DispatchMessage(&msg);  //使Windows调用应用程序的WindowProc()函数来处理消息
        }
    }
    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;    //当前应用程序实例的句柄(wWinMaind的_In_ HINSTANCE hInstance)
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WNDAPP)); //图标的句柄
    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);   //游标的句柄
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);       //背景画笔的句柄
    wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_WNDAPP); //窗口菜单
    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(    //创建窗口,hInst,Window handle
       szWindowClass,          //窗口类名称
       szTitle,                 //窗口名称
       WS_OVERLAPPEDWINDOW,       //正在创建的窗口的样式
       CW_USEDEFAULT,       //X
       0,               //Y
       CW_USEDEFAULT,   //nWidth
       0,               //nHeight
       nullptr,     //所有者窗口的句柄
       nullptr,      //菜单句柄
       hInstance,   //要与窗口关联的模块实例的句柄。(wWinMaind的_In_ HINSTANCE hInstance)
       nullptr);    //​指向要通过 WM_CREATE 消息的 lParam 参数指向的 

   if (!hWnd)
   {
      return FALSE;
   }
   ShowWindow(hWnd, nCmdShow);  //显示窗口
   UpdateWindow(hWnd);          //重画窗口工作区
   return TRUE;
}

//  函数: WndProc(HWND, UINT, WPARAM, LPARAM)
//  目标: 处理主窗口的消息。
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_COMMAND:    //  WM_COMMAND  - 处理应用程序菜单
        {
            int wmId = LOWORD(wParam);      //该宏从指定的 32 位值中检索低位字。
            // 分析菜单选择:
            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:  //  WM_PAINT    - 绘制主窗口
        {
            PAINTSTRUCT ps;     //此信息可用于绘制该应用程序拥有的窗口的客户区。
            HDC hdc = BeginPaint(hWnd, &ps);    //准备指定的窗口进行绘画,并用有关绘画的信息填充 PAINTSTRUCT 结构。
            // TODO: 在此处添加使用 hdc 的任何绘图代码...
            EndPaint(hWnd, &ps);    //标记指定窗口中绘画的结束。
        }
        break;
    case WM_DESTROY:        //  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); //UNREFERENCED_PARAMETER 展开传递的参数或表达式。其目的是避免编译器关于未引用参数的警告。
    switch (message)
    {
    case WM_INITDIALOG:     //在显示对话框之前立即发送到对话框过程
        return (INT_PTR)TRUE;   //INT_PTR(其实也就是 typedef了一把)

    case WM_COMMAND:    //  WM_COMMAND  - 处理应用程序菜单
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
        {
            EndDialog(hDlg, LOWORD(wParam));    //销毁模态对话框,导致系统结束对对话框的任何处理。
            return (INT_PTR)TRUE;
        }
        break;
    }
    return (INT_PTR)FALSE;
}

你可能感兴趣的:(c++,mfc,windows,microsoft)