实验三 一次性口令设计实验
【实验目的】
- 了解口令机制在系统安全中的重要意义。
- 掌握动态生成一次性口令的程序设计方法。
【实验内容】
- 编写一个一次性口令程序
- 运行该口令程序,屏幕上弹出一个仿Windows窗口,提示用户输入口令,并给出提示模式。
- 用户输入口令,按照一次性算法计算比较,符合,给出合法用户提示;否则给出非法用户提示。
- 再一次运行口令程序,如果输入与第一次同样的口令,系统应当拒绝,提示非法用户。每次提示和输入的口令都是不一样的。
- 写出设计说明(含公式、算法,随机数产生法,函数调用和参数传递方式)
【实验设备与环境】
- 个人计算机
- Windows系统平台
- 开发语言不限
【实验方法步骤】
- 选择一个一次性口令的算法
- 选择随机数产生器
- 给出口令输入(密码)提示
- 用户输入口令(密码)
- 给出用户确认提示信息
- 调试、运行、验证。
【实验报告要求】
- 提交所有程序代码
- 提交设计说明
【实验注意事项】
1、口令设计
一次性口令设计必须注意以下问题:
- 输入密码(口令)存放问题与比较方式
- 输入口令是否加密和加密方式
- 算法有无二义性
- 算法是否容易被破译
- 重复输入错误处理方法
2、口令程序的后台运行
一次性口令可以预先放置在系统启动程序中,也可以预先填入Windows注册表,当系统启动后自动运行,首先进行口令提示,达到开机口令的目的。如果要达到此项功能,必须修改系统配置文件或者系统注册表。对不同的操作系统,系统配置文件和注册表的修改方式和修改项各有不同。步骤为:
(1) 熟悉Win注册表或文件
(2) 将口令程序填写入注册表中相关表项
- 重新启动后进入后台运行
- 提示界面:仿Windows界面
- 交互方式:键盘输入
- 设计文档:给出设计说明(含公式、算法,随机数产生法,函数调用和参数传递方式)
【相关知识点】
1、一次性口令设计
口令攻击常常作为黑客目标攻击的开始,一旦黑客获取了目标机上的用户口令,就可以进入目标计算机,对目标机造成严重的安全威胁。
一次性口令是增强口令安全的有效方法之一。其主要设计思想是:设计一种动态生成口令的算法,使生成的口令只能使用一次,当再次使用时,该口令无效。从而有效地避免了基于口令破解的口令攻击。
2、 算法设计
可以通过以下两种方式设计算法
(1)数学计算式
选定一个数学计算式(函数),系统提供该函数的一个变量,用户计算并返回函数值,按照用户的响应判断其真实性。
e.g.1: f(x)=x+1
系统提示x,用户输入x+1
(2)字符串组合式
选定一个字符串组合式,系统提供特征字符串,用户根据组合方式返回字符串,系统按照用户的响应判断其真实性。
e.g.2: f(a1a2a3a4a5a6)=a1a3a4a6
系统提供特征串:Friend
用户变换此字符串为:Fied
输入后进行口令认证。
【评分要求】100分
- 程序运行正常(不死机)40分
- 密码输入正常10分
- 一次性口令功能正常20分
- 界面设计良好10分
- 有设计文档10分
- 有新增功能10分
一次性口令算法这里采取,长度采取6位.
首先由程序生成6位随机数给用户,然后提示用户输入口令,在用户输入后给出相应的提示然后更新随机数.
效果:
完整程序如下
#include <windows.h>
#include <tchar.h>
#include <string>
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
typedef unsigned long long llu;
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
llu random_number(){
llu ans = 0;
srand((int)time(0));
for ( int i = 0; i < 6; i++ ) {
ans += rand()%10;
ans *= 10;
}
return ans/10;
}
HWND hTextBox; // 声明文本框句柄
HWND hButton; // 声明按钮句柄
HWND hStatic; // 声明静态文本句柄
int *randomNumber = nullptr;
void UpdateStaticText( int *randomNumber ) {
*randomNumber = random_number(); // 修改randomNumber的值
char formattedText[256];
sprintf(formattedText, "口令为%d×3+1 mod 1000000,请输入", *randomNumber);
SetWindowTextA(hStatic, formattedText);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
//分配指针空间
randomNumber = new int;
// 关闭控制台
FreeConsole();
// 注册窗口
WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, WindowProc, 0L, 0L, GetModuleHandle(NULL), NULL, NULL, NULL, NULL, _T("MyWindow"), NULL };
RegisterClassEx(&wc);
// 创建窗口
HWND hwnd = CreateWindow(wc.lpszClassName, _T("实验三 一次性口令设计"), WS_OVERLAPPEDWINDOW & ~WS_SIZEBOX & ~WS_MAXIMIZEBOX, 600, 300, 400, 200, NULL, NULL, wc.hInstance, NULL);
// 创建静态文本控件
hStatic = CreateWindow(_T("STATIC"), _T("口令为random×3+1 mod 1000000,请输入"), WS_CHILD | WS_VISIBLE, 60, 40, 280, 16, hwnd, NULL, hInstance, NULL);
//更新静态文本控件
UpdateStaticText( randomNumber );
// 创建文本框
hTextBox = CreateWindowEx(WS_EX_CLIENTEDGE, _T("EDIT"), _T(""), WS_CHILD | WS_VISIBLE | ES_NUMBER, 100, 80, 200, 25, hwnd, NULL, hInstance, NULL);
// 创建按钮
hButton = CreateWindow(_T("BUTTON"), _T("确认"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 310, 80, 40, 25, hwnd, NULL, hInstance, NULL);
// 设置焦点以便直接编辑
SetFocus(hTextBox);
// 显示窗口
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
// 消息循循环
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// 注销窗口类
UnregisterClass(wc.lpszClassName, wc.hInstance);
delete randomNumber;
return 0;
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
static string inputString;
llu test = 0;
char inputChar;
switch (uMsg) {
case WM_CLOSE:
PostQuitMessage(0);
break;
case WM_COMMAND:
if (lParam == (LPARAM)hTextBox) {
if (HIWORD(wParam) == EN_CHANGE) {
// 文本框内容发生变化
char buffer[256];
GetWindowTextA(hTextBox, buffer, sizeof(buffer));
inputString = buffer;
}
}
if (HIWORD(wParam) == BN_CLICKED)
if ( LOWORD(wParam) == (WORD)GetDlgCtrlID(hButton) ) { // 处理按钮点击事件
// 获取文本框内容
char buffer[256];
GetWindowTextA(hTextBox, buffer, sizeof(buffer));
inputString = buffer;
// 检查输入是否是纯数字
bool isNumeric = true;
for (char c : inputString) {
if (!isdigit(c)) {
isNumeric = false;
break;
}
}
if (isNumeric) {
// 输入是纯数字,处理输入
test = atoll(inputString.c_str());
llu ans = (3* *randomNumber+1)%1000000;
char message[256];
if ( ans == test ) MessageBox(hwnd, _T("合法用户"), _T("提示"), MB_OK | MB_ICONASTERISK);
else {
sprintf(message, "非法用户,口令为%llu", ans);
MessageBox(hwnd, message, _T("提示"), MB_OK | MB_ICONERROR);
}
UpdateStaticText(randomNumber);
SetWindowText(hTextBox, _T(""));
} else {
// 输入不是纯数字,显示错误消息
MessageBox(hwnd, _T("请输入有效的数字"), _T("错误"), MB_OK | MB_ICONERROR);
}
}
break;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}
逐行解释
typedef unsigned long long llu;
定义了一个新的数据类型别名llu,其中llu 是 unsigned long long的缩写,在这行定义之后便可以采用llu来代替unsigned long long.采用unsigned long long是为了防止后面计算过程中溢出.因为unsigned long long是64位无符号数,最大为64个1即从
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
定义一个窗口过程(Window Procedure)的函数原型。在Windows编程中,窗口过程是一个回调函数,用于处理窗口消息和事件.该函数会接收四个参数:
1.HWND hwnd:表示窗口句柄,用于标识要处理消息的窗口
2.UINT uMsg:表示窗口消息的标识符,指示了要处理的消息类型.消息可以是诸如鼠标点击、键盘输入、窗口尺寸变化等事件
3.WPARAM wParam:这是一个整数值,通常用于传递与消息相关的附加信息,例如,如果消息是鼠标点击消息,wParam
可能包含鼠标的状态信息
4.LPARAM lParam:这也是一个整数值,通常用于传递与消息相关的更多附加信息。
llu random_number(){
llu ans = 0;
srand((int)time(0));
for ( int i = 0; i < 6; i++ ) {
ans += rand()%10;
ans *= 10;
}
return ans/10;
}
生成随机数,返回类型为llu.rand()函数用于生成伪随机数,但在每次程序运行时,它生成的随机数序列通常是相同的。为了使随机数生成更具随机性,可以使用srand() 函数来设置随机数生成器的种子。srand()函数接受一个整数值作为种子,以便在生成随机数时使用该种子作为起始点。time(0) 函数返回当前时间的表示,通常是从某个特定时间点(通常是1970年1月1日午夜,称为UNIX时间戳)经过的秒数。将time(0) 的返回值强制转换为整数(int)可以将时间戳转换为整数,以便作为srand() 函数的种子。这样,每次程序运行时,种子将基于当前时间,因此rand()将生成不同的随机数序列. rand()%10每次将生成10以内的数,逐次×10执行六次得到一个七位随机数,最后返回除以10的结果就是六位数
HWND hTextBox; // 声明文本框句柄
HWND hButton; // 声明按钮句柄
HWND hStatic; // 声明静态文本句柄
声明了三个不同的句柄(HWND
),分别用于表示窗口元素(控件)的句柄。通常在Windows图形用户界面(GUI)编程中,句柄用于标识和操作窗口元素,如文本框、按钮和静态文本。
HWND hTextBox;:这一行声明了一个名为 hTextBox 的变量,它是一个窗口句柄(Handle to Window)。通常情况下,hTextBox 可能用于表示一个文本框控件的句柄。这个句柄可以用来操作文本框,例如设置文本内容、获取文本内容等。
HWND hButton;:这一行声明了一个名为 hButton 的变量,同样它也是一个窗口句柄。通常情况下,hButton 可能用于表示一个按钮控件的句柄。这个句柄可以用来操作按钮,例如捕获按钮点击事件或者改变按钮的文本标签等。
HWND hStatic;:这一行声明了一个名为 hStatic 的变量,同样它也是一个窗口句柄。通常情况下,hStatic 可能用于表示一个静态文本控件的句柄。这个句柄可以用来操作静态文本,例如设置静态文本的内容或者更改其外观。
int *randomNumber = nullptr;
全局指针,用于保存生成的随机数
void UpdateStaticText( int *randomNumber ) {
*randomNumber = random_number(); // 修改randomNumber的值
char formattedText[256];
sprintf(formattedText, "口令为%d×3+1 mod 1000000,请输入", *randomNumber);
SetWindowTextA(hStatic, formattedText);
}
更新文本,
char formattedText[256];:这一行代码声明了一个名为 formattedText 的字符数组,用于存储将要设置为静态文本控件的文本内容。这个数组有足够的空间来容纳文本内容,最大长度为256个字符。
sprintf(formattedText, "口令为%d×3+1 mod 1000000,请输入", *randomNumber);:这行代码使用 sprintf 函数将格式化的文本串生成到 formattedText 中。文本串中包含 %d 占位符,该占位符将被 *randomNumber 的值替换,因此最终的文本内容将包含 *randomNumber 变量的值。
SetWindowTextA(hStatic, formattedText);最后,这行代码使用 SetWindowTextA 函数将生成的 formattedText 设置为静态文本控件 hStatic 的文本内容。这将导致静态文本显示新的文本内容,其中包括计算结果和指示用户输入的信息。
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
WinMain 函数是Windows图形应用程序的入口点,它在应用程序启动时被调用,负责初始化应用程序、创建窗口和处理消息循环等操作.类似于平时写的int main
//分配指针空间
randomNumber = new int;
为之前建立的全局变量分配空间
// 关闭控制台
FreeConsole();
在WinMain函数内调用此函数后在执行exe程序时就不会唤起终端窗口.在IDE中执行程序可能仍然会看到窗口,这是由于IDE调用的问题.手动点击exe程序就不会显示终端窗口.
// 注册窗口
WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, WindowProc, 0L, 0L, GetModuleHandle(NULL), NULL, NULL, NULL, NULL, _T("MyWindow"), NULL };
RegisterClassEx(&wc);
WNDCLASSEX wc = { ... };:这一行代码创建了一个名为 wc 的 WNDCLASSEX 结构体变量,并使用大括号 { ... } 初始化了它。WNDCLASSEX 是一个包含窗口类信息的结构体。结构体成员的初始化如下:
sizeof(WNDCLASSEX):表示结构体的大小,通常使用 sizeof 运算符来获取结构体的字节大小。
CS_CLASSDC:表示窗口类的风格(style)。在这里,CS_CLASSDC 表示窗口类将共享设备上下文(Device Context)。
WindowProc:这是窗口过程(Window Procedure)的函数指针,用于处理窗口消息。WindowProc 是一个程序员自己编写的函数,用于处理窗口消息和事件。
GetModuleHandle(NULL):这是用于获取应用程序模块句柄(Handle to Module)的函数,通常用于在应用程序中获取模块(即可执行文件)的句柄。
_T("MyWindow"):这是一个字符串,表示窗口类的名称。窗口类名称是一个应用程序定义的标识符,用于标识窗口类。
RegisterClassEx(&wc);:这一行代码将上面定义的窗口类信息注册到Windows操作系统中。RegisterClassEx 函数接受一个指向 WNDCLASSEX 结构体的指针,这里是 &wc,以注册窗口类。
一旦窗口类被成功注册,应用程序就可以使用该窗口类来创建窗口实例。注册窗口类是在应用程序启动时执行的重要步骤,因为它告诉操作系统如何处理并显示窗口,以及如何调用指定的窗口过程函数来处理窗口消息。
// 创建窗口
HWND hwnd = CreateWindow(wc.lpszClassName, _T("实验三 一次性口令设计"), WS_OVERLAPPEDWINDOW & ~WS_SIZEBOX & ~WS_MAXIMIZEBOX, 600, 300, 400, 200, NULL, NULL, wc.hInstance, NULL);
HWND hwnd:这一行代码声明了一个名为 hwnd 的窗口句柄变量。窗口句柄是用来标识和操作窗口的唯一标识符。
CreateWindow 函数:这是一个Windows API函数,用于创建一个窗口。它接受多个参数,用于指定窗口的各种属性和特性。
wc.lpszClassName:这是之前注册的窗口类的名称,即_T("MyWindow")。它告诉Windows操作系统要创建的窗口将使用哪个窗口类的属性。
_T("实验三 一次性口令设计"):这是窗口的标题,显示在窗口的标题栏中,以便用户能够识别窗口的用途。
WS_OVERLAPPEDWINDOW & ~WS_SIZEBOX & ~WS_MAXIMIZEBOX:这是窗口的样式(style)设置。WS_OVERLAPPEDWINDOW 表示创建一个标准的窗口,包括标题栏、系统菜单、最小化和关闭按钮等。~WS_SIZEBOX 和 ~WS_MAXIMIZEBOX 是按位取反操作,用于禁用窗口的大小调整和最大化按钮,以确保用户无法调整窗口的大小。
600、300、400、200:这些参数分别表示窗口的左上角坐标(x和y坐标)以及窗口的宽度和高度。这些值确定了窗口在屏幕上的位置和尺寸。
NULL, NULL:这是窗口的父窗口和菜单句柄,通常设置为NULL,表示没有父窗口和菜单。
wc.hInstance:这是应用程序的实例句柄,即应用程序模块的句柄,通常用于与应用程序实例相关的操作。
NULL:这是传递给窗口的额外数据,通常用于向窗口过程传递一些自定义数据。
一旦 CreateWindow 函数被调用,它会创建一个具有指定属性和样式的窗口,并返回一个窗口句柄,该句柄存储在 hwnd 变量中。窗口句柄可用于操作和管理窗口,例如更新窗口内容、处理窗口消息等。
// 创建静态文本控件
hStatic = CreateWindow(_T("STATIC"), _T("口令为random×3+1 mod 1000000,请输入"), WS_CHILD | WS_VISIBLE, 60, 40, 280, 16, hwnd, NULL, hInstance, NULL);
hStatic:这是一个先前声明的窗口句柄变量,用于存储新创建的静态文本控件的句柄。在这个代码段之前,hStatic 可能已经在程序中被声明和初始化。
CreateWindow 函数:这是Windows API函数,用于创建窗口控件。在这里,它被用来创建一个静态文本控件。
_T("STATIC"):这是控件的类名,表示要创建一个静态文本控件。在Windows中,静态文本控件用于显示文本信息,通常不接受用户输入。
_T("口令为random×3+1 mod 1000000,请输入"):这是控件的初始文本内容,即静态文本控件中显示的文本。
WS_CHILD | WS_VISIBLE:这是控件的样式(style)。WS_CHILD 表示这是一个子窗口,WS_VISIBLE 表示控件初始时是可见的。这些样式设置控制了控件的行为和可见性。
60、40、280、16:这些参数分别表示控件的左上角坐标(x和y坐标)以及控件的宽度和高度。这些值确定了控件在窗口内的位置和尺寸。
hwnd:这是控件的父窗口句柄,表示静态文本控件将作为窗口 hwnd 的子控件。
hInstance:这是应用程序的实例句柄,即应用程序模块的句柄,通常用于与应用程序实例相关的操作。
NULL:这是传递给控件的额外数据,通常用于向控件过程传递一些自定义数据。
一旦 CreateWindow 函数被调用,它会创建一个静态文本控件,该控件会显示指定的文本内容,并返回一个控件句柄,该句柄存储在 hStatic 变量中。这个句柄可以用于后续操作,例如在控件上设置文本内容或改变其外观。
//更新静态文本控件
UpdateStaticText( randomNumber );
调用之前的函数,在文本控件被创建之后更新它的内容
// 创建文本框
hTextBox = CreateWindowEx(WS_EX_CLIENTEDGE, _T("EDIT"), _T(""), WS_CHILD | WS_VISIBLE | ES_NUMBER, 100, 80, 200, 25, hwnd, NULL, hInstance, NULL);
hTextBox:这是一个先前声明的窗口句柄变量,用于存储新创建的文本框控件的句柄。在这个代码段之前,hTextBox 可能已经在程序中被声明和初始化。
CreateWindowEx 函数:这是Windows API函数,用于创建窗口控件,可以在之前的代码中见到它的使用。
WS_EX_CLIENTEDGE:这是一个扩展窗口样式(extended window style),在这里用于为文本框控件添加一个凸起的边框。
_T("EDIT"):这是控件的类名,表示要创建一个文本框控件。文本框控件通常用于接受用户的文本输入。
_T(""):这是文本框控件的初始文本内容。在这里为空,因此文本框是空白的。
WS_CHILD | WS_VISIBLE | ES_NUMBER:这是控件的样式(style)。WS_CHILD 表示这是一个子窗口,WS_VISIBLE 表示控件初始时是可见的,ES_NUMBER 表示文本框只接受数字输入,因此用户无法输入其他字符。
100、80、200、25:这些参数分别表示控件的左上角坐标(x和y坐标)以及控件的宽度和高度。这些值确定了控件在窗口内的位置和尺寸。
hwnd:这是控件的父窗口句柄,表示文本框控件将作为窗口 hwnd 的子控件。
hInstance:这是应用程序的实例句柄,即应用程序模块的句柄,通常用于与应用程序实例相关的操作。
NULL:这是传递给控件的额外数据,通常用于向控件过程传递一些自定义数据。
一旦 CreateWindowEx 函数被调用,它会创建一个文本框控件,该控件可以接受用户的文本输入,并返回一个控件句柄,该句柄存储在 hTextBox 变量中。这个句柄可以用于后续操作,例如获取或设置文本框中的文本内容,以及处理与文本框相关的事件
// 创建按钮
hButton = CreateWindow(_T("BUTTON"), _T("确认"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 310, 80, 40, 25, hwnd, NULL, hInstance, NULL);
hButton:这是一个先前声明的窗口句柄变量,用于存储新创建的按钮控件的句柄。在这个代码段之前,hButton 可能已经在程序中被声明和初始化。
CreateWindow 函数:这是Windows API函数,用于创建窗口控件,可以在之前的代码中见到它的使用。
_T("BUTTON"):这是控件的类名,表示要创建一个按钮控件。按钮控件通常用于触发操作或事件,如用户单击按钮时触发的操作。
_T("确认"):这是按钮控件的文本标签,显示在按钮上,以便用户知道按钮的目的或功能。
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON:这是控件的样式(style)。WS_CHILD 表示这是一个子窗口,WS_VISIBLE 表示控件初始时是可见的,BS_PUSHBUTTON 表示按钮控件为普通的按下按钮,用户单击它时会触发相关事件。
310、80、40、25:这些参数分别表示控件的左上角坐标(x和y坐标)以及控件的宽度和高度。这些值确定了控件在窗口内的位置和尺寸。
hwnd:这是控件的父窗口句柄,表示按钮控件将作为窗口 hwnd 的子控件。
hInstance:这是应用程序的实例句柄,即应用程序模块的句柄,通常用于与应用程序实例相关的操作。
NULL:这是传递给控件的额外数据,通常用于向控件过程传递一些自定义数据。
一旦 CreateWindow 函数被调用,它会创建一个按钮控件,该控件会显示指定的文本标签,用户可以单击它来触发相关事件,然后返回一个控件句柄,该句柄存储在 hButton 变量中。这个句柄可以用于后续操作,例如在按钮上设置文本标签或处理与按钮相关的事件。
// 设置焦点以便直接编辑
SetFocus(hTextBox);
SetFocus函数会在一个控件被创建后将焦点设置在上面,类似于打卡浏览器后光标自动被设置到搜索框中
// 显示窗口
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
显示窗口,更新句柄
// 消息循循环
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
MSG msg;:这一行代码声明了一个名为 msg 的消息结构体(MSG)。消息结构体用于存储从消息队列中接收的消息。
while (GetMessage(&msg, NULL, 0, 0)):这是一个循环,它不断从消息队列中获取消息并处理它们。GetMessage 函数用于从消息队列中获取一条消息,它的参数定义如下:
第一个参数 &msg:用于接收消息的消息结构体。
第二个参数 NULL:用于指定窗口句柄,通常设置为 NULL 表示获取所有线程的消息。
第三个参数 0:用于指定要接收的消息的最小消息值。
第四个参数 0:用于指定要接收的消息的最大消息值。
循环会一直执行,直到没有更多消息要处理(例如,窗口关闭时消息队列为空),此时 GetMessage 函数会返回一个假值(FALSE),退出循环。
TranslateMessage(&msg);:在消息循环中,通常会调用 TranslateMessage 函数来翻译一些消息,主要是键盘输入消息。这个函数将原始键盘消息翻译为字符消息,以便在窗口过程中处理。
DispatchMessage(&msg);:这一行代码调用 DispatchMessage 函数,将消息传递给适当的窗口过程(Window Procedure),以便处理消息。窗口过程是开发者编写的函数,用于响应和处理窗口消息,例如处理鼠标点击、键盘输入、窗口尺寸变化等事件。
这个消息循环的目的是不断处理来自操作系统的消息,例如用户的输入、窗口事件等。通过调用适当的窗口过程,应用程序能够响应这些消息,执行相应的操作和事件处理。这种消息循环是GUI应用程序的核心,确保应用程序能够与用户进行交互并实时响应用户的输入。
// 注销窗口类
UnregisterClass(wc.lpszClassName, wc.hInstance);
UnregisterClass(wc.lpszClassName, wc.hInstance);:这是一个Windows API函数,用于注销一个之前注册的窗口类。它接受两个参数:
wc.lpszClassName:这是要注销的窗口类的名称。wc.lpszClassName 包含了在注册窗口类时指定的窗口类的名称。
wc.hInstance:这是窗口类所属的应用程序实例的句柄,即应用程序模块的句柄。这个句柄用于确定要注销的窗口类的所属应用程序。
delete randomNumber;
删除指针
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
前面声明过的定义一个窗口过程.
LRESULT:这是函数的返回类型,表示函数返回的是一个长整数值(通常用于表示处理结果)。LRESULT 常常用于窗口过程函数,用于指示消息处理的结果或其他信息。
CALLBACK:这是一个宏,通常被定义为 __stdcall,它指定了函数的调用约定。在Windows API中,CALLBACK 通常用于确保正确的函数调用约定。
WindowProc:这是函数的名称,通常是用户自定义的,可以根据需要进行命名。这个函数被Windows操作系统调用,以处理窗口消息。
HWND hwnd:这是一个参数,表示与窗口消息相关的窗口句柄。hwnd 用于标识哪个窗口接收了消息,从而可以针对特定窗口执行相应的处理。
UINT uMsg:这是一个参数,表示接收到的消息的类型。消息是整数常数,用于标识不同类型的事件或操作,例如鼠标点击、键盘输入、窗口尺寸变化等。uMsg 参数用于确定消息的类型,以便适当地处理消息。
WPARAM wParam:这是一个参数,通常包含消息的附加信息,可以根据不同的消息类型来解释。例如,对于键盘输入消息,wParam 可能包含按下的键码,而对于鼠标点击消息,它可能包含鼠标事件的详细信息。
LPARAM lParam:这也是一个参数,通常包含消息的附加信息,类似于 wParam,但通常包含更多的数据。 lParam 可以根据不同的消息类型来解释。
static string inputString;
llu test = 0;
char inputChar;
定义变量用于处理输入
switch (uMsg) {
case WM_CLOSE:
PostQuitMessage(0);
break;
case WM_COMMAND:
WM_CLOSE:这是窗口关闭消息。当用户尝试关闭窗口(通常通过单击关闭按钮或按下关闭窗口的快捷键时),Windows会发送 WM_CLOSE 消息到窗口过程函数,以通知应用程序窗口即将关闭。在这段代码中,当收到 WM_CLOSE 消息时,通过 PostQuitMessage(0) 发送一个退出消息,用于通知应用程序退出。
PostQuitMessage(0):这个函数通知应用程序的消息循环停止执行,同时返回一个退出代码(在这里是0),表示正常退出应用程序。应用程序将在处理完所有消息后退出。
WM_COMMAND:这是一个通用的窗口命令消息,通常与控件(如按钮、菜单项)的交互有关。当用户单击按钮或执行与控件相关的操作时,Windows会发送 WM_COMMAND 消息到窗口过程函数,以通知应用程序发生了某种用户交互事件。在这段代码中,WM_COMMAND 消息的处理逻辑可能会在后续的 switch 语句中定义,具体处理方式取决于 wParam 和 lParam 中的参数值。
case WM_COMMAND:
if (lParam == (LPARAM)hTextBox) {
if (HIWORD(wParam) == EN_CHANGE) {
// 文本框内容发生变化
char buffer[256];
GetWindowTextA(hTextBox, buffer, sizeof(buffer));
inputString = buffer;
}
case WM_COMMAND::这是一个 switch 语句中的 case 分支,用于处理 WM_COMMAND 消息类型,这是一个通用的窗口命令消息。当用户与控件(如按钮、文本框等)进行交互时,Windows会发送 WM_COMMAND 消息给窗口过程函数,以通知应用程序发生了一些用户操作。
if (lParam == (LPARAM)hTextBox):这是一个条件语句,用于检查 lParam 是否等于 (LPARAM)hTextBox,其中 lParam 通常包含有关消息的附加信息,hTextBox 是一个窗口句柄,代表文本框控件。
如果条件成立,表示该 WM_COMMAND 消息与特定的文本框控件 (hTextBox) 有关。
if (HIWORD(wParam) == EN_CHANGE):这是条件语句的嵌套部分。它用于检查 wParam 中的消息参数是否包含 EN_CHANGE 通知。
wParam 通常包含控件标识符(通知消息的来源控件)和通知码。在这里,HIWORD(wParam) 用于提取通知码部分,并检查是否等于 EN_CHANGE。
如果条件成立,表示 WM_COMMAND 消息的来源是文本框控件,并且用户已经更改了文本框中的文本内容。接下来调用GetWindowTextA函数获取文本框的内容并传递给字符串inputString
if (HIWORD(wParam) == BN_CLICKED)
if ( LOWORD(wParam) == (WORD)GetDlgCtrlID(hButton) ) { // 处理按钮点击事件
检查是否点击了按钮.
if (HIWORD(wParam) == BN_CLICKED):这是外层的条件语句。它用于检查 wParam 中的消息参数是否包含 BN_CLICKED 通知。
wParam 通常包含控件标识符(通知消息的来源控件)和通知码。在这里,HIWORD(wParam) 用于提取通知码部分,并检查是否等于 BN_CLICKED。
如果条件成立,表示 WM_COMMAND 消息的来源是一个按钮控件,而且用户已经单击了按钮。
if (LOWORD(wParam) == (WORD)GetDlgCtrlID(hButton)):这是内层的条件语句,用于检查消息来自特定的按钮控件。
LOWORD(wParam) 用于提取 wParam 中的控件标识符(通知消息的来源控件的ID)。
(WORD)GetDlgCtrlID(hButton) 用于获取 hButton 控件的ID,并将其转换为WORD类型。
如果这两者相等,表示按钮点击事件来自与 hButton 相关的按钮控件
// 检查输入是否是纯数字
bool isNumeric = true;
for (char c : inputString) {
if (!isdigit(c)) {
isNumeric = false;
break;
}
}
遍历字符串检查是否为纯数字
if (isNumeric) {
// 输入是纯数字,处理输入
test = atoll(inputString.c_str());
llu ans = (3* *randomNumber+1)%1000000;
char message[256];
if ( ans == test ) MessageBox(hwnd, _T("合法用户"), _T("提示"), MB_OK | MB_ICONASTERISK);
else {
sprintf(message, "非法用户,口令为%llu", ans);
MessageBox(hwnd, message, _T("提示"), MB_OK | MB_ICONERROR);
}
UpdateStaticText(randomNumber);
SetWindowText(hTextBox, _T(""));
} else {
// 输入不是纯数字,显示错误消息
MessageBox(hwnd, _T("请输入有效的数字"), _T("错误"), MB_OK | MB_ICONERROR);
}
如果是纯数字,则检验是否合法并调用MessageBox函数给出相应的提示.最后再次调用UpdateStaticText以便每次点击确认后文本给出的随机数都会更新.