窗口的创建
1. 六个要素
- 设计注册窗口类
- 创建窗口实例
- 显示窗口
- 更新窗口
- 消息循环
- 实现窗口过程函数(回调函数)
2. 设计注册窗口类
2.1 RegisterClass注册窗口类API
定义:
参数:限定内容的WNDCLASS类型的指针
2.2 窗口类WNDCLASS
定义:
2.2.1 数据类型具体含义解释
1. UNIT style
定义:Specifies the class style(s). This member can be any combination of the class styles.
释义:指定类的样式。这个成员可以是类样式的任何组合。
样式库:
常用默认:
CS_HREDRAW & CS_VREDRAW
释义:如果移动或大小调整改变了客户区域的宽度或者高度,则重绘整个窗口。
宏定义:位运算
语法:
WNDCLASS window1; window1.style = CS_VREDRAW | CS_HREDRAW; //两种属性的组合用按位或运算 //检查是否含有CS_VREDRAW属性,用按位与运算 if (window1.style & CS_VREDRAW) { MessageBox(NULL, TEXT("这是CS_VREDRAW风格"), TEXT("提示"), MB_OK); } window1.style &= ~CS_VREDRAW;//取消CS_VREDRAW风格
2. WNDPROC lpfnWndProc —— 窗口回调函数(函数指针)
回调函数:
LRESULT CALLBACK MyWindow1Proc( HWND hwnd, // handle to window UINT uMsg, // message identifier WPARAM wParam, // first message parameter LPARAM lParam // second message parameter ) { return 1; }
赋予属性:
window1.lpfnWndProc = MyWindow1Proc;
3. HISTANCE hInstance —— 实例化句柄
window1.hInstance = hInstance;//实例化句柄
填0
window1.cbClsExtra = 0; window1.cbWndExtra = 0;
4. HICON hIcon —— 图标
window1.hIcon = NULL;
5. HCURSOR hCursor —— 光标句柄
window1.hCursor = NULL;
6. HBRUSH hbrBackground —— 背景色
window1.hbrBackground = COLOR_SCROLLBAR;//窗口背景色
7. LPCTSTR lpszMenuName —— 窗口菜单
window1.lpszMenuName = NULL;
8. LPCTSTR lpszClassName —— 窗口类名
此处定义的窗口类名,可以在以后的代码中,直接使用窗口类名来表示当前此窗口对象
window1.lpszClassName = TEXT("MyWin1");
9. 返回值
If the function succeeds, the return value is a class atom that uniquely identifies the class being registered. If the function fails, the return value is zero. To get extended error information, call GetLastError.
释义:如果函数成功,则返回值是唯一标识所注册类的类单元。如果函数失败,返回值为0。要获取扩展的错误信息,请调用GetLastError。
检查是否注册成功,注意相同窗口类名注册会失败,可以更改窗口类名后继续注册
if (!RegisterClass(&window1)) { MessageBox(NULL, TEXT("注册失败"), TEXT("提示"), MB_OK); return 0; }
10. 获取失败结果 —— GetLastError()
通过GetLastError()获取的错误信息可以再vs中工具——错误查找中查询:
其它办法:
1. @err,hr
2. *(unsigned int*)(tib+0x34),hr
3. hr释义:解释错误
11. 打印错误信息 —— FormatMessage()
主体示例:将以下代码拉入一个显示错误信息的函数中
//显示错误信息 void ShowErr() { LPVOID lpMsgBuf; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR)&lpMsgBuf, 0, NULL ); // Process any inserts in lpMsgBuf. // ... // Display the string. MessageBox(NULL, (LPCTSTR)lpMsgBuf, TEXT("Error"), MB_OK | MB_ICONINFORMATION); // Free the buffer. LocalFree(lpMsgBuf); }
判断错误信息:
if (!RegisterClass(&window1)) { ShowErr(); //MessageBox(NULL, TEXT("注册失败"), TEXT("提示"), MB_OK); return 0; }
3. 创建窗口实例 —— CreateWindow
3.1 窗口的类型 —— DWORD dwStyle, // window style
三种基本类型,有且仅有其中一种
WS_CHILD
WS_OVERLAPPED
WS_POPUP
常用的为WS_OVERLAPPEDWINDOW,它包含了WS_OVERLAPPED
3.2 创建一个窗口实例
HWND hRet = CreateWindow( TEXT("MyWin1"),//窗口类的类名 TEXT("test"),//窗口的标题 WS_OVERLAPPEDWINDOW, 400,//x 200,//y 800,//宽 400,//高 NULL,//没有父窗口 NULL,//没有子窗口 hInstance,//实例化句柄 NULL,//没有参数 );
3.3 返回值
HWND hRet = CreateWindow();
如果未成功,返回值为空,其返回值类型为句柄
4. 显示窗口 —— ShowWindow()
ShowWindow(hRet, SW_SHOW);
注意:参数为创建窗口实例返回的句柄
5. 更新窗口 —— UpdateWindow()
UpdateWindow(hRet);
注意:参数为创建窗口实例返回的句柄
6. 消息循环
6.1 消息结构体
6.2 消息循环
6.3 GetMessage()
释义:GetMessage函数从调用线程的消息队列中检索消息。该函数将发送传入的消息,直到已发送的消息可供检索为止。
第二个参数:HWND hWnd, // handle to window
如果填窗口句柄,只拿指定窗口的消息,如果填NULL,拿所有窗口消息
第二个参数和第三个参数:
UINT wMsgFilterMin, // first message UINT wMsgFilterMax // last message
如果填3 ,填8,则会只拿3-8之间的消息,如果都填0,就会拿取所有消息
返回值:
If the function retrieves a message other than WM_QUIT, the return value is nonzero.
If the function retrieves the WM_QUIT message, the return value is zero.
If there is an error, the return value is -1.
释义:
如果函数检索到的消息不是WM_QUIT,则返回值是非零。
如果函数检索到WM_QUIT消息,则返回值为0。
如果有错误,返回值是-1。
注意:
WM_QUIT退出消息系统不会发送,只能自己发送,此时需要使用PostQuitMessage() API来发送quit消息,才能使消息循环打破
处理消息
MSG message1; while (GetMessage(&message1, NULL, 0, 0)) { MyWindow1Proc(message1.hwnd, message1.message, message1.wParam, message1.lParam); }
默认处理消息api —— DefWindowProc()
DefWindowProc函数调用默认窗口过程来为应用程序没有处理的任何窗口消息提供默认处理。此函数确保处理每个消息。DefWindowProc使用窗口过程接收到的相同参数被调用。
LRESULT CALLBACK MyWindow1Proc( HWND hwnd, // handle to window UINT uMsg, // message identifier WPARAM wParam, // first message parameter LPARAM lParam // second message parameter ) { return DefWindowProc(hwnd, uMsg, wParam, lParam); }
6.4 窗口关闭
1. WM_CLOSE消息
此是窗口关闭的消息结构体
返回值:
如果处理该关闭消息,返回0
2. DestroyWindow() —— 关闭窗口api
返回值:
如果函数成功,返回值为非零。
如果函数失败,返回值为0。
3. 关闭窗口
LRESULT CALLBACK MyWindow1Proc( HWND hwnd, // handle to window UINT uMsg, // message identifier WPARAM wParam, // first message parameter LPARAM lParam // second message parameter ) { switch (uMsg) { case WM_CLOSE: DestroyWindow(hwnd);//销毁窗口 PostQuitMessage(0);//退出消息循环 return 0; default: break; } return DefWindowProc(hwnd, uMsg, wParam, lParam); }
6.5 DispatchMessage() —— 调用消息的相应句柄的窗口回调函数
MSG message1; while (GetMessage(&message1, NULL, 0, 0)) { DispatchMessage(&message1);//根据窗口句柄调用对应的窗口进程函数,处理消息 //MyWindow1Proc(message1.hwnd, //message1.message, //message1.wParam, //message1.lParam); }
根据窗口句柄调用对应的窗口进程函数,处理消息
7. 实现窗口回调函数 —— 即实现的MyWindow1Proc()函数
8. 对应鼠标消息
WM_LBUTTONDOWN —— 鼠标按下消息
WM_LBUTTONUP —— 鼠标回弹消息
WM_LBUTTONUP —— 鼠标移动消息
9. 小知识
1. wsprintf()
定义:
根据格式字符串中相应的格式规范,将任何参数转换并复制到输出弹框中。函数将结束null字符添加到它写入的字符中,但是返回值不包含结束null字符。
返回值:
如果函数成功,返回值是存储在输出缓冲区中的字符数,不包括结束的null字符。
如果函数失败,返回值小于预期输出的长度。
调用约定:__cdecl,因为多参