Win32API标准模板

#include<Windows.h>

LRESULT CALLBACK WndProc //处理发送到窗口的消息的应用程序定义的函数。wndproc类型定义指向此回调函数的指针。
						 //WindowProc是应用程序定义函数名的占位符。
						 //参考:https://msdn.microsoft.com/en-us/library/ms633573(v=VS.85).aspx
(
	HWND, //hwnd 窗口的句柄
	UINT, //uMsg 消息。 有关系统提供的消息的列表,请参阅系统定义的消息。
	WPARAM, //wParam 其他消息信息。 此参数的内容取决于uMsg参数的值。
	LPARAM //lParam 其他消息信息。 此参数的内容取决于uMsg参数的值。
);

int WINAPI WinMain//用户提供的基于Windows的图形应用程序的入口点。
				  //WinMain是用于应用程序入口点的常规名称。 有关更多信息,请参阅备注。
				  //参考:https://docs.microsoft.com/zh-cn/windows/desktop/api/winbase/nf-winbase-winmain
(
	HINSTANCE hInstance, //应用程序当前实例的句柄。
	HINSTANCE hPrevInstance, //上一个应用程序实例的句柄。 
							 //此参数始终为NULL。 
							 //如果需要检测是否已存在其他实例,请使用CreateMutex函数创建唯一命名的互斥锁。 
							 //即使互斥锁已经存在,CreateMutex也会成功,但该函数将返回ERROR_ALREADY_EXISTS。 
							 //这表示您的应用程序的另一个实例存在,因为它首先创建了互斥锁。 
							 //但是,恶意用户可以在执行此操作之前创建此互斥锁,并阻止您的应用程序启动。 
							 //要防止出现这种情况,请创建一个随机命名的互斥锁并存储该名称,以便只能由授权用户获取。 
							 //或者,您可以使用文件来实现此目的。 
							 //要将应用程序限制为每个用户一个实例,请在用户的配置文件目录中创建一个锁定文件。
	PSTR szCmdLine, //应用程序的命令行,不包括程序名称。 要检索整个命令行,请使用GetCommandLine函数。
	int iCmdshow //TBD
)
{
	static TCHAR szAppName[] = TEXT("MyWindows");
	HWND hwnd;
	MSG msg;
	WNDCLASS wndclass;//包含RegisterClass函数注册的窗口类属性。
					  //参考:https://docs.microsoft.com/en-us/windows/desktop/api/winuser/ns-winuser-tagwndclassa

	wndclass.style = CS_HREDRAW| CS_VREDRAW;//调整窗口高度或宽度则重绘。
											//参考:https://docs.microsoft.com/zh-cn/windows/desktop/winmsg/window-class-styles
	wndclass.lpfnWndProc = WndProc;//指向窗口过程的指针。
	wndclass.cbClsExtra = 0;//在窗口类结构之后分配的额外字节数。 系统将字节初始化为零。
	wndclass.cbWndExtra = 0;//窗口实例后要分配的额外字节数。 系统将字节初始化为零。
							//如果应用程序使用WNDCLASS注册在资源文件中使用CLASS指令创建的对话框,则必须将此成员设置为DLGWINDOWEXTRA。
	wndclass.hInstance = hInstance;//包含该类的窗口过程的实例的句柄。
	wndclass.hIcon = //类图标的句柄。 该成员必须是图标资源的句柄。 
					 //如果此成员为NULL,则系统提供默认图标。
		LoadIcon(NULL, IDI_APPLICATION);//从与应用程序实例关联的可执行(.exe)文件加载指定的图标资源。
										//参考:https://docs.microsoft.com/en-us/windows/desktop/api/Winuser/nf-winuser-loadicona
	wndclass.hCursor = //类游标的句柄。 该成员必须是游标资源的句柄。
					   //如果此成员为NULL,则只要鼠标移动到应用程序窗口,应用程序就必须显式设置光标形状。
		LoadCursor(NULL, IDC_ARROW);//从与应用程序实例关联的可执行文件(.EXE)加载指定的游标资源。
									//参考:https://docs.microsoft.com/en-us/windows/desktop/api/Winuser/nf-winuser-loadcursora
	wndclass.hbrBackground = //类背景画笔的句柄。
							 //该成员可以是用于绘制背景的物理画笔的句柄,也可以是颜色值。 
		(HBRUSH)GetStockObject(WHITE_BRUSH);//getstockobject函数检索库存笔、画笔、字体或调色板之一的句柄。
											//参考:https://docs.microsoft.com/en-us/windows/desktop/api/wingdi/nf-wingdi-getstockobject
	wndclass.lpszMenuName = NULL;//类菜单的资源名称,名称显示在资源文件中。 
								 //如果使用整数来标识菜单,请使用MAKEINTRESOURCE宏。 
								 //如果此成员为NULL,则属于此类的窗口没有默认菜单。
	wndclass.lpszClassName = szAppName; //指向以null结尾的字符串或是atom的指针。

	if (!RegisterClass(&wndclass))//注册一个窗口类,以便在调用CreateWindow或CreateWindowEx函数时使用。
	{
		MessageBox(NULL, TEXT("This program needs to be executed on Windows NT."), szAppName, MB_OK| MB_ICONERROR);
		//显示模式对话框,其中包含系统图标,一组按钮和简要的特定于应用程序的消息,例如状态或错误信息。 
		//消息框返回一个整数值,指示用户单击的按钮。
		//参考:https://docs.microsoft.com/en-us/windows/desktop/api/Winuser/nf-winuser-messagebox
		return 0;
	}
	else
	{
		hwnd = CreateWindow//创建重叠、弹出或子窗口。它指定窗口类、窗口标题、窗口样式和(可选)窗口的初始位置和大小。
						   //该函数还指定窗口的父级或所有者(如果有)以及窗口的菜单。
						   //参考:https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-createwindowa
		(
			szAppName,//由以前调用RegisterClass或RegisterClassEx函数创建的以null结尾的字符串或类原子。 
									  //原子必须在lpClassName的低位字中; 高阶词必须为零。 
									  //如果lpClassName是字符串,则它指定窗口类名称。 
									  //类名可以是使用RegisterClass或RegisterClassEx注册的任何名称,前提是注册该类的模块也是创建窗口的模块。 
									  //类名也可以是任何预定义的系统类名。 有关系统类名称的列表,请参阅“备注”部分。
			TEXT("My Window"),	//窗口名称。 如果窗口样式指定标题栏,则lpWindowName指向的窗口标题将显示在标题栏中。 
								//使用CreateWindow创建控件(如按钮,复选框和静态控件)时,请使用lpWindowName指定控件的文本。 
								//使用SS_ICON样式创建静态控件时,请使用lpWindowName指定图标名称或标识符。 要指定标识符,请使用语法“#num”。
			WS_OVERLAPPEDWINDOW,//正在创建窗口的样式。此参数可以是窗口样式值的组合,以及“备注”部分中指示的控件样式。
								//参考:https://docs.microsoft.com/zh-cn/windows/desktop/winmsg/window-styles
			CW_USEDEFAULT,//窗口的初始水平位置。 
						  //对于重叠或弹出窗口,x参数是窗口左上角的初始x坐标,以屏幕坐标表示。 
						  //对于子窗口,x是窗口左上角相对于父窗口客户区左上角的x坐标。 
						  //如果此参数设置为CW_USEDEFAULT,则系统选择窗口左上角的默认位置并忽略y参数。 
						  //CW_USEDEFAULT仅对重叠窗口有效; 如果为弹出窗口或子窗口指定,则x和y参数设置为零。
			CW_USEDEFAULT,//窗口的初始垂直位置。 
						  //对于重叠或弹出窗口,y参数是窗口左上角的初始y坐标,以屏幕坐标表示。 
						  //对于子窗口,y是子窗口左上角相对于父窗口客户区左上角的初始y坐标。 
						  //对于列表框,y是列表框客户区左上角相对于父窗口客户区左上角的初始y坐标。
						  //如果使用WS_VISIBLE样式位设置创建重叠窗口并且x参数设置为CW_USEDEFAULT,则y参数确定窗口的显示方式。 
						  //如果y参数是CW_USEDEFAULT,则窗口管理器在创建窗口后使用SW_SHOW标志调用ShowWindow。 
						  //如果y参数是某个其他值,则窗口管理器使用该值调用ShowWindow作为nCmdShow参数。
			CW_USEDEFAULT,//窗口的宽度(以设备为单位)。 
						  //对于重叠窗口,nWidth是窗口宽度,屏幕坐标或CW_USEDEFAULT。 
						  //如果nWidth是CW_USEDEFAULT,则系统选择窗口的默认宽度和高度; 
						  //默认宽度从屏幕的初始x坐标延伸到右边缘,默认高度从初始y坐标延伸到图标区域的顶部。 
						  //CW_USEDEFAULT仅对重叠窗口有效; 如果为弹出窗口或子窗口指定了CW_USEDEFAULT,则nWidth和nHeight设置为零。
			CW_USEDEFAULT,//窗口的高度,以设备为单位。 
						  //对于重叠窗口,nHeight是窗口坐标中窗口的高度。 
						  //如果nWidth设置为CW_USEDEFAULT,则系统忽略nHeight。
			NULL,//正在创建的窗口的父窗口或所有者窗口的句柄。要创建子窗口或拥有的窗口,请提供有效的窗口句柄。此参数对于弹出窗口是可选的。
				 //要创建仅消息窗口,请向现有仅消息窗口提供hwnd_消息或句柄。
			NULL,//菜单的句柄,或根据窗口样式指定子窗口标识符。
				 //对于重叠窗口或弹出窗口,hmenu标识要与窗口一起使用的菜单;如果要使用类菜单,则可以为空。
				 //对于子窗口,hmenu指定子窗口标识符,该标识符是对话框控件用来通知其父窗口有关事件的整数值。
				 //应用程序确定子窗口标识符;对于具有相同父窗口的所有子窗口,该标识符必须是唯一的。
			hInstance,//与窗口关联的模块实例的句柄。
			NULL//指向要通过createStruct结构(lpcreateParams成员)传递到窗口的值的指针,该结构由wm_create消息的lparam参数指向。
				//此消息在返回之前由函数发送到创建的窗口。
				//如果应用程序调用CreateWindow来创建MDI客户机窗口,lpparam应指向ClientCreateStruct结构。
				//如果MDI客户机窗口调用CreateWindow来创建MDI子窗口,lpParam应该指向MDICreatestruct结构。如果不需要其他数据,lpparam可能为空。
		);

		ShowWindow(hwnd, iCmdshow);//设置指定窗口的显示状态。
								   //参考:https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-showwindow
		UpdateWindow(hwnd);//updateWindow函数通过向窗口发送wm_paint消息(如果窗口的更新区域不为空)来更新指定窗口的客户机区域。
						   //该函数将wm_paint消息直接发送到指定窗口的窗口过程,绕过应用程序队列。如果更新区域为空,则不发送消息。
						   //参考:https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-updatewindow

		while (GetMessage//从调用线程的消息队列中检索消息。该函数将发送传入的已发送消息,直到可以检索已发布的消息。
						 //与getmessage不同,peekmessage函数不等待消息在返回之前发布。
						 //参考:https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-getmessage
		(
			&msg, //指向从线程的消息队列接收消息信息的MSG结构的指针。
			NULL, //要检索其消息的窗口的句柄。
				  //窗口必须属于当前线程。
				  //如果hwnd为空,getmessage将检索属于当前线程的任何窗口的消息,以及当前线程的消息队列中hwnd值为空的任何消息(请参见msg结构)。
				  //因此,如果hwnd为空,则同时处理窗口消息和线程消息。
				  //如果hwnd为 - 1,则getmessage仅检索当前线程的消息队列中hwnd值为空的消息,
				  //也就是说,由postmessage(当hwnd参数为空时)或postmthreadmessage发布的线程消息。
			0, //要检索的最低消息值的整数值。
			   //使用wm_keyfirst(0x0100)指定第一个键盘消息,或使用wm_mouse first(0x0200)指定第一个鼠标消息。
			   //在这里和wmsgfiltermax中使用wm_input仅指定wm_输入消息。
			   //如果wmsgfiltermin和wmsgfiltermax都为零,则getmessage返回所有可用消息(即,不执行范围筛选)。
			0//要检索的最高消息值的整数值。
			 //使用wm_keylast指定最后一条键盘消息,或使用wm_mouselast指定最后一条鼠标消息。
			 //在这里和wmsgfiltermin中使用wm_input仅指定wm_输入消息。
			 //如果wmsgfiltermin和wmsgfiltermax都为零,则getmessage返回所有可用消息(即,不执行范围筛选)。
		))
		{
			TranslateMessage(&msg);//将虚拟密钥消息转换为字符消息。
								   //字符消息被发送到调用线程的消息队列,以便下次线程调用getmessage或peekmessage函数时读取。
								   //参考:https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-translatemessage
			DispatchMessage(&msg);//将虚拟密钥消息转换为字符消息。
								  //字符消息被发送到调用线程的消息队列,以便下次线程调用getmessage或peekmessage函数时读取。
								  //参考:https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-dispatchmessage
		}

		return msg.wParam;//有关该消息的其他信息。 确切含义取决于消息成员的值。
						  //参考:https://docs.microsoft.com/en-us/windows/desktop/api/winuser/ns-winuser-tagmsg
	}
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	HDC hdc;
	PAINTSTRUCT ps;
	RECT rect;

	switch (message)
	{
	case WM_PAINT:
		hdc = BeginPaint(hwnd, &ps);//beginpaint函数准备用于绘制的指定窗口,并用有关绘制的信息填充paintstruct结构。
									//参考:https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-beginpaint
		GetClientRect(hwnd, &rect);//检索富编辑控件的客户端矩形。
								   //参考:https://docs.microsoft.com/en-us/windows/desktop/api/tom/nf-tom-itextdocument2-getclientrect

		DrawText//drawtext函数在指定的矩形中绘制格式化文本。
				//它根据指定的方法格式化文本(展开选项卡、调整字符、换行等)。
				//参考:https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-drawtext
		(
			hdc, //设备上下文的句柄
			TEXT("Hello, this is my first window project."), //指向要指定要绘制的文本的字符串的指针。
															 //如果nCount参数为 - 1,则字符串必须以空值终止。
															 //如果uFormat包含DT_MODIFYSTRING,则该函数最多可以为该字符串添加四个附加字符。
															 //包含字符串的缓冲区应足够大以容纳这些额外字符。
			-1, //字符串的长度(以字符为单位)。 
				//如果nCount为-1,则假定lpchText参数是指向以null结尾的字符串的指针,DrawText会自动计算字符计数。
			&rect, //指向rect结构的指针,该结构包含要格式化文本的矩形(以逻辑坐标表示)。
			DT_SINGLELINE| DT_CENTER| DT_VCENTER //格式化文本的方法。单行、水平中心、竖直中心。
		);

		EndPaint(hwnd, &ps);//EndPaint函数标记指定窗口中绘制的结束。 
							//每次调用BeginPaint函数都需要此函数,但仅在绘制完成后才需要此函数。
							//参考:https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-endpaint
		return 0;

	case WM_DESTROY:
		PostQuitMessage(0);//向系统指示线程已请求终止(退出)。它通常用于响应wm_销毁消息。
		return 0;
	}

	return DefWindowProc(hwnd, message, wParam, lParam);
	//调用默认窗口过程为应用程序不处理的任何窗口消息提供默认处理。 
	//此功能可确保处理每条消息。 
	//使用窗口过程接收的相同参数调用DefWindowProc。
	//参考:https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-defwindowproca
}
posted @ 2019-04-29 21:42  永恒月华  阅读(298)  评论(0编辑  收藏  举报