#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
}