赞
踩
首先我们来画一个窗口:
#include<Windows.h> #include <stdio.h> #define _WIN32_WINNT 0x0500 typedef struct _Color { DWORD r; DWORD g; DWORD b; }Color; typedef struct _WindowClass { DWORD x; DWORD y; DWORD width; DWORD hight; Color color; }WindowClass; void PaintWindwos(HDC hdc, WindowClass* p) { HBRUSH hBrush; hBrush = (HBRUSH)GetStockObject(DC_BRUSH); SelectObject(hdc, hBrush);//画刷 SetDCBrushColor(hdc, RGB(p->color.r, p->color.g, p->color.b)); MoveToEx(hdc, p->x, p->y, NULL); LineTo(hdc, p->x + p->width, p->y); LineTo(hdc, p->x + p->width, p->y + p->hight); LineTo(hdc, p->x, p->y + p->hight); LineTo(hdc, p->x, p->y); Rectangle(hdc, p->x, p->y, p->x + p->width, p->y + p->width + 1); DeleteObject(hBrush); } void main() { char cMessage; //消息 HWND hwnd; //画在哪 HDC hdc; //显卡缓存 //设置窗口参数:长宽高之类的 WindowClass wClass; wClass.x = 0; wClass.y = 0; wClass.width = 800; wClass.hight = 400; wClass.color.r = 0xEF; wClass.color.g = 0xEB; wClass.color.b = 0xDE; //画在哪 hwnd = GetDesktopWindow(); //hwnd=FindWindow("notepad.exe",NULL); //获取DC设备句柄:可以把DC理解成显卡缓存 hdc = GetWindowDC(hwnd); cMessage = getchar(); for(;;) { //画窗口 PaintWindwos(hdc, &wClass); //接收消息 switch (cMessage) { case 'a': wClass.color.r += 0x10; wClass.color.g += 0x10; wClass.color.b += 0x10; break; case 'b': wClass.color.r += 0x20; wClass.color.g += 0x20; wClass.color.b += 0x20; break; default: break; } } }
在这里呢我们可以通过控制台去控制窗口的颜色,那么接下来让我们一起来看看原理:
首先我们假设把消息队列放在用户空间(3环),那么谁又来往用户空间的消息队列存储这些东西呢?
最好的解决方案就是找一个专用进程来监听鼠标和键盘等,再来进行判断是属于哪个进程的消息队列,最后来进行消息分发(Linux解决方案)
弊端:涉及了跨进程通信问题,专用进程传给其它进程。大量时间都花在跨进程。
首先普及一下:
kernel32.dll
----------> ntoskrnl.exe(进程,线程,内存管
user32.dll gdi32.dll -----------> win32k.sys(图形界面,消息管理)
Windows已经画好的界面(windows提供的)GUI编程 user32.dll
不用Windows提供的那些界面 GDI编程 gdi32.dll
窗口句柄HWN
针对窗口的句柄表,只有一个,(放在内核中)表是全局的,所有窗口共用的
HDC hdc;
HPEN hpen;
1.设备对象 画在哪
hwnd =(HWND)0x0003543;
2.获取设备对象上下文
hdc=GetDC(hwnd);
3.创建画笔 设置线条属性
hpen=CreatePen(PS_S0LID,5,RGB(0xFF,00,00));
4.关联
SelectObject(hdc,hpen);
5.开始画
LineTo(hdc,400,400);//gdi32.dll
6.释放资源
DeleteObject(hpen);
ReleaseDC(hwnd,hdc);
它把消息队列放在(内核空间)0环中,
微软的解决方案:GUI线程
GUI(自己使用微软提供的窗口函数,比如CreateWindow,CreateButton等创建的图形界面,这种API就叫做GUI)
GDI(如果觉得微软提供的窗口不符合自己所需条件,需要自己画,所用的那些API就叫GDI)
1.当线程刚创建的时候,都是普通线程:
Thread.ServiceTable -->KeServiceDescriptorTable(SSDT表)
ServiceTable中存储了一张表,叫做系统服务表
2.当线程第一次调用(与图形界面相关的模块 )Win32k.sys时(只要试图正常调用Win32k中的任何一个函数),会调用一个函数:PsConvertToGuiThread(把普通线程转换为GUI线程)
PsConvertToGuiThread主要做几件事:
a.扩充内核栈,必须换成64KB 的大内核栈,因为普通内核栈只有12KB大小。
b.创建一个包含消息队列的结构体,并挂到KTHREAD上(也就是KTHREAD中的Win32Thread)
c.Thread.ServiceTable–>KeServiceDescriptorShadow(SSDTShadow表)
d.把需要的内存数据映射到本进程空间
(SSDT表中只引用了一张表,只有一张系统服务表,也就是ntoskernel,win32k的第二张表它没有。但是SSDTShaow表中既包含了ntoskernel中的函数,又包含了Win32k(与图形界面相关的)中的函数)
解释:
如果是一个普通线程的话,那么ETHRED结构体中成员KTHREAD结构体中有一个Win32Thread成员它是为空(未使用图形界面相关的API)
如果是一个GUI线程的话,那么ETHRED结构体中成员KTHREAD有一个Win32Thread成员它是一个地址值,指向一个结构体,指向一个_THREADINFO结构体,这个结构体里面又有一个成员,存放着消息队列
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。