Windows窗口是怎么创建的呢
windows的窗口是由windows内核中的win32k.sys这个一个模块中提供的接口实现的,理解如下图
Windows消息概念介绍
Windows是由消息驱动的操作系统,消息类似于发一条指令,操作系统收到这条指令调用自己的窗口过程函数去处理这条指令,
事件:点击鼠标左键,右键,输入键盘都是一系列动作称为事件
消息:事件的映射(把事件封装成一个MSG结构体),一个消息对应一个事件,这个消息也就代表这个事件
例如我们常见的点击鼠标左键这个事件就会被操作系统封装成一条消息,操作系统把消息存储在对应的应用程序的线程消息队列中如下图
个人图解消息传递机制
创建一个完整的窗口的需要6个步骤
设计注册窗口类
创建窗口示例
显示窗口
更新窗口
实现消息循环
实现窗口回调
// Win32Test.cpp : 定义应用程序的入口点。
//
#include "stdafx.h"
#include "Win32Test.h"
void ShowErrorMessage()
{
LPVOID lpMsgBuf;
//将错误码转化为错误信息,参数可以抄MSDN
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.
// ...
// 弹出错误提示窗口.
MessageBox(NULL, (LPCTSTR)lpMsgBuf, TEXT("Error"), MB_OK | MB_ICONINFORMATION);
// Free the buffer.
LocalFree(lpMsgBuf);
}
LRESULT CALLBACK MyWindowPro
(HWND hwnd, // 窗口句柄
UINT uMsg, // 消息标识
WPARAM wParam, // 附加在消息上的参数
LPARAM lParam // 附加在消息上的参数
)
{
switch (uMsg)
{
case WM_NCCREATE://创建窗口先发送WM_NCCREATE消息,系统默认处理是返回ture创建客户区发送WM_CREATE消息,//非客户区,窗口自带区
{
return TRUE;
}
case WM_CREATE://客户区,可供编辑区域
{
CREATESTRUCT* pcs = (CREATESTRUCT*)lParam;
int nVal = (int)pcs->lpCreateParams;//这就是CreateWindow最后的参数
break;
}
//点击关闭窗口会发送WM_CLOSE消息
case WM_CLOSE:
{
int nRet = MessageBox(hwnd, TEXT("是否退出"), TEXT("询问"), MB_OKCANCEL);
if (nRet == IDCANCEL)//取消关闭
{
return 0;
}
else
{
//摧毁窗口发送WM_DESTROY消息
DestroyWindow(hwnd);
}
break;
}
// 鼠标消息,左键按下
case WM_LBUTTONDOWN:
{
int xPos = LOWORD(lParam);
int yPos = HIWORD(lParam);
break;
}
case WM_DESTROY:
{
//向消息队列投递WM_QUIT消息 WM_QUIT使消息循环退出,程序退出。
PostQuitMessage(0);
break;
}
default:
break;
}
//系统默认处理消息窗口函数
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW; //默认风格,窗口尺寸被修改后重画窗口
wc.lpfnWndProc = MyWindowPro; //窗口回调,处理消息的(Windows消息处理用的是回调函数处理消息的,因为windows知道消息什么时候来并不知道怎么处理,所以通过回调去处理)
wc.cbClsExtra = 0; //窗口类的额外空间
wc.cbWndExtra = 0; //窗口实例的额外空间
wc.hInstance = hInstance;
wc.hIcon = NULL; //图标
wc.hCursor = NULL; //光标
wc.hbrBackground = NULL;//背景
wc.lpszMenuName = NULL;//菜单
wc.lpszClassName = TEXT("MyWindow");
ATOM nRet = RegisterClass(&wc);
return nRet;
}
HWND MyCreatWindow(HINSTANCE hInstance)
{
//创建窗口实例
HWND hWnd = CreateWindow(
TEXT("MyWindow"), //窗口类名
TEXT("Hello World"), //窗口标题
WS_OVERLAPPEDWINDOW, //重叠窗口
CW_USEDEFAULT, CW_USEDEFAULT, //默认坐标
CW_USEDEFAULT, CW_USEDEFAULT,//默认长和宽
NULL, //没有父窗口
NULL, //没有菜单
hInstance,//main函数的实例句柄
NULL//暂时不用,(LPVOID)0x87654093,可用来做参数标记
);
//显示窗口
ShowWindow(hWnd, SW_SHOW);
//更新窗口
UpdateWindow(hWnd);
return hWnd;
}
//句柄可以理解为标识ID,如窗口句柄就表示这个标识这个窗口的唯一ID
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,//应用程序当前实例的句柄
_In_opt_ HINSTANCE hPrevInstance,//应用程序的先前实例的句柄
_In_ LPTSTR lpCmdLine,//指向应用程序命令行的字符串的指针
_In_ int nCmdShow)//指明窗口如何显示,查msdn帮助文档,有各种宏
{
ATOM nRet = MyRegisterClass(hInstance);
if (nRet == 0)
{
ShowErrorMessage();
}
HWND hWnd = MyCreatWindow(hInstance);
if (hWnd == NULL)
{
ShowErrorMessage();
}
MSG msg;
//获取消息
while (GetMessage(&msg, NULL, 0, 0) != 0)
{
//处理消息
MyWindowPro(msg.hwnd, msg.message, msg.wParam, msg.lParam);
}
return 0;
}