#include<windows.h>
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
/*
Windows 的窗口总是基于窗口类来创建的,窗口类同时确定了处理窗口消息的窗口过程(回调函数)。
回调函数需要到函数最后面几行找
*/
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hprevInstance,PSTR szCmdLine,int iCmdShow)
/*
hInstance:应用程序当前事例的句柄。
hPrelnstance:应用程序的先事例的句柄。对于同一个程序打开两次,出现两个窗口第一次打开的窗口就是先前实例的窗口。对于一个32的位程序,该参数总为NULL。
lpCmdLine:指向应用程序命令行的空字符串的指针,不包括函数名。获得整个命令行,参看GetCommandLine。
iCmdShow:指明窗口如何显示(是隐藏还是显示,有没有最大化按钮之类的)。取值可以参考MSDN
这里我相信有一个词大家好应该比较陌生,句柄(HANDLE)是吧。下面我就来简单的说下
句柄其实就是Windows系统中一个东西的唯一标识。就是系统中有很多运行的程序或者资源之类的,为了更好的管理使用,
Windows系统给它们每人一个ID一样。懂得网页制作的人应该知道网页中各个元素的ID吧,网页的ID如果重复话可能出现错误。
那么系统的句柄会不会有相同的,那是肯定不会有的了,就和我们的学号一样,系统自动分配每一个模块的句柄,是不会相同的了。
*/
{
static TCHAR szAppName[] = TEXT("开始坑爹之旅");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
/*在创建应用程序窗口之前,必须调用 RegisterClass 函数来注册窗口类。
该函数只需要一个参数,即指向 WNDCLASS 窗口类的指针。因为 WNDCLASS 类包含了窗口所拥有的基本属性。
结构原型:
typedef struct tagWNDCLASSW {
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCWSTR lpszMenuName;
LPCWSTR lpszClassName;
} WNDCLASSW, *PWNDCLASSW, NEAR *NPWNDCLASSW, FAR *LPWNDCLASSW;
成员 含义
style 指定窗口类型,各种“类风格”(详见下方↓)可以使用按位或操作符组合起来
lpfnWndProc 指定窗口过程(必须是回调函数)
cbClsExtra 预留的额外空间,一般为 0
cbWndExtra 预留的额外空间,一般为 0
hInstance 应用程序的实例句柄
hIcon 为所有基于该窗口类的窗口设定一个图标
hCursor 为所有基于该窗口类的窗口设定一个鼠标指针
hbrBackground 指定窗口背景色
lpszMenuName 指定窗口菜单
lpszClassName 指定窗口类名 */
wndclass.style = CS_HREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL,IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL,IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(COLOR_CAPTIONTEXT); //背景色
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if(!RegisterClass(&wndclass))
{
MessageBox(NULL,TEXT("这个程序无法执行"),szAppName,MB_OK);
return 0;
}
hwnd =CreateWindow(szAppName,
TEXT("开始坑爹了"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(hwnd,iCmdShow); //显示窗口
UpdateWindow(hwnd); //更新窗口
while(GetMessage(&msg,NULL,0,0))
/*
注释:_In_ 说明该参数是输入的,_opt_ 说明该参数是可选参数。
BOOL WINAPI GetMessage(
_Out_ LPMSG lpMsg,
_In_opt_ HWND hWnd,
_In_ UINT wMsgFilterMin,
_In_ UINT wMsgFilterMax
);
lpMsg 指向 MSG 结构的指针
hWnd 1. 需要检索消息的窗口的句柄,该窗口必须属于当前线程
2. 当其值是 NULL 时,将检索所有的当前线程的窗口消息和线程消息
3. 当其值是 -1 时,只检索当前线程消息
wMsgFilterMin 指定被检索的最小消息值的整数
wMsgFilterMax 指定被检索的最大消息值的整数
返回值:
1. 如果函数取得 WM_QUIT 之外的其他消息,返回非零值;
2. 如果函数取得 WM_QUIT 消息,返回值是零;
3. 如果出现了错误,返回值是 -1。
*/
{
TranslateMessage(&msg);
/*
TranslateMessage 函数将虚拟键消息转换为字符消息,字符消息被寄送到当前线程的消息队列里。
当下一次线程调用函数 GetMessage 或 PeekMessage 时被读出。
BOOL WINAPI TranslateMessage( _In_ const MSG *lpMsg);
lpMsg 指向含有消息的 MSG 结构的指针
返回值:
1. 如果消息被转换(字符消息被寄送到当前线程的消息队列里)则返回非零值;
2. 如果消息是 WM_KEYDOWN,WM_KEYUP WM_SYSKEYDOWN 或 WM_SYSKEYUP,返回非零值,不考虑转换;
3. 如果消息没被转换(字符消息没被寄送到调用线程的消息队列里)则返回值是零。
*/
DispatchMessage(&msg);
/*
DispatchMessage 函数分派一个消息给窗口过程(回调函数),通常该消息从 GetMessage 函数获得。Windows 的控制权在该函数交给了应用程序。
LRESULT WINAPI DispatchMessage( _In_ const MSG *lpmsg);
lpmsg 指向含有消息的 MSG结构 的指针
返回值:
1. 返回值是窗口过程返回的值;
2. 尽管返回值的含义依赖于被分派的消息,但返回值通常被忽略。
备注:
1. MSG 结构必须包含有效的消息值。
2. 如果参数 lpmsg 指向一个 WM_TIMER 消息,并且 WM_TIMER 消息的参数 lParam 不为 NULL,则调用 lParam 指向的函数,而不是调用窗口程序。
*/
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
/*
PAINTSTRUCT 结构包含一些窗口过程用来对客户区进行绘制的信息。
typedef struct tagPAINTSTRUCT {
HDC hdc;
BOOL fErase;
RECT rcPaint;
BOOL fRestore;
BOOL fIncUpdate;
BYTE rgbReserved[32];
} PAINTSTRUCT, *PPAINTSTRUCT;
成员 含义
hdc 用于绘制的设备环境句柄
fErase 1. 表示背景是否必须擦除,如果为非零值则擦除背景,否则不擦除背景
2. 如果创建窗口类的时候没有设置背景画刷,则负责擦除背景
rcPaint 一个 RECT 结构,指定左上角和右下角的坐标确定一个要绘制的矩形范围
fRestore 系统保留
fIncUpdate 系统保留
rgbReserved 系统保留
*/
HDC hdc;
PAINTSTRUCT ps; //声明一个PAINTSTRUCT 结构变量ps
RECT rect;
/*
RECT 结构定义了一个矩形的左上角和右下角的坐标。
typedef struct _RECT {
LONG left; 指定矩形左上角的 x 坐标
LONG top; 指定矩形左上角的 y 坐标
LONG right; 指定矩形右下角的 x 坐标
LONG bottom; 指定矩形右下角的 y 坐标
} RECT, *PRECT;
*/
switch (message)
{
case WM_PAINT: //WM_PAINT 0x000F 要求一个窗口重绘自己
hdc = BeginPaint(hwnd, &ps);
/*
BeginPaint 函数为指定窗口进行绘画工作的准备,并用将和绘画有关的信息填充到一个 PAINTSTRUCT 结构中。
HDC BeginPaint(
_In_ HWND hwnd,
_Out_ LPPAINTSTRUCT lpPaint
);
hwnd 需要重新绘制的窗口句柄
lpPaint 指向 PAINTSTRUCT 结构的指针,用于存放绘画相关的信息
返回值:
1. 如果函数成功,返回值是指定窗口的“显示设备描述表”句柄;
2. 如果函数失败,返回值是 NULL,表明没有得到显示设备的内容。
备注:
1. BeginPaint 函数自动设置显示设备内容的剪切区域,而排除任何更新区域外的区域。
该更新区域可以通过 InvalidateRect 或 InvalidateRgn 函数设置,也可以是系统在改变大小、移动、创建、滚动后设置的,或者其他的影响客户区的操作来设置的。
2. 如果更新区域被标记为可擦除的,BeginPaint 发送一个 WM_ERASEBKGND 消息给窗口。
3. 一个应用程序除了响应 WM_PAINT 消息外,不应该调用 BeginPaint。
4. 每次调用 BeginPaint 都应该有相应的 EndPaint 函数。
5. 如果被绘画的客户区中有一个 caret(caret:插入符。是窗口客户区中的一个闪烁的线,块,或位图。插入符通常表示文本或图形将被插入的地方。
即一闪一闪的光标),BeginPaint 自动隐藏该符号,而保证它不被擦除。
6. 如果窗口类有一个背景刷,BeginPaint 使用这个刷子来擦除更新区域的背景
*/
GetClientRect(hwnd, &rect);
/*GetClientRect 函数用于获取窗口客户区的坐标,客户区坐标指定客户区的左上角和右下角。
由于客户区坐标是相对窗口客户区的左上角而言的,因此左上角坐标为(0,0)
BOOL WINAPI GetClientRect(
_In_ HWND hWnd,
_Out_ LPRECT lpRect
);
hWnd 需要获取客户区坐标的窗口句柄
lpRect 1. 指向 RECT 结构的指针,该结构有四个成员,分别为 left、top、right 和 bottom
2. GetClientRect 将这四个成员设定为窗口显示区域的尺寸。
left 和 top 字段通常设定为 0,right 和 bottom 字段设定为显示区域的宽度和高度(像素点数)
*/
DrawText(hdc, TEXT("大家好,这是我的第一个窗口程序!"), -1, &rect,
DT_SINGLELINE | DT_CENTER | DT_VCENTER);
/*
DrawText 函数在指定的矩形里写入格式化的正文,根据指定的方法对正文格式化(扩展的制表符,字符对齐、折行等)。
int DrawText(
_In_ HDC hDC,
_Inout_ LPCTSTR lpchText,
_In_ int nCount,
_Inout_ LPRECT lpRect,
_In_ UINT uFormat
);
hDC 指定“显示设备描述表”句柄
lpchText 1. 指向将被写入的字符串的指针,如果参数 nCount 是 -1,则字符串必须是以 \0 结束的
2. 如果 uFormat 包含 DT_MODIFYSTRING,则函数可为此字符串增加 4 个字符,存放字符串的缓冲区必须足够大,能容纳附加的字符
nCount 1. 指向字符串中的字符数
2. 如果 nCount 为 -1,则 lpchText 指向的字符串被认为是以 \0 结束的,DrawText 会自动计算字符数
lpRect 指向 RECT 结构的指针,其中包含文本将被置于其中的矩形的信息(按逻辑坐标)
uFormat 1. 指定格式化文本的方法
2. 此参数可以通过指定下列标志或标志的组合
返回值:
1. 如果函数调用成功,返回值是正文的高度(逻辑单位);
2. 如果指定了 DT_VCENTER 或 DT_BOTTOM,返回值是 lpRect -> top 到绘制的正文的底部的偏移值;
3. 如果 函数调用失败,返回值是 0。
备注:
1. 函数 DrawText 用设备环境中的字体选择、正文颜色和背景颜色来写正文。
2. DrawText 裁剪正文,使之不会出现在指定矩形的外面,除非指定了 DT_NOCLIP。
3. 除非使用 DT_SINGLELINE 格式化,否则其余的格式都认为正文有多行。
4. 如果选择的字体对指定的矩形而言太大,DrawText 并不会试图去换成一种小字体。
5. 设备环境的正文对齐方式必须包括 TA_LEFT, TA_TOP 和 TA_NOUPDATECP 标志。
*/
EndPaint(hwnd, &ps);
/*EndPaint 函数标记指定窗口的绘画过程结束。
BOOL EndPaint(
_In_ HWND hWnd,
_In_ const PAINTSTRUCT *lpPaint
);
hWnd 已经被重新绘制的窗口句柄
lpPaint 指向 PAINTSTRUCT 结构的指针,用于存放绘画相关的信息(该指针在调用 BeginPaint 时被赋值)
*/
return 0;
case WM_DESTROY: //WM_DESTROY 0x0002 一个窗口被销毁
PostQuitMessage(0);
/*PostQuitMessage 函数向系统表明有个线程有终止(退出)请求。
这个函数通常用来响应 WM_DESTROY 消息。
VOID WINAPI PostQuitMessage(
_In_ int nExitCode
);
nExitCode 指定应用程序的退出代码,此值被用作 WM_QUIT 消息的 wParam 参数
返回值:该函数没有返回值。
备注:
1. PostQuitMessage 函数的功能是发送一个 WM_QUIT 消息给线程的消息队列并立即返回。
2. 当线程从消息队列里取得 WM_QUIT 消息时,应当退出消息循环并将返回系统,
返回给系统的退出值必须是消息 WM_QUIT 的 wParam 参数(所以 WinMain 函数的返回值是 msg.wParam)。
*/
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
/*DefWindowProc 函数调用缺省的窗口过程来处理那些窗口过程没有处理的任何消息,该函数是为了确保每个消息都被处理。
DefWindowProc 函数传入和窗口过程同样的参数。
LRESULT WINAPI DefWindowProc(
_In_ HWND hWnd,
_In_ UINT Msg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
hWnd 指定接收消息的窗口句柄
Msg 1. 消息的标识符,由于数值不便于记忆,所以 Windows 将消息对应的数值定义为 WM_XXX 宏的形式
2. 应用程序消息只能使用低 16 位,高 16 位被系统保留
3. 传送门:Windows 常用消息及含义
wParam 指定消息的附加消息,确切的含义取决于消息成员的值
lParam 指定消息的附加消息,确切的含义取决于消息成员的值
返回值就是消息处理结果,它取决于发送的消息
*/
}