Message mechanism (GUI thread explanation)

Prelude

First, let's draw a window:
Insert picture description here

Window code

#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;
		}
	}
}

Insert picture description here
Here we can control the color of the window through the console, so let's take a look at the principle together:

Can you answer these questions?

  1. What is a window handle? where is it? What is the use?
  2. What is a message? What is a message queue? Where is the message queue?
  3. What is a window procedure? Who calls the window procedure? Will the window procedure be executed without a message loop?
  4. Why is there a w32k.sys module?
  5. Why can only programs that use a graphical interface access KeServiceDescriptorTableShadow?
  6. Why does the mouse still work when the interface is "stuck"?

message queue:

Insert picture description here

Where is the message queue?

Insert picture description here

First of all, we assume that the message queue is placed in user space (ring 3), then who will store these things in and out of the message queue in user space?
The best solution is to find a dedicated process to listen for mouse and keyboard, the message queue is again to judge which process belongs to, and finally to distribute news (Linux solutions)
drawbacks: involves inter-process communication problems, special transfer process To other processes. A lot of time is spent across processes.

So how does Windows solve it?

First popularize it:
kernel32.dll----------> ntoskrnl.exe (process, thread, memory management
user32.dll gdi32.dll -----------> win32k.sys (graphic interface, Message management)

Windows has drawn the interface (provided by windows) GUI programming user32.dll
does not use those interfaces provided by Windows GDI programming gdi32.dll

Window handle HWN

For the window handle table, there is only one, (in the kernel) the table is global, shared by all windows

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);

It puts the message queue in ring 0 (kernel space),

Microsoft's solution: GUI thread
GUI (I use the window functions provided by Microsoft, such as the graphical interface created by CreateWindow, CreateButton, etc., this API is called GUI)

GDI (If you feel that the windows provided by Microsoft do not meet the requirements you need, you need to draw by yourself, those APIs used are called GDI)

Focus:

1. When threads are just created, they are all ordinary threads:
Thread.ServiceTable -->KeServiceDescriptorTable (SSDT table)
A table is stored in ServiceTable, called the system service table

2. When a thread calls Win32k.sys (a module related to the graphical interface) for the first time (as long as it tries to call any function in Win32k normally), it will call a function: PsConvertToGuiThread (convert a normal thread into a GUI thread)

PsConvertToGuiThread mainly does several things:
a. To expand the kernel stack, it must be replaced with a large 64KB kernel stack, because the normal kernel stack is only 12KB in size.
b. Create a structure containing a message queue and hang it on KTHREAD (that is, Win32Thread in KTHREAD)
c.Thread.ServiceTable–>KeServiceDescriptorShadow (SSDTShadow table)
d. Map the required memory data to the process space

(There is only one table referenced in the SSDT table, only one system service table, which is ntoskernel. The second table of win32k does not. But the SSDTShaow table contains both the functions in ntoskernel and Win32k (and graphics Interface-related function)
Explanation:
If it is a normal thread, then there is a Win32Thread member in the KTHREAD structure of the ETHRED structure, which is empty (not using the graphical interface-related API)
if it is a GUI thread , Then the member KTHREAD in the ETHRED structure has a Win32Thread member, which is an address value, points to a structure, points to a _THREADINFO structure, and there is another member in this structure that stores the message queue
Insert picture description here

Insert picture description here

to sum up:

  1. The message queue is stored in ring 0, which can be found through KTHREAD.Win32Thread
  2. Not all threads need message queues, only GUI threads have message queues
  3. One GUI thread corresponds to one message queue

Guess you like

Origin blog.csdn.net/CSNN2019/article/details/113824754