Windows核心编程随笔

 

最近在学习Windows底层原理,准备写个系列文章分享给大家,Michael Li(微软实习期间的Mentor,为人超好)在知乎回答过一些关于学习Windows原理的书籍推荐,大家可以拜读其中一本来入门。我是先从《Windows核心编程》开始了解一些Windows底层管理与硬件交互的原理,然后买了一套冬瓜哥撰写的《大话计算机》系列丛书,学有余力的童鞋强烈推荐你去看看,这套书对计算机整体的运作原理讲解的很系统,涉及了计算机组成原理、网络原理、编译原理、操作系统、硬件等,可以作为不错的入门教材。

Windows核心编程(第5版)电子书及配套代码

学习前需要理解一些系统专业词汇的概念,比如:系统资源、内存管理、句柄、内核态/用户态、Hook、事件、消息处理机制等。不然后续对Windows底层原理的理解会有些误差和盲区,例如很容易将系统资源和CPU资源(CPU使用率)相混淆。

Windows核心编程随笔_控件

Windows核心编程随笔_整型_02

我们将Linux、Unix、Windows对其内核进行对比学习Windows的内核管理机制。

Linux:

Linux 优先使用物理内存,当物理内存还有空闲时,linux是不会释放内存的,即时占用内存的程序已经被关闭了(这部分内存就用来做缓存了)。也就是说,即时你 有很大的内存,用过一段时间后,也会被占满。这样做的好处是,启动那些刚开启过的程序、或是读取刚存取过得数据会比较快,对于服务器很有好处。

Windows:

windows则总是给内存留下一定的空闲空间,即时内存有空闲也会让程序使用一些虚拟内存,这样做的好处是,启动新的程序比较快,直接分给它些空闲内存就可以了,而linux下呢?由于内存经常处于全部被使用的状态,则要先清理出一块内存,再分配给新的程序使用,因此,新程序的启动会慢一些。

Windows是由C语言编写的,但是整个系统是面向对象设计的,所以引入了句柄这种数据结构。句柄是一种指向指针的指针,确切点说句柄是一种指向结构体的指针,而指针就是一串内存地址。

Windows是基于事件驱动机制的,整个系统都是通过消息传递来实现的。

Issue:

各大系统平台的程序是用什么机制来接收用户的事件而做出反应的?

Windows的消息系统是如何支持带有图形用户界面的应用程序?

点击鼠标,触发一个系统事件(事件本质上是对消息的封装)——>Windows把这个事件翻译为消息,然后把它放到消息队列中,传递给应用程序——>应用程序从消息队列中接收到这个消息,把它存放在TMsg记录中——>应用程序把消息传递给一个适当的窗口的窗口过程(回调函数)——>窗口过程响应这个消息并进行处理

Windows操作系统消息包括:标准Windows消息(WM_打头) + 通知消息(针对标注Windows控件) + 自定义消息(编程)

消息系统(内核控制中心)组成:消息队列 + 消息循环 + 窗口过程

在Windows中发生的一切都可以用消息来表示,消息用于告诉操作系统发生了什么,所有的Windows应用程序都是消息驱动的。消息本身是作为一个记录传递给应用程序的,这个记录(一般在 C/C++/汇编 中称为“结构体”)中包含了消息的类型以及其他信息。例如,对单击鼠标所产生的消息来说,这个记录(结构体)中包含了单击鼠标的消息号(WM_LBUTTONDOWN)、单击鼠标时的坐标(由X,Y值连接而成的一个32位整数)。这个记录类型叫做TMsg。

在C语言中消息的定义:

typedef struct Msg
{
HWND hwnd; / /窗口句柄
UINT message; / /消息常量标识符
WPARAM wParam; // 32位消息的特定附加信息
LPARAM lParam; // 32位消息的特定附加信息
DWORD time; / /消息创建时的时间
TPoint pt; / /消息创建时的鼠标位置
} TMsg;
typedef struct TPoint
{
int x;
int y;
}TPoint;


不是每个控件都能接收消息,转发消息和绘制自身,只有具有句柄(handle)的控件才能做到。有句柄的控件本质上都是一个窗体(window),它们可以独立存在,可以作为其它控件的容器,而没有句柄的控件,如Label,是不能独立存在的,只能作为窗口控件的子控件,它不能绘制自身,只能依靠父窗体将它绘制来。

然而,并非所有的句柄都是窗体的句柄,Windows系统中还中很多其它类型的句柄,如画布(hdc)句柄,画笔句柄,画刷句柄,应用程序句柄(hInstance)等。这种句柄是不能接收消息的。但不管是哪种句柄,都是系统中对象的唯一标识。本文只讨论窗体句柄。

那为什么句柄使窗口具有了如此独特的特性呢?实际是都是由于消息的原因。由于有了句柄,窗体能够接收消息,也就知道了该什么时候绘制自己,绘制子控件,知道了鼠标在什么时候点击了窗口的哪个部分,从而作出相应的处理。句柄就好像是一个人的身份证,有了它,你就可以从事各种社会活动;否则的话,你要么是一个社会看不到的黑户,要么跟在别人后面,通过别人来证明你的存在。

Windows保存的消息队列是以线程(Thread)来分组的,也就是说每个线程都有自己的消息队列。事件本质上是对消息的封装。



有哪些内核对象:

令牌对象 Token

事件对象 Event

文件对象 File

文件映射对象 Mapping File

线程对象 Thread

时钟对象 Timer

线程池对象 ThreadPool

I/O完成端对象 Completion port

工作对象 Job

邮槽对象 Mailslot

互斥对象 Mutex

管道对象 Pipe

进程对象 Process

信号灯对象 Semaphore

...

内核对象的结构:

公用部分(安全描述符、计数器) + 个性部分

句柄、Windows数据类型:

WORD:16位无符号整型数据

DWORD:32位无符号整型数据(DWORD32)

DWORD64:64位无符号整型数据

INT:32位有符号整型数据类型

INT_PTR:指向INT数据类型的指针类型

INT32:32位符号整型

INT64:64位符号整型

UINT:无符号INT

LONG:32位符号整型(LONG32)

ULONG:无符号LONG

LONGLONG:64位符号整型(LONG64)

SHORT:无符号短整型(16位)

LPARAM:消息的L参数

WPARAM:消息的W参数

HANDLE:对象的句柄,最基本的句柄类型

HICON:图标的句柄

HINSTANCE:程序实例的句柄

HKEY:注册表键的句柄

HMODULE:模块的句柄

HWND:窗口的句柄

LPSTR:字符指针,也就是字符串变量

LPCSTR:字符串常量

LPCTSTR:根据环境配置,如果定义了UNICODE宏,则是LPCWSTR类型,否则则为LPCSTR类型

LPCWSTR:UNICODE字符串常量

LPDWORD:指向DWORD类型数据的指针

CHAR:8比特字节

TCHAR:如果定义了UNICODE,则为WCHAR,否则为CHAR

UCHAR:无符号CHAR

WCHAR:16位Unicode字符

BOOL:布尔型变量

BYTE:字节类型(8位)

CONST:常量

FLOAT:浮点数据类型

SIZE_T:表示内存大小,以字节为单位,其最大值是CPU最大寻址范围

VOID:无类型,相当于标准C语言中的void

WINAPI:Windows API的函数调用方式,常见于SDK头文件中对API函数的声明中,相当于_stdcall(更严格地说,这不是数据类型,而是一种函数调用约定

BYTE 8位 unsigned char

CHAR 8位 char

BOOL 16位 int

DWORD 32位 unsigned long int

HANDLE 一般句柄

HWND 32位 long int

LONG 32位 long int

LPCSTR 指向字符串的 const 指针

LPSTR 指向字符串的指针

SHORT 16位短整数

UINT 32位无符号长整数

WORD 16位无符号短整数

BITMAP 独立于逻辑设备的位图(DIB)

LOGBRUSH 逻辑刷

LOGFONT 逻辑字体

LOGPEN 逻辑笔

MSG 窗口消息

POINT 点

RECT 矩形

WNDCLASS 窗口类结构

hBitmap 为保存DIB图像信息的内存域的句柄

hBrush 当画图时用于填满设备范围的刷子的句柄

hCtl 子窗口控件的句柄

hCursor 鼠标光标句柄

hDc 设备描述表句柄

hDlg 文本字体的句柄

hFont 文本字体的句柄

hIcon 图标的句柄

hInstance windows应用程序实例句柄

hMem 内存块句柄

hMenu 菜单或弹出式菜单句柄

hModule 模式的句柄,常用于从一可执行文件获取资源数据

hPalette 颜色调色板

hPen 当在设备上画图时用于指明线型的笔的句柄

hRgn 在窗口上剪贴一块区域的句柄

hTask 独立于已执行的任务的句柄

hWnd 窗口句柄

持续更新中...

 

============ End