注册窗口
分为用户窗口和系统窗口
用户窗口
多种多样的,需要提前注册,需要填充一个数据结构(窗口清单)
首先声明一个Windows API主函数
int APIENTRY WinMain(
HINSTANCE hinstance, // handle to current instance
HINSTANCE hinstPrev, // handle to previous instance
LPSTR lpCmdLine, // address of command-line string
int nCmdShow) // show-window type
{
return 0
}
创建过程
注册窗口
WNDCLASS wc;
// 注册窗口
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)MainWndProc; //回调函数
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hinstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = HBRUSH(GetStockObject(WHITE_BRUSH));
wc.lpszMenuName = L"MainMenu";
wc.lpszClassName = L"MainWindowClass"; //类的名字
RegisterClass(&wc);
回调函数这里需要注册一个类来接收回调
LRESULT MainWndProc(HWND, UINT, WPARAM, LPARAM){
return 0;
};
创建窗口
注意,这里的创建窗口只是在内核中创建窗口对象(Window Object)并返回句柄(HWND),并不会真的渲染窗口
// 创建窗口
// 一旦成功,窗口并不会显示出来,而是会存在数据缓存区
HWND hwnd=CreateWindow(L"MainWindowClass",L"窗口", WS_OVERLAPPEDWINDOW,50,50,500,500,NULL,NULL, hinstance,NULL);
//设置hwnd拿到窗口的内存
渲染窗口
//渲染窗口
ShowWindow(hwnd,SW_SHOW);
UpdateWindow(hwnd);
处理消息
此时窗口会一闪而过,所以我们需要消息循环,持续刷新
MSG msg;
while(GetMessage(&msg,0,0,0)){
TranslateMessage(&msg);
DispatchMessageA(&msg);
}
此时需要操作系统处理我们不处理的消息,更改回调函数
LRESULT MainWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lparam) {
return DefWindowProc(hwnd, msg, wParam, lparam);
};
消息
概念
Windows 操作系统是 事件驱动(Event-Driven) 的。当用户触发输入(如点击鼠标、按下键盘)或系统状态发生改变(如窗口大小调整、定时器到期)时,操作系统会将这些事件封装为**“消息”(Message) ,投递给对应的窗口线程。
结构体
typedef struct tagMSG {
HWND hwnd; // 1. 窗口句柄:指定该消息属于哪一个具体窗口
UINT message; // 2. 消息 ID:一个无符号整数,代表具体事件(如 WM_PAINT, WM_LBUTTONDOWN)
WPARAM wParam; // 3. 附加参数1:32位/64位整型,通常传递简短数据(如按键的虚拟键码)
LPARAM lParam; // 4. 附加参数2:32位/64位整型,通常传递复杂数据(如鼠标点击的 X/Y 坐标,或内存指针)
DWORD time; // 5. 时间戳:消息被创建时的时间
POINT pt; // 6. 光标坐标:消息创建时,鼠标在屏幕上的绝对坐标 (x, y)
} MSG;
消息的作用与生命周期
消息的存在实现了操作系统与应用程序、以及应用程序各模块之间的解耦。其核心作用体现在消息循环的三个关键步骤中:
GetMessage(获取消息): 从当前线程的消息队列(Message Queue)中阻塞式地取出一条消息。如果队列为空,线程挂起,释放 CPU 资源。TranslateMessage(翻译消息): 专门用于处理键盘输入。它将按键消息(如WM_KEYDOWN和WM_KEYUP)组合翻译成字符消息(WM_CHAR),并重新投递回消息队列。DispatchMessage(分发消息): 这是最核心的一步。操作系统根据MSG.hwnd找到该窗口在注册时绑定的回调函数(lpfnWndProc) ,并直接调用该函数,将hwnd,message,wParam,lParam作为参数传入。
扩展消息
我们可以扩展消息回调函数的情况来针对不同消息展示不同的功能
LRESULT MainWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lparam) {
switch(msg){
case WM_CREATE:
MessageBox(0,0,0,0);
Break;
}
return DefWindowProc(hwnd, msg, wParam, lparam);// 去执行操作系统默认的函数
};
此时就需要更改我们的分发消息函数
MSG msg;
while(GetMessage(&msg,0,0,0)){
TranslateMessage(&msg);
// DispatchMessageA(&msg);
WinProc(msg.)
}
所有代码
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <windows.h>
#include<WinBase.h>
LRESULT MainWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lparam) {
switch (msg) {
case WM_CREATE:
MessageBox(0, 0, 0, 0);
break;
}
return DefWindowProc(hwnd, msg, wParam, lparam);//去执行操作系统默认的函数
};
int APIENTRY WinMain(
HINSTANCE hinstance, // handle to current instance
HINSTANCE hinstPrev, // handle to previous instance
LPSTR lpCmdLine, // address of command-line string
int nCmdShow) // show-window type
{
WNDCLASS wc;
// 注册窗口
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)MainWndProc; //回调函数
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hinstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = HBRUSH(GetStockObject(WHITE_BRUSH));
wc.lpszMenuName = L"MainMenu";
wc.lpszClassName = L"MainWindowClass"; //类的名字
RegisterClass(&wc);
// 创建窗口
// 一旦成功,窗口并不会显示出来,而是会存在数据缓存区
HWND hwnd = CreateWindow(L"MainWindowClass",L"窗口", WS_OVERLAPPEDWINDOW,50,50,500,500,NULL,NULL, hinstance,NULL);
//渲染窗口
ShowWindow(hwnd,SW_SHOW);
UpdateWindow(hwnd);
MSG msg;
while (GetMessage(&msg, 0, 0, 0))
{
TranslateMessage(&msg);
// DispatchMessageW(&msg);
MainWndProc(msg.hwnd,msg.message,msg.wParam,msg.lParam);
}
}
扩展风格
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <windows.h>
#include<WinBase.h>
// 透明风格
LRESULT MainWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lparam) {
switch (msg) {
case WM_CREATE:
MessageBox(0, 0, 0, 0);
break;
}
return DefWindowProc(hwnd, msg, wParam, lparam);//去执行操作系统默认的函数
};
int APIENTRY WinMain(
HINSTANCE hinstance, // handle to current instance
HINSTANCE hinstPrev, // handle to previous instance
LPSTR lpCmdLine, // address of command-line string
int nCmdShow) // show-window type
{
WNDCLASSEX wc = { 0 };//这里初始化一下
// 注册窗口
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)MainWndProc; //回调函数
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hinstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = HBRUSH(RGB(0,0,0));
wc.lpszMenuName = L"MainMenu";
wc.lpszClassName = L"MainWindowClass"; //类的名字
wc.cbSize = sizeof(WNDCLASSEX);
RegisterClassEx(&wc);//这里声明扩展风格
// 创建窗口
// 一旦成功,窗口并不会显示出来,而是会存在数据缓存区
HWND hwnd = CreateWindowEx(WS_EX_LAYERED, L"MainWindowClass", L"窗口", WS_POPUP, 50, 50, 500, 500, NULL, NULL, hinstance, NULL);
//设置分层窗口属性
SetLayeredWindowAttributes(hwnd, RGB(0,0,0),0 , LWA_COLORKEY);
//渲染窗口
ShowWindow(hwnd, SW_SHOW);
UpdateWindow(hwnd);
MSG msg;
while (GetMessage(&msg, 0, 0, 0))
{
TranslateMessage(&msg);
// DispatchMessageW(&msg);
MainWndProc(msg.hwnd, msg.message, msg.wParam, msg.lParam);
}
}