win32核心编程01:进程和线程

目录

0x00 进程:

1.如何去了解进程?

2.进程的组成:

3.进程调度

4.进程的优先级:

5.进程的状态:

6.僵尸进程出现的原因:

7.创建进程的方式

8.进程的其他函数:

1.FindWindow()

2.OpenProccess:

3.TerminateProcess(进程句柄,错误码):

4.DWORD GetProcessId(句柄) :

5.EnumProcess:

0x01 线程:

1.进程和线程区别:

2.线程使用

2.1线程的创建

创建三个线程,分别打印不同的值

2.2线程参数:

2.3线程的控制:


 


0x00 进程:

什么叫进程?所谓进程,就是一个运行中的程序。

进程的相关信息:

1.如何去了解进程?

  1. 任务管理器
  2. 命令:tasklist
  3. 命令:wmic 然后输入process

2.进程的组成:

  1. 每个进程都有它的可执行文件(代码,每个进程都会有一个主函数)
  2. 每个进程都有其所控制的内存段(这个内存可以只由这个进程使用,即绑定了所有权;也可以共享使用,即共享内存)
  3. 每个进程都有属于自己的时钟
  4. CPU的时间片
  5. 进程所占据的其他资源(图片资源呀,堆内存呀)

3.两种简单的CPU调度算法

1.绝对公平机制

CPU公平的分配给每个进程,这些进程存放在一个队列中。例如:CPU先分配给进程1处理5ms,然后分配给进程2处理5ms,然后分配给进程3处理5ms

2.优先机制

例如操作系统的启动进程boot,优先占据CPU,只有当这个进程用完CPU之后,其他进程才能使用CPU

4.进程的优先级:

5.进程的状态:

  1. 运行时
  2. 等待
  3. 挂起状态
  4. 睡眠状态
  5. 死亡状态:进程结束了,但是它占据的资源还没有被释放,这个时间非常短,但是存在。死亡状态占据的资源最终是可以被回收的。
  6. 僵尸状态:进程结束了,但是它占据的资源还没有被释放,并且我们没有办法释放这些资源。解决方法:重启操作系统。

培训机构有时真是误人子弟呀,学了操作系统回头来看自己的笔记,真是谬误颇多。进程的状态应该如下分类:

1.就绪态:被分配了内存等资源,但是还有被分配CPU

2.运行态:被分配了资源,并且被分配了CPU

3.等待态(阻塞态,挂起态):进程被剥夺CPU和资源,进入外存的阻塞队列。

4.僵尸态:子进程结束后,父进程收尸前的这一段时间子进程的状态称为僵尸态。

 

6.僵尸进程出现的原因:

进程结束的方式:

1.进程自己结束自己,操作系统os控制这个进程的进程会回收这个进程的资源。

2.进程被别的进程干掉:如果该进程有父进程,那么父进程负责进程资源的回收。如果没有父进程,操作系统的init进程(它是操作系统的第一个进程)会收养这个进程,负责进程资源的回收。

如果一个进程有父进程,但是父进程先于子进程结束,在init进程收养子进程之前,子进程被别的进程干掉了。那么子进程就会变成僵尸进程。

所以,保证父进程晚于子进程结束,就能避免僵尸进程的产生。

7.创建进程的方式

  1. 运行可执行程序
    1. 命令行运行。
    2. 在程序中执行命令行命令:system("c://xxxx//Desktop//xxx.exe")
  2. 在程序中调用windowsAPI 创建进程
    1. CreateProcess创建一个进程
      CreateProcessW(
          LPCWSTR lpApplicationName, //应用程序名
          LPWSTR lpCommandLine,    //命令行参数
          LPSECURITY_ATTRIBUTES lpProcessAttributes, //进程属性
          LPSECURITY_ATTRIBUTES lpThreadAttributes,//线程属性,因为一个进程可以有多个线程
          BOOL bInheritHandles,//是否继承
          DWORD dwCreationFlags,//创建方式
          LPVOID lpEnvironment,//环境变量
          LPCWSTR lpCurrentDirectory,//当前目录
          LPSTARTUPINFOW lpStartupInfo,//启动信息
          LPPROCESS_INFORMATION lpProcessInformation//返回进程信息
          );

      实例:用一个程序打开12-三级缓存.exe并输出该进程的相关信息

      #include <iostream>
      #include <Windows.h>
      #include <cstring>
      using namespace std;
      
      int main()
      {
      	STARTUPINFO startInfo = { 0 };
      	startInfo.lpTitle = new char[256];
      	strcpy(startInfo.lpTitle, TEXT("程序中打开GDI程序"));
      	PROCESS_INFORMATION processInfo;
      	bool is = CreateProcess(TEXT("C:\\Users\\Administrator\\Desktop\\我的代码\\2019-11\\13-三级缓存防闪烁\\12-三级缓存防闪烁\\Debug\\12-三级缓存防闪烁.exe"),NULL,NULL,NULL,false,NULL,NULL,NULL,&startInfo,&processInfo);
      	if (is) {
      		cout << TEXT("创建进程成功!") << endl;
      		cout << "进程id:" << processInfo.dwProcessId << endl;
      		cout << "线程id:" << processInfo.dwThreadId << endl;
      		cout << "进程句柄:" << processInfo.hProcess << endl;
      		cout << "线程句柄:" << processInfo.hThread << endl;
      	}
      	else {
      		cout << TEXT("创建进程失败!") << endl;
      	}
      	return 0;
      }

       

    2. 当一个应用程序需要对系统资源进行管理时,这个应用程序的图标上就会有一个盾牌,CreateProcess函数无法直接启动一个有盾牌的应用程序,因为CreateProcess会默认以标准用户的身份去启动这个程序。但是启动“盾牌”程序需要管理员身份。这时就需要我们在代码中手动提权,以管理员身份启动程序(对应函数ShellExecuteEx)。代码如下:

    3. 首先,我封装了一个专门用来提权启动的函数CreateProcessAsAdmin(PTCHAR fileName):

      HANDLE CreateProcessAsAdmin(PTCHAR fileName) {
      	SHELLEXECUTEINFO sei = {0};
      	sei.cbSize = sizeof(SHELLEXECUTEINFO);
      	sei.lpVerb = TEXT("runas");
      	sei.lpFile = fileName;
      	sei.nShow = SW_SHOWNORMAL;
      	sei.fMask = SEE_MASK_NOCLOSEPROCESS;
      
      	if (!ShellExecuteEx(&sei)) {
      		DWORD dwError = GetLastError();
      		if (dwError == ERROR_CANCELLED) {
      			cout << "提权失败!" << endl;
      		}
      		else if (dwError == ERROR_FILE_NOT_FOUND) {
      			cout << "未找到文件" << endl;
      		}
      		//return NULL;//可有可无
      	}
      	return sei.hProcess;
      }

      注意:fMask必须设置为SEE_MASK_NOCLOSEPROCESS,否则sei.hProcess的值为空。return NULL可有可无,因为如果进程打开失败,sei.hProcess的值本来就是NULL(第一步时我们将整个结构体置零了哦)。

    4. 主函数逻辑:创建进程,如果进程创建失败

      int main(){
      	TCHAR buff[1024] = TEXT("C:\\Users\\Rui\\Desktop\\MapKeyboard.exe");
      	STARTUPINFO startUpInfo = { sizeof(startUpInfo) };
      	PROCESS_INFORMATION processInformation;
      	BOOL isCreate = CreateProcess(NULL, buff, NULL, NULL, false, NULL, NULL, NULL, &startUpInfo, &processInformation);
      	if (!isCreate) {
      		cout << "创建子进程失败!" << endl;
      		DWORD error = GetLastError();
      		if (error == ERROR_FILE_NOT_FOUND) {
      			cout << "未找到文件" << endl;
      		}
      		else if (error = ERROR_CANCELLED) {
      			cout << "权限不足" << endl;
      			HANDLE hProcess = CreateProcessAsAdmin(buff);
      		}
      	}
              return 0;
      
      }

       

8.进程的其他函数:

1.FindWindow()

HWND FindWindowA(
    LPCSTR lpClassName,//窗口类的类名
    LPCSTR lpWindowName);//窗口的名字

这个函数只要给它窗口类的类名和窗口的名字,它就能返回窗口的句柄。如何知道窗口类的类名,通过工具>>spy++,只要获得窗口的句柄,那么就可以通过SendMessage来控制窗口。

#include "pch.h"
#include <iostream>
#include <Windows.h>
#include <cstring>
using namespace std;
int main()
{
	HWND hwnd = FindWindow("DuiHostWnd", "欢迎使用百度网盘");
	if (INVALID_HANDLE_VALUE == hwnd) {
		cout << "获取窗口句柄失败!" << endl;
	}
	else {
		cout << "获取窗口句柄成功!" << endl;
	
	}
	SendMessage(hwnd, WM_DESTROY, NULL, NULL);
	

	return 0;
}

 

2.OpenProccess:

用来打开一个进程,指获得这个进程的控制权限。前提是知道这个进程的id

3.TerminateProcess(进程句柄,错误码):

通过句柄来关闭一个进程

4.DWORD GetProcessId(句柄) :

通过句柄来返回一个进程的id

for instance:思路是创建一个进程,然后通过句柄关闭它,然后在通过OpenProcess打开它。通过命令行查看前后两次打开id和句柄的变化。

#include "pch.h"
#include <iostream>
#include <Windows.h>
#include <cstring>
using namespace std;

int main()
{
	STARTUPINFO startInfo = { 0 };
	startInfo.lpTitle = new char[256];
	strcpy(startInfo.lpTitle, TEXT("程序中打开GDI程序"));
	PROCESS_INFORMATION processInfo;
	bool is = CreateProcess(TEXT("C:\\Users\\Administrator\\Desktop\\我的代码\\2019-11\\13-三级缓存防闪烁\\12-三级缓存防闪烁\\Debug\\12-三级缓存防闪烁.exe"), NULL, NULL, NULL, false, NULL, NULL, NULL, &startInfo, &processInfo);
#if 1
	if (is) {
		cout << TEXT("创建进程成功!") << endl;
		cout << "进程id:" << processInfo.dwProcessId << endl;
		cout << "线程id:" << processInfo.dwThreadId << endl;
		cout << "进程句柄:" << processInfo.hProcess << endl;
		cout << "线程句柄:" << processInfo.hThread << endl;
		TerminateProcess(processInfo.hProcess, -2);
		HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, processInfo.dwProcessId);
		if (INVALID_HANDLE_VALUE == hProcess) {
			printf("failure!");
		}
		else {
			printf("open successfully\n");
			cout << "process handle :" << hProcess << endl;
			cout << "process id:" << GetProcessId(hProcess) << endl;
		}
	}
	else {
		cout << TEXT("创建进程失败!") << endl;
	}
#endif
	return 0;
}

执行结果:进程被正确的打开,正确的关闭,然后又诡异的打开,所谓诡异的打开,就是说,命令行窗口显示进程打开成功了,并且id号相同,句柄不同(正常,因为id是不变的,句柄是实施动态变化的)。但是你看不到进程被打开了。

5.EnumProcess:

枚举系统中所有进程的id,并存入到一个数组中

BOOL EnumProcesses(
  DWORD   *lpidProcess,
  DWORD   cb,
  LPDWORD lpcbNeeded
);

例如:

#include <psapi.h>
#pragma comment(lib,"Psapi.lib")
DWORD processArray[1024] = { 0 };
EnumProcesses(processArray, 1024, NULL);

 

0x01 线程:

1.进程和线程区别:

进程是操作系统分配资源的基本单位。

线程是操作系统调度的基本单位。

一个进程至少拥有一个线程(main函数是进程的主线程),可以拥有多个线程(同一个进程的所有线程共用进程的资源,包括文件、内存)。

线程被创建后,自动开始运行,结束后不需要释放进程资源,只需释放线程本身资源

2.线程使用

2.1线程的创建

HANDLE CreateThread(//返回线程的句柄
    _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,//线程的属性,NULL表示默认属性
    _In_ SIZE_T dwStackSize,//线程栈的大小
    _In_ LPTHREAD_START_ROUTINE lpStartAddress,//线程代码的起始地址,即函数名
    _In_opt_ __drv_aliasesMem LPVOID lpParameter,//线程的参数
    _In_ DWORD dwCreationFlags,//创建方式
    _Out_opt_ LPDWORD lpThreadId//线程的id
    );

创建三个线程,分别打印不同的值

#include "pch.h"
#include <iostream>
#include <Windows.h>

using namespace std;
void f1() {
	int n = 0;
	while (1) {
		cout << "我是主线程:"<<n++ << endl;
		Sleep(1000);
	}
}

void f2() {
	int n = 0;
	while (1) {
		cout << "我是线程f2:" << n++ << endl;
		Sleep(1000);
	}
}
void f3() {
	int n = 0;
	while (1) {
		cout << "我是线程f3:" << n++ << endl;
		Sleep(1000);
	}
}
int main()
{
	CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)f2, NULL, NULL, NULL);
	CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)f3, NULL, NULL, NULL);
	f1();
	return 0;
}

注意:当f1执行结束后,就会执行return 0,进程结束,即便是f2,f3还没有返回(执行结束),也会被强制结束。

解决方法:

int main()
{
	CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)f2, NULL, NULL, NULL);
	CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)f3, NULL, NULL, NULL);
	f1();
        WaitForSingleObject(h1,INFINITE);//该函数一定要等到h1结束才会返回(阻塞函数)
	return 0;
}

 

2.2线程参数:

注意类型转化

#include "pch.h"
#include <Windows.h>
#include <cstdio>
#include <iostream>
using namespace std;
DWORD WINAPI func(LPVOID lpThreadParameter) {
	int n = *((int*)lpThreadParameter);
        //int n = (int)lpThreadParameter;
	cout << n << endl;
	return 0;
}
int main()
{
	int m = 1024;
	CreateThread(NULL, NULL, func, &m, NULL, NULL);
//      CreateThread(NULL,NULL,func,(LPVOID)m,NULL,NULL);
	while (1);
	return 0;
}

传递字符串参数举例:

#include "pch.h"
#include <Windows.h>
#include <cstdio>
#include <iostream>
using namespace std;
DWORD WINAPI func(LPVOID lpThreadParameter) {
	
	cout <<(char*)lpThreadParameter<< endl;
	return 0;
}
int main()
{
	char m[1024] = "xidian university";
	CreateThread(NULL, NULL, func,(LPVOID)m, NULL, NULL);
	while (1);
	return 0;
}

2.3线程的控制:

线程内:ExitThread 退出当前线程

线程外:TerminateThread 结束某个线程

作业:

写一个程序去关闭QQ,别人只要运行这个程序就关闭QQ

写一个程序去循环打开记事本,别人只要运行这个程序,就循环打开十几个记事本。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值