吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2213|回复: 9
上一主题 下一主题
收起左侧

[系统底层] win32笔记十一 窗口的本质

  [复制链接]
跳转到指定楼层
楼主
huchen 发表于 2024-5-7 00:12 回帖奖励
本帖最后由 huchen 于 2024-5-7 10:33 编辑

之前的笔记索引

窗口的本质

在学习进程的时候,我们得知了高2G与低2G,即内核与应用层,在应用层,每个进程都由许多的模块组成,而内核实际上本质并没有多大的差别,只是模块不一样罢了

在操作系统的内核空间,有很多模块,但是与我们编程息息相关的两个最重要的模块

为什么说最重要呢?

在之前的学习中,我们知道了怎么创建进程、线程等等所有与编程程序运行相关的功能实现,实际上都是在ntoskrnl.exe模块上实现的

那我们之前使用的API函数有啥关系呢?

我们用的创建进程、线程、终止进程、线程等,全是在这个模块上实现的,表面上感觉好像是kernel32提供的,其实他只是提供了一个接口

win32k是所有和图形界面相关的、消息管理相关的这些功能,全在这模块实现,想要使用的话,就可以使用旁边的两个dll,这两个是有区别的

  • 如果你想使用windows现成的,已经画好的图形界面,就使用user32.dll,管这种编程叫GUI
  • 如果你想自己画个东西出来,就用gdi32.dll,这种编程叫GDI

不管你用你那个dll最终的实现都是在win32k.sys模块上实现

在前面的学习,我们讲到了句柄表(HANDLE),对于图形界面,我们有一个新的句柄,是 HWND,这个句柄也是索引,不一样的是这个HWND是个全局表的索引

每一个窗口都是在win32k里(也就是在内核)画的,应用层想要使用这些窗口,只要得到这个句柄就行了,并且不同的进程得到同样的句柄返回的是同样的窗口,因为这是全局的

GDI的简单实现

这里不用去深究只是用GDI来了解窗口的本质和消息机制,并不是真的去画窗口

步骤

GDI 图形设备接口(Graphics Device Interface)

1.设备对象(HWND)

2.DC(设备上下文,Device Contexts)

3.图形对象

图像对象 作用
画笔(Pen) 影响线条,包括颜色、粗细、虚实、箭头形状等
画刷(Brushes) 影响对形状、区域等操作,如使用的颜色
字体(Fonts) 影响文字输出的字体
位图(Bitmaps) 影响位图创建、位图操作和保存

首先,设备对象的意思就是画在那,就比如说,我打开画图的程序

这里是一个窗口,那我就可以在这里画,那这个窗口又是谁画出来的呢?

win32k画的,所以就会有个句柄,这里就先用工具来获取句柄,工具会放在文末

获取到窗口句柄

代码

#include<windows.h>
int main()
{
        HWND hwnd;
        HDC hdc;
        HPEN hpen;
        //1.设备对象,画在那
        hwnd = (HWND)0x00080A3E;        //NULL为桌面

        //2.获取设备对象上下文
        hdc = GetDC(hwnd);

        //3.创建画笔,设置线条的属性
        hpen = CreatePen(PS_SOLID, 5, RGB(0xFF, 0, 0));

        //4.关联
        SelectObject(hdc,hpen);

   //5.开始画
        MoveToEx(hdc, 0, 400, NULL);//hdc 起始x坐标 起始y坐标 原来的位置,需要的话用指针接收
        LineTo(hdc, 400, 400);

        //6.释放资源 Get对应Release Create对应Delete
        DeleteObject(hpen);
        DeleteObject(hBrush);
        ReleaseDC(hwnd, hdc
        return 0;

}

GetDC

HDC GetDC(
  HWND hWnd   // handle to window
);

需要传个HWND类型的句柄,返回值为HDC类型,想要画东西,就必须先要往他的内存里画,然后在打印到设备上

LineTo

BOOL LineTo(
  HDC hdc,    // device context handle
  int nXEnd,  // x-coordinate of ending point
  int nYEnd   // y-coordinate of ending point
);

首先是你要在那个内存中画线,后面的两个参数就是终止的x,y坐标,我们的屏幕就像是坐标系,左上角是(0,0)

然后就要设置图形的对象了,比如说画的是线还是面,多长多宽,什么颜色等等,详情请见步骤中的第3条

所以,假如我要画一条线,就要先创建画笔,设置线条的属性

CreatePen

HPEN CreatePen(
  int fnPenStyle,    // pen style
  int nWidth,        // pen width
  COLORREF crColor   // pen color
);

第一个参数就是笔的风格,比如:实线,虚线,波浪线等

第二个参数是线有多宽

CreatePen returns a pen with the specified width bit with the PS_SOLID style if you specify a width greater than one for the following styles: PS_DASH, PS_DOT, PS_DASHDOT, PS_DASHDOTDOT.

如果对于以下样式指定了大于一的宽度 PS_DASH,PS_DOT,PS_DASHDOT,PS_DASHDOTDOT,CreatePen 函数将返回一个具有指定宽度的 PS_SOLID 样式的画笔。

也就是说上面的格式宽度超过了1,就会变成实线

第三个就是颜色,也就是RGB,分别是红、绿、蓝三种颜色,这三种颜色被称为原色(没记错的话),也就是说这三个颜色可以组成任何颜色

COLORREF RGB(
  BYTE byRed,    // red component of color
  BYTE byGreen,  // green component of color
  BYTE byBlue    // blue component of color
);

可以看到这里没个都是1字节,你能看过这种类型的#FF0000,这个代码就是红色,每个字节都是0~FF,可以把这个理解成浓度,而#FF0000就是纯红色,#00FF00是纯绿色,#0000FF就是纯蓝色,除了这三种代码,以外而组成的其他颜色就是中间色

SelectObject

HGDIOBJ SelectObject(
  HDC hdc,          // handle to DC
  HGDIOBJ hgdiobj   // handle to object
);

把hdc,和hpen关联起来,在画的时候用我设置的画笔去画,而不是默认的画笔

也可以画一个区域

#define _CRT_SECURE_NO_WARNINGS 1
#include<windows.h>
int main()
{
        HWND hwnd;
        HDC hdc;
        HPEN hpen;
        HBRUSH hBrush;
        //1.设备对象,画在那
        hwnd = (HWND)NULL;

        //2.获取设备对象上下文
        hdc = GetDC(hwnd);

        //3.创建画笔,设置线条的属性
        hpen = CreatePen(PS_SOLID, 5, RGB(0xFF, 0, 0));
        hBrush = (HBRUSH)GetStockObject(DC_BRUSH);

        //4.关联
        SelectObject(hdc,hpen);
        SelectObject(hdc, hBrush);

        //5.开始画
        //MoveToEx(hdc, 0, 400, NULL);//hdc 起始x坐标 起始y坐标 原来的位置,需要的话用指针接收
        //LineTo(hdc, 400, 400);
        SetDCBrushColor(hdc, RGB(0xFF, 0xFF, 0));
        Rectangle(hdc, 0,0, 400, 400);

        //6.释放资源 Get对应Release Create对应Delete
        DeleteObject(hpen);
        DeleteObject(hBrush);
        ReleaseDC(hwnd, hdc);
        return 0;
}

有些API就不介绍了,查文档,挺简单的

(有个问题,win10运行后直接一闪而过了,我在虚拟机winxp运行却提示DC_BRUSH和SetDCBrushColor函数未定义)

消息队列

什么是消息?

当我们点击鼠标的时候,或者当我们按下键盘的时候,操作系统都要把这些动作记录下来,存储到一个结构体中,这个结构体就是消息

比如,使用图形界面的程序,像画图这个程序,可以拖动,可以缩小,可以最大化,可以用笔画画有显示等,这些都是消息,并且存储在一个地方,这个地方就是线程

每个线程只有一个消息队列,因此是一对一的关系

当我们在使用鼠标或键盘时,并不是应用程序先接收到,而是操作系统先接收到动作,然后再发送给你当前进程对应的线程,然后再做出相应的反馈

假如有三个进程,显示了有三个窗口,A、B、C,当我要关闭A窗口时,为什么是A窗口做出反应,而不是别的窗口?

当你点下去的时候,操作系统就会接收到,你在哪里点的?你的坐标?你的动作,左键还是右键等等这些信息封装到结构体里,我们称之为消息,封装好后,这些信息应该给谁呢?我应该把信息放进消息队列里去,但这里有三个进程,并且一个进程不止一个线程,那我该给那个进程的那个线程里的消息队列呢?

这些界面都是win32k模块画出来的,每一个窗口在零环都有一个结构体,里面有许多信息,比如,从哪开始、有多宽、我在什么位置等等,还有一个成员就是当前这个窗口所属的线程是谁,那么上面的疑问也就解开了

当我们点击红叉的时候,操作系统会根据我点的左键还是右键等生成一个消息,这个消息没有办法找到是属于谁的,但是能根据信息找到是那个窗口,所以消息一定是针对窗口的,遍历窗口对象来找到是属于那个窗口

一个线程是可以拥有多个窗口的,但无论是哪个窗口接收到消息,都是存在同样的消息队列



工具: Spy_2.7.rar (458.72 KB, 下载次数: 37)
这个工具也是论坛中的大佬所做,真滴好用啊,原文找不到了T_T

免费评分

参与人数 7吾爱币 +12 热心值 +5 收起 理由
asciibase64 + 1 谢谢@Thanks!
池塘春草 + 1 谢谢@Thanks!
willJ + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
hjl008 + 1 用心讨论,共获提升!
等到烟火也清凉 + 1 + 1 我很赞同!
jhoneyr + 1 + 1 谢谢@Thanks!
Bob5230 + 1 + 1 热心回复!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

沙发
等到烟火也清凉 发表于 2024-5-7 10:14
学习了解win的好帖
3#
kestrel 发表于 2024-5-7 10:24
4#
Liebesfreud 发表于 2024-5-7 10:32
5#
qwq23496 发表于 2024-5-7 12:44
感谢分享,学习了
6#
nitian0963 发表于 2024-5-7 15:57

感谢分享,学习了
7#
ihjun 发表于 2024-5-7 17:51
现在还有学windowns编程的,赞
8#
irework 发表于 2024-5-8 10:29
感谢分享!
9#
hazier 发表于 2024-5-8 18:18
句柄部分挺清楚的,获取窗口句柄,以及类型和传值
10#
woaiwozhui 发表于 2024-5-9 11:16
写的蛮清晰的,学习一下
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-21 16:02

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表