实验三 一次性口令设计实验

实验三  一次性口令设计实验

【实验目的】

  1. 了解口令机制在系统安全中的重要意义。
  2. 掌握动态生成一次性口令的程序设计方法。

【实验内容】

  1. 编写一个一次性口令程序
  2. 运行该口令程序,屏幕上弹出一个仿Windows窗口,提示用户输入口令,并给出提示模式。
  3. 用户输入口令,按照一次性算法计算比较,符合,给出合法用户提示;否则给出非法用户提示。
  4. 再一次运行口令程序,如果输入与第一次同样的口令,系统应当拒绝,提示非法用户。每次提示和输入的口令都是不一样的。
  5. 写出设计说明(含公式、算法,随机数产生法,函数调用和参数传递方式)

【实验设备与环境】

  1. 个人计算机
  2. Windows系统平台
  3. 开发语言不限

【实验方法步骤】

  1. 选择一个一次性口令的算法
  2. 选择随机数产生器
  3. 给出口令输入(密码)提示
  4. 用户输入口令(密码)
  5. 给出用户确认提示信息
  6. 调试、运行、验证。

【实验报告要求】

  1. 提交所有程序代码
  2. 提交设计说明

实验注意事项】

1、口令设计

    一次性口令设计必须注意以下问题:

  1. 输入密码(口令)存放问题与比较方式
  2. 输入口令是否加密和加密方式
  3. 算法有无二义性
  4. 算法是否容易被破译
  5. 重复输入错误处理方法

2、口令程序的后台运行

    一次性口令可以预先放置在系统启动程序中,也可以预先填入Windows注册表,当系统启动后自动运行,首先进行口令提示,达到开机口令的目的。如果要达到此项功能,必须修改系统配置文件或者系统注册表。对不同的操作系统,系统配置文件和注册表的修改方式和修改项各有不同。步骤为:

(1) 熟悉Win注册表或文件

(2) 将口令程序填写入注册表中相关表项

  1. 重新启动后进入后台运行
  2. 提示界面:仿Windows界面
  3. 交互方式:键盘输入
  4. 设计文档:给出设计说明(含公式、算法,随机数产生法,函数调用和参数传递方式)

【相关知识点】

1、一次性口令设计

口令攻击常常作为黑客目标攻击的开始,一旦黑客获取了目标机上的用户口令,就可以进入目标计算机,对目标机造成严重的安全威胁。

一次性口令是增强口令安全的有效方法之一。其主要设计思想是:设计一种动态生成口令的算法,使生成的口令只能使用一次,当再次使用时,该口令无效。从而有效地避免了基于口令破解的口令攻击。

2、 算法设计

    可以通过以下两种方式设计算法

(1)数学计算式

    选定一个数学计算式(函数),系统提供该函数的一个变量,用户计算并返回函数值,按照用户的响应判断其真实性。

     e.g.1: f(x)=x+1

     系统提示x,用户输入x+1

(2)字符串组合式

     选定一个字符串组合式,系统提供特征字符串,用户根据组合方式返回字符串,系统按照用户的响应判断其真实性。

     e.g.2: f(a1a2a3a4a5a6)=a1a3a4a6

     系统提供特征串:Friend

     用户变换此字符串为:Fied

     输入后进行口令认证。

评分要求100

  1. 程序运行正常(不死机)40分
  2. 密码输入正常10分
  3. 一次性口令功能正常20分
  4. 界面设计良好10分
  5. 有设计文档10分
  6. 有新增功能10分

一次性口令算法这里采取f(x)=3x+1,长度采取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即从0 \textasciitilde ~2^{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以便每次点击确认后文本给出的随机数都会更新.

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

shuonine5b

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值