1、打开Visual Studio 2017,其他Visual Studio版本也可以
2、新建一个Windows桌面向导项目,或者Win32应用程序项目都可以
3、新建项目时,选择Windows应用程序,并勾上空项目
4、新加源文件,注意因为WindowsAPI都是C语言实现,所以,新加文件的后缀要是*.c文件
5、实现功能,源码如下:
必要解释:
- WM_PAINT 消息:当窗口客户区的一部分或者全部变为“ 无效” 时, 系统会发送 WM_PAINT 消息,通知应用程序重新绘制窗口。当窗口刚创建的时候, 整个客户区都是无效的。因为这个时候程序还没有在窗口上绘制任何东西,当调用 UpdateWindow 函数时,会发送 WM_PAINT 消息给窗口过程,对窗口进行刷新。当窗口从无到有、改变尺寸、最小化后再恢复、被其他窗口遮盖后再显示时, 窗口的客户区都将变为无效, 时系统会给应用程序发送 WM_PAINT 消息,通知应用程序重新绘制。
- WM_CLOSE 消息:对 WM_CLOSE 消息的响应并不是必须的,如果应用程序没有对该消息进行响应, 系统将把这条消息传给 DefWindowProc 函数而 DefWindowProc 函数则调用 DestroyWindow 函数来响应这条 WM_CLOSE 消息。
- WM_DESTROY消息:DestroyWindow 函数在销毁窗口后,会给窗口过程发送 WM_DESTROY消息,我们在该消息的响应代码中调用 PostQuitMessage 函数。PostQuitMessage函数向应用程序的消息队列中投递一条 WM_QUIT 消息并返回。我们在前边介绍过,GetMessage 函数只有在收到 WM_QUIT 消息时才返回 0,此时消息循环才结束,程序退出。要想让程序正常退出, 我们必须响应 WM_DESTROY 消息,并在消息响应代码中调用PostQuitMessage,向应用程序的消息队列中投递 WM_QUIT 消息。传递给 PostQuitMessage函数的参数值将作为 WM_QUIT 消息的 wParam 参数,这个值通常用做 WinMain 函数的返回值。
- BeginPaint、EndPaint 函数:BeginPaint 函数的第 1 个参数是窗口的句柄,第二个参数是 PAINTSTRUCT 结构体的指针,该结构体对象用于接收绘制的信息。在 调 用 BeginPaint 时,如果客户区的背景还没有被擦除, 那么 BeginPaint 会 发 送WM_ERASEBKGND 消息给窗口, 系统就会使用 WNDCLASS 结构体的 hbrBackground 成员指定的画刷来擦除背景。在响应 WM_PAINT 消息的代码中, 要得到窗口的 DC, 必须调用 BeginPaint 函数。BeginPaint 函数也只能在 WM_PAINT 消息的响应代码中使用, 在其他地方, 只能使用GetDC 来得到 DC 的句柄。 另外, BeginPaint 函数得到的 DC, 必须用 EndPaint 函数去释放。
- TextOut函数: 调用 TextOut 函数在(300, 300) 的位置输出一个字符串“Hello,MFC!”。当发生重绘时,窗口中的文字和图形都会被擦除。在擦除背景后,TextOut 函数又一次执行,在窗口中再次绘制出 “Hello,MFC!”。 这个过程对用户来说是透明的,用户并不知道程序执行的过程,给用户的感觉就是你在响应 WM_PAINT 消息的代码中输出的文字或图形始终保持在窗口中。换句话说,如果我们想要让某个图形始终在窗口中显示, 就应该将图形的绘制操作放到响应 WM_PAINT 消息的代码中。
- DefWindowProc函数:调用默认的窗口过程,对应用程序没有处理的其他消息提供默认处理。对于大多数的消息,应用程序都可以直接调用 DefWindowProc函数进行处理。在编写窗口过程时,应该将 DefWindowProc 函数的调用放到 default 语句中,并将该函数的返回值作为窗口过程函数的返回值。
- SendMessage发送“不进队消息”,直接把消息发送给窗口,并调用该窗口的窗口过程函数进行处理。在窗口过程对消息处理完毕后,返回处理结果。
- PostMessage发送“进队消息”。将消息放入与创建窗口的线程相关联的消息队列后立即返回。
/* 注意此时必须包含windows.h文件 */
#include <windows.h>
//窗口过程函数
LRESULT CALLBACK DealMessage(HWND hWnd, //窗口句柄,消息所属的窗口
UINT uMsg, //消息标志
WPARAM wParam, //附加信息
LPARAM lParam
)
{
switch (uMsg)
{
case WM_LBUTTONDOWN: //鼠标左键按下
MessageBox(hWnd, TEXT("ABC"), TEXT("鼠标左键按下"), MB_OK);
break;
case WM_PAINT:
{
PAINTSTRUCT ps; //绘图结构体
HDC dc = BeginPaint(hWnd, &ps); //开始绘图
TCHAR * p = L"aaaaaaa"; //转为宽字节
TextOutW(dc, 30, 30, p, wcslen(p));//输出
EndPaint(hWnd, &ps);//结束绘图
break;
}
case WM_DESTROY:
PostQuitMessage(2); //WM_QUIT, 给主函数 return msg.wParam
break;
default:
/* 该函数对未被处理的消息提供默认响应 */
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
//WINAPI: 修饰函数,规定函数参数入栈从右往左,函数调用完毕,自动清理堆栈
//CALLBACK
int WINAPI WinMain(HINSTANCE hInstance, //应用程序实例
HINSTANCE hPrevInstance, //上一个应用程序实例,不用
LPSTR lpCmdLine, //命令行参数
int nCmdShow //窗口显示的样式, 最大化,最小化
)
{
/*
1、定义入口函数WinMain()
2、创建一个窗口
a)设计窗口类WNDCLASS(给成员变量赋值)
b)注册窗口类
c)创建窗口类
d)显示和更新窗口
3、消息循环
4、窗口过程函数
*/
//a)设计窗口类WNDCLASS(给成员变量赋值)
WNDCLASS wc;
wc.cbClsExtra = 0; //类的附加信息
wc.cbWndExtra = 0; //窗口附加信息
//获取系统默认的白色画刷
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); //背景色,必须写
wc.hCursor = LoadCursor(NULL, IDC_HELP); //加载系统默认光标
wc.hIcon = LoadIcon(NULL, IDI_WARNING); //加载系统默认图标
wc.hInstance = hInstance; //应用程序实例
wc.lpfnWndProc = DealMessage; //窗口过程函数名字,消息处理函数
wc.lpszClassName = TEXT("abc"); //类的名字
wc.lpszMenuName = NULL; //菜单名字
wc.style = nCmdShow; //显示风格
//b)注册窗口类, 告诉系统窗口过程函数的入口地址
RegisterClass(&wc);
//c)创建窗口类
HWND hWnd = CreateWindow(TEXT("abc"), TEXT("hello, windwos"), WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL);
//d)显示和更新窗口
ShowWindow(hWnd, SW_SHOWNORMAL);
UpdateWindow(hWnd);
//消息循环
MSG msg;
//如果接受到WM_QUIT, 返回0, 退出
//如果出错,返回-1,不退出
while (GetMessage(&msg, NULL, 0, 0))
{
//翻译工作
//虚拟按键转为标准字符WM_CHAR
TranslateMessage(&msg);
//给操作系统分发消息
DispatchMessage(&msg);
}
return msg.wParam;
}
6、按下左键,效果如下: