这个是visual studio 2022上利用 Windows桌面应用程序模板创建的源文件注释
一个Windows图形界面(GUI)应用程序通常由主窗体,对话框,控件组成。
当应用程序创建一个窗体,需要调用CreateWindowEx函数,必须提供的参数
1.窗体类
窗体类是一个结构体。是一系列属性的集合,用来描述窗体的行为及外观,应用程序
通过它的描述来注册和创建窗体类,在创建窗体前向操作系统注册窗体类。
窗体在创建之前需要先注册窗体类。
控件?
控件是系统窗体类,由操作系统“注册”
常见控件:
Button,ComboBox,Edit,ListBox,MDIClient,ScrollBar,Static等
创建控件的时机?
应用程序框架,主窗体分为非客户区域,客户区域,要在客户区域创建控件,需要等客户区域
创建完成之后才能创建。怎样才能知道客户区域创建完成了呢?操作系统会给我们发送一条消
息WM_CREATE。即当收到WM_CREAT消息时,代表主窗体的客户区域创建完成,此时可以
创建控件。
窗体类的分类
1.系统窗体类
2.应用程序本地窗体类
3.应用程序全局窗体类
在一个动态库里调用RegisterClassEx,WNDCLASS的style成员设置成
CS_CLOBALCLASS;最后把DLL的名字写到注册表里。其他应用程序可以使用这个窗体类。
这么多窗体类,操作系统怎么定位它们?
当应用程序调用CreateWindow or CreateWindowWx, 操作系统使用下面的步骤定位窗体类:
第一步,从”应用程序本地窗口类“表中查找:用CreateWindow的参数hInstance和
szWindowClass匹配出”窗口类结构体“,用这个窗体类创建窗体。
模块句柄hInstance1 窗体类名称1 窗体类结构体1
模块句柄hInstance2 窗体类名称2 窗体类结构体2
第二步,如果第一步么有找到,从”应用程序全局窗体类“表中查找。
第三步,如果第二步没有找到,从”系统窗体类“表中查找。
//
#include "framework.h"
#include "Project1.h"
#include<windowsx.h>//GET_Y_LPARAM
#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);
//----------------------------------------------------------------------------------------------------------------
/*
这段代码是一个Windows应用程序的入口函数,即程序启动后执行的第一个函数。
它接受一些参数,
包括实例句柄(hInstance)、
上一个实例句柄(hPrevInstance)、
命令行参数(lpCmdLine)
显示命令(nCmdShow)。
*/
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{ //代码中的UNREFERENCED_PARAMETER宏用于解决编译器产生的未使用参数的警告。
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// 初始化全局字符串
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);//函数加载应用程序的标题和窗口类名。
LoadStringW(hInstance, IDC_PROJECT1, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);////函数注册自定义的窗口类。
// 执行应用程序初始化:
if (!InitInstance (hInstance, nCmdShow))//通过调用InitInstance函数初始化应用程序实例。
{
return FALSE;
}
//通过调用LoadAccelerators函数加载加速器表,用于处理加速器键盘消息。
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_PROJECT1));
//之后使用一个消息结构体MSG来接收消息。
MSG msg;
// 主消息循环:
/*
在主消息循环内部,通过调用GetMessage函数获取消息,
并进行TranslateAccelerator、TranslateMessage和DispatchMessage操作来处理消息。
TranslateAccelerator函数用于处理加速器键盘消息,TranslateMessage函数用于将虚
拟键消息转换为字符消息,DispatchMessage函数用于将消息派发给窗口过程函数进行处理。
*/
while (GetMessage(&msg, nullptr, 0, 0))//通过调用GetMessage函数获取消息
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))//TranslateAccelerator函数用于处理加速器键盘消息
{
TranslateMessage(&msg);//TranslateMessage函数用于将虚拟键消息转换为字符消息
DispatchMessage(&msg);//DispatchMessage函数用于将消息派发给窗口过程函数进行处理。
}
}
//当主消息循环结束后,返回msg.wParam作为应用程序的返回值。
return (int) msg.wParam;
}
//-------------------------------------------------------------------------------------------------------------
// 函数: MyRegisterClass()
//
// 目标: 注册窗口类。
//这段代码用于注册自定义窗口类。在Windows应用程序中,窗口类是用来定义窗口的外观和行为的结构体。
//函数MyRegisterClass接受一个实例句柄(hInstance)作为参数。
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex;//在函数内部,创建一个WNDCLASSEXW结构体变量wcex来描述窗口类。
wcex.cbSize = sizeof(WNDCLASSEX);//在结构体的成员赋值部分,将cbSize成员设置为sizeof(WNDCLASSEX),即结构体的大小。
//style成员用于指定窗口样式,包括如何绘制和响应窗口的行为,这里使用了CS_HREDRAW(水平重绘)和CS_VREDRAW(垂直重绘)样式。
wcex.style = CS_HREDRAW | CS_VREDRAW;
//lpfnWndProc成员是指向窗口过程函数的指针,用于处理窗口消息,这里指定为WndProc函数。
wcex.lpfnWndProc = WndProc;
//cbClsExtra和cbWndExtra是额外的窗口类和窗口实例的附加字节数,这里都设置为0。
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
//hInstance成员是应用程序的实例句柄。
wcex.hInstance = hInstance;
//hIcon成员是窗口的图标,通过调用LoadIcon函数加载一个图标资源。
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_PROJECT1));
//hCursor成员是窗口的光标,通过调用LoadCursor函数加载一个光标资源。
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
//hbrBackground成员是窗口的背景刷子,这里使用了COLOR_WINDOW+1来指定颜色
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
//lpszMenuName成员是窗口的菜单资源,通过调用MAKEINTRESOURCEW将资源ID转换为字符串,并指定为窗口类的菜单。
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_PROJECT1);
//lpszClassName成员是窗口类的名称,这里指定为之前加载的窗口类名。
wcex.lpszClassName = szWindowClass;
//hIconSm成员是窗口的小图标,通过调用LoadIcon函数加载一个小图标资源。
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
//最后,调用RegisterClassExW函数来注册窗口类,并将注册的ATOM值作为函数的返回值。
return RegisterClassExW(&wcex);
//通过这段代码,我们可以看到窗口类的各种属性是如何设置的,
// 包括样式、窗口过程函数、图标、光标、背景等,这些属性将影响窗口的外观和行为。
}
//-------------------------------------------------------------------------------------------------
// 函数: InitInstance(HINSTANCE, int)
//
// 目标: 保存实例句柄并创建主窗口
//
// 注释:
//
// 在此函数中,我们在全局变量中保存实例句柄并
// 创建和显示主程序窗口。
//这段代码是用于初始化应用程序实例的函数InitInstance。它接受一个实例句柄(hInstance)和一个显示命令(nCmdShow)作为参数。
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
//在函数内部,将传入的实例句柄存储在全局变量hInst中,以便其他函数可以访问它。
hInst = hInstance; // 将实例句柄存储在全局变量中
//然后,通过调用CreateWindowW函数创建一个窗口,并将窗口类名(szWindowClass)、窗口标题(szTitle)
// 和窗口样式(WS_OVERLAPPEDWINDOW)作为参数传递给它。
// 窗口的初始位置和大小使用CW_USEDEFAULT指定。
// 这个函数返回一个窗口句柄(hWnd)。
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
//接下来,使用条件判断语句检查窗口句柄是否创建成功。如果窗口句柄为NULL,表示创建窗口失败,则函数返回FALSE。
if (!hWnd)
{
return FALSE;
}
//如果窗口创建成功,将通过调用ShowWindow函数显示窗口,
// 并使用传入的显示命令(nCmdShow)来指定窗口的显示状态,
// 例如最大化、最小化或正常状态。
ShowWindow(hWnd, nCmdShow);
//然后,通过调用UpdateWindow函数更新窗口客户区的显示。
UpdateWindow(hWnd);
//最后,函数返回TRUE表示初始化成功。
return TRUE;
//通过这段代码,可以看到函数InitInstance实际上是将传入的实例句柄存储在全局变量中,
// 并创建并显示一个窗口。它负责初始化应用程序实例的一些基本操作。
}
//------------------------------------------------------------------------------------------------
// 函数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// 目标: 处理主窗口的消息。
//
// WM_COMMAND - 处理应用程序菜单
// WM_PAINT - 绘制主窗口
// WM_DESTROY - 发送退出消息并返回
//
//这段代码是一个窗口过程函数(WndProc),用于处理窗口的消息。
//窗口过程函数接受四个参数:窗口句柄(hWnd)、消息代码(message)、消息的附加信息(wParam和lParam)。
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
//在函数内部,通过使用switch语句根据不同的消息代码进行处理。
switch (message)
{
//当收到WM_COMMAND消息时,表示接收到菜单命令。
case WM_COMMAND:
{
//从wParam中获取菜单的ID(wmId),然后使用switch语句进一步处理选择的菜单ID。
int wmId = LOWORD(wParam);
// 分析菜单选择:
//然后使用switch语句进一步处理选择的菜单ID。
switch (wmId)
{
//当菜单ID为IDM_ABOUT时,调用DialogBox函数创建一个模态对话框,显示关于对话框。
// hInst表示应用程序的实例句柄,
// MAKEINTRESOURCE将资源ID转换为字符串,
// hWnd表示所属的窗口句柄,
// About是关于对话框的回调函数。
case IDM_ABOUT: //关于
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
//当菜单ID为IDM_EXIT时,调用DestroyWindow函数销毁窗口,结束应用程序的运行。
case IDM_EXIT: //退出
DestroyWindow(hWnd);
break;
//默认情况下,使用DefWindowProc函数进行默认的窗口消息处理。
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
//当收到WM_PAINT消息时,表示窗口客户区需要重绘。
// 在处理此消息时,首先通过调用BeginPaint函数创建一个绘图设备环境(HDC)
// 和一个PAINTSTRUCT结构体(ps),然后执行绘图操作。
// 绘图操作可以在注释处添加,然后通过调用EndPaint函数结束绘图,
// 并释放绘图设备上下文。
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: 在此处添加使用 hdc 的任何绘图代码...
TCHAR szInfo[] = _T("Hello, world!");
TextOut(hdc, 200, 20, szInfo,_tcslen(szInfo));
EndPaint(hWnd, &ps);
}
break;
//当收到WM_DESTROY消息时,表示窗口正在被销毁。
// 在处理此消息时,调用PostQuitMessage函数向消息队列发送一个退出消息,通知主消息循环退出。
case WM_DESTROY:
PostQuitMessage(0);
break;
//第一步
//当鼠标点击应用程序窗口的“客户区域”,操作系统将鼠标左键单机消息:WM_LBUTTONDOWN
//放到消息队列里。消息队列由操作系统维护。
//第二步
//由于应用程序的消息循环一直在运行,它的GetMessage函数从消息队列中获取消息,保存到MSG结构体中
/*
typedef struct tagMSG {
HWND hwnd; //消息所关联的窗口句柄
UINT message; //消息代码
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
#ifdef _MAC
DWORD lPrivate;
#endif
} MSG
*/
//第三步
//应用程序调用TranslateMessage,将虚拟建消息转换为字符消息。
//它处理键盘消息,不必关心这个函数的细节
//第四步
//应用程序调用DispatchMessage,DispatchMessage函数通知操作系统,
//操作系统根据DispatchMessage提供的窗口句柄,查找它的窗口句柄,
//查找它的窗口句柄表(操作系统维护了一个窗口句柄表)类似
/*
Hwnd1 窗口过程函数1
Hwnd2 窗口过程函数2
*/
//找到窗口句柄对应的窗口过程函数
//操作系统执行这个窗口过程函数
//第五步
//窗口过程函数对消息做出响应,执行完毕返回到DispatchMessage,回到消息循环
case WM_LBUTTONDOWN://鼠标左击的消息
{
POINT pt;
pt.x = GET_X_LPARAM(lParam);
pt.y = GET_Y_LPARAM(lParam);
WCHAR szOutput[128] = { 0 };
wsprintf(szOutput, _T("x:%d,y:%d\n"), pt.x, pt.y);
OutputDebugString(szOutput);
}
break;
//默认情况下,使用DefWindowProc函数进行默认的窗口消息处理。
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
//最后,窗口过程函数返回一个LRESULT类型的值,通常是0。这个返回值的具体含义取决于消息的类型和处理方式。
return 0;
//通过这段代码,我们可以看到窗口过程函数根据不同的消息类型执行相应的操作,从而实现了对窗口消息的处理。
}
//-------------------------------------------------------------------------------------------------------
// “关于”框的消息处理程序。
//这段代码是一个关于对话框的回调函数(About),用于处理关于对话框的消息。
//回调函数接受四个参数:
// 对话框句柄(hDlg)、
// 消息代码(message)、
// 消息的附加信息(wParam和lParam)。
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
//在函数内部,通过使用switch语句根据不同的消息代码进行处理。
switch (message)
{
//当收到WM_INITDIALOG消息时,表示对话框即将初始化。
// 在处理此消息时,将返回(INT_PTR)TRUE,表示对话框初始化成功。
case WM_INITDIALOG:
return (INT_PTR)TRUE;
//当收到WM_COMMAND消息时,表示接收到控件的命令消息。
// 在处理此消息时,首先检查wParam中的控件ID(LOWORD(wParam))。
// 如果是IDOK或者IDCANCEL,表示点击了“确定”或“取消”按钮。
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
//当点击了“确定”或“取消”按钮时,
// 调用EndDialog函数结束对话框,
// 并将按钮的ID作为参数传递给EndDialog函数。
// 然后返回(INT_PTR)TRUE,表示对话框处理成功。
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
//默认情况下,返回(INT_PTR)FALSE,表示对话框处理失败。
return (INT_PTR)FALSE;
//通过这段代码,我们可以看到关于对话框的回调函数根据不
// 同的消息类型执行相应的操作,例如初始化对话框、处理按钮点击等。
// 在处理完消息后,根据返回值决定对话框的继续运行或结束。
} 标签:窗口,函数,Windows,句柄,应用程序,源文件,窗体,消息,cpp From: https://www.cnblogs.com/bigbabyone/p/17745044.html