第一个Windows窗口程序
1. 入口函数
Windows编程的入口函数:
建议直接F1查询官方文档,Ctrl C+V
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nShowCmd
)
{
return 0;
}
2. 创建窗口类
我们准备创建一个窗口类,使用WNDCLASSW创建一个支持宽字符的窗口类:
这个类比较复杂,但是我们实际用到的属性不多:
WNDCLASSW函数原型官方文档
WNDCLASSW myClassWindow{ 0 };
myClassWindow.lpszClassName = L"我的第一个窗口"; //显式指定窗口类名
myClassWindow.lpfnWndProc = nullptr; //指定回调函数,我们之后会用到,暂时给他赋一个空值
我们创建一个最简单的窗口类,可以只声明这个两个参数的值,但是在我们以后的学习中,你就会慢慢丰富这个类,比如,我们可以指定窗口的图标,鼠标样式等等。。。我们以后再说。
3. 注册窗口
根据我们创建的窗口类,注册一个窗口实例:
RegisterClassW(&myClassWindow);
注册成功后,我们便可以使用这个窗口类创建一个实例对象了。
4. 创建窗口实例
CreatClass创建一个窗口类:
HWND window=CreateWindowW(
myClassWindow.lpszClassName,//窗口的类名
L"无标题", //窗口的标题
WS_OVERLAPPEDWINDOW, //窗口样式
CW_USEDEFAULT, //窗口的x坐标(左上角)
0, //窗口的y坐标
CW_USEDEFAULT, //窗口的width宽度
0, //窗口的height高度
NULL, //窗口的父窗口句柄(一般为空)
NULL, //菜单
hInstance, //与此窗口相关联的窗口句柄
NULL //一般为空
);
//显示窗口
ShowWindow(window, SW_SHOWNORMAL);
我们返回一个HWND的句柄,这样我们就得到我们的主窗口的句柄了。
然后再显示此窗口。
5. 处理消息事件
Windows系统是基于消息的操作系统。
每一个窗口都在不停的处理消息,所有的操作都是接收到消息之后,进行处理的结果。
围绕着消息的处理,产生了获取消息的消息泵机制也叫消息循环,以及处理消息的窗口回调函数机制。
消息的产生
Windows下产生消息的时机共有以下四种:
1、用户主动产生的消息
2、Windows系统本身产生的消息。
3、应用程序本身产生的消息。
4、其他应用程序产生的消息。
那么应用程序是如何接受消息的呢?
Windows操作系统有一个系统消息队列,每个GUI程序,都有自己的消息队列,系统消息队列负责将消息发送给不同GUI程序的消息队列。
API函数:
GetMessage 从消息队列中取出消息
TranslateMessage 翻译消息为字符消息
DispatchMessage 将消息发送给消息处理函数。
MSG msg{ 0 };
while (GetMessageW(&msg, 0, 0, 0))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
6. 回调函数
Wndproc: 在应用程序中定义的回调函数,用于处理发送到窗口的消息。
windows就是一个不断处理消息的系统,我们要对其处理消息,并且返回给主函数。
LRESULT CALLBACK Wndproc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
switch (uMsg)
{
case WM_CREATE:
{
MessageBoxW(hwnd, L"窗口创建成功!", L"提示", MB_OK);
break;
}
case WM_CLOSE:
{
DestroyWindow(hwnd);
PostQuitMessage(NULL);
break;
}
}
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
}
记得在我们最开始创建的窗口类中指明我们的回调函数:
myClassWindow.lpfnWndProc = Wndproc;
完整测试
#include <Windows.h>
LRESULT CALLBACK Wndproc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
switch (uMsg)
{
case WM_CREATE:
{
MessageBoxW(hwnd, L"窗口创建成功!", L"提示", MB_OK);
break;
}
case WM_CLOSE:
{
DestroyWindow(hwnd);
PostQuitMessage(NULL);
break;
}
}
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
}
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nShowCmd
)
{
WNDCLASSW myClassWindow{ 0 };
myClassWindow.lpszClassName = L"我的第一个窗口";
myClassWindow.lpfnWndProc = Wndproc;
RegisterClassW(&myClassWindow);
HWND window=CreateWindowW(
myClassWindow.lpszClassName,//窗口的类名
L"无标题", //窗口的标题
WS_OVERLAPPEDWINDOW, //窗口样式
CW_USEDEFAULT, //窗口的x坐标(左上角)
0, //窗口的y坐标
CW_USEDEFAULT, //窗口的width宽度
0, //窗口的height高度
NULL, //窗口的父窗口句柄(一般为空)
NULL, //菜单
hInstance, //与此窗口相关联的窗口句柄
NULL //一般为空
);
//显示窗口
ShowWindow(window, SW_SHOWNORMAL);
MSG msg{ 0 };
while (GetMessageW(&msg, 0, 0, 0))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
return 0;
}
Windows消息处理
Windows通用消息:
Windows通用消息标志都定义在WINUSER.H中,以WM_开头,大体分为三类。
-
窗口消息
例如:WM_CREATE;WM_CLOSE -
命令消息
特指WM_COMMAND消息,与处理用户请求有关,如点击菜单项,工具栏,控件等就会产生命令消息。 -
通知消息
特指WM_NOTIFY消息,只使用用windows的公共控件,如列表,视图等。
-
Windos控件消息
控件消息是用于控制控件的一些行为的,不同的控件有不同的控制消息,命名规则如下:
BM_按钮控制消息
EM_编辑框控制消息
STM_静态文本控制消息
CM_组合框控制消息
LBM_列表框控制消息 -
用户自定义消息
除了windows消息外,我们也可以定义自己的消息。系统的消息马在0-WM_USER之间,故而我们定义的消息大于WM_USER即可 -
消息的发送
PostMessage、SendMessage
PostMessage会将消息发送到消息队列,应用程序的消息循环会最终得到消息,并分发给回调函数。
SendMessage
相当于直接调用窗口的回调函数,等待窗口过程处理结束并返回结果。
根据发送消息的方式不同,消息分为两类:
队列消息、非队列消息。