重启 explorer 进程的正确做法(二)

重启资源管理器进程的方法不唯一,但长期以来大家对实施方法用的不到位。

在上一篇中我认为:“我们往往使用 TerminateProcess 并传入 PID 和特殊结束代码 1 或者 taskkill /f /im 等方法重启资源管理器( explorer.exe ),其实这是不正确的。我们应该使用重启管理器接口来重启 explorer 进程。”

其实,并不能一口咬定以前的方法不正确。我们应该想想为什么 TerminateProcess 似乎必须传入结束代码 1 ,才能不让资源管理器自动重新启动?

要知其然,更要知其所以然。

系列文章:

  • 1.Windows 重启 explorer 的正确做法-CSDN博客
  • 2.重启 explorer 进程的正确做法(二)

在注册表中,有一个叫 “AutoRetartShell” 的注册表值项,该值是 BOOL 类型。当值为 1 时,资源管理器会在结束时通知 Winlogon 并由 Winlogon 自动重新启动 explorer。反之,当该值为 0 时,则不会自动重新启动。

在修改注册表之前,资源管理器在退出时会被自动重启,只有指定特殊的退出状态,才能阻止自动重启。而在修改好注册表后,就不会触发自动重启了。所以,我们正确的做法不是去研究应该用什么进程退出状态码,而是通过临时修改注册表中的关键设置,来屏蔽自动重启功能。

所以,我们正确的做法是,在调用 TerminateProcess 之前,修改注册表 “AutoRetartShell” 的值为 0 ,然后再在结束进程后恢复值为 1 即可。(通常需要管理员权限)

使用下面的代码修改注册表:

/**
 * @brief 结束 explorer 进程之前,需要首先检查注册表配置
 *
 * @param[in]       
 *
 * @return	TRUE	操作成功完成;
 *			FALSE	操作失败
 * @note
 */
BOOL SetRegistryValue(LPCWSTR lpSubKey, LPCWSTR lpValueName, DWORD dwData)
{
    HKEY hKey = NULL;
    DWORD dwDisposition = 0;
    //DWORD dwData = bEnable ? 3 : 0; // 默认值为 3,bEnable 作为开关变量

    // 尝试打开或创建注册表键
    LONG lResult = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
        lpSubKey, // L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System"
        0,
        NULL,
        REG_OPTION_NON_VOLATILE,
        KEY_READ | KEY_WRITE,
        NULL,
        &hKey,
        &dwDisposition);

    if (lResult == ERROR_SUCCESS) {
        DWORD dwType = 0;
        DWORD dwValue = 0;
        DWORD dwSize = sizeof(DWORD);

        // 检查值是否存在
        lResult = RegQueryValueExW(hKey, lpValueName,
            NULL, &dwType, (LPBYTE)&dwValue, &dwSize);

        if (lResult == ERROR_SUCCESS) {
            if (dwType == REG_DWORD && dwValue == dwData) {
                // 值已存在且为 dwData,无需更新
                RegCloseKey(hKey);
                return TRUE;
            }
            else {
                // 值存在但不为 dwData,更新值为 dwData
                lResult = RegSetValueExW(hKey, lpValueName,  // L"SoftwareSASGeneration"
                    0, REG_DWORD, (BYTE*)&dwData, sizeof(DWORD));
                RegCloseKey(hKey);
                return (lResult == ERROR_SUCCESS);
            }
        }
        else if (lResult == ERROR_FILE_NOT_FOUND) {
            // 值不存在,创建并设置为 dwData
            lResult = RegSetValueExW(hKey, lpValueName,
                0, REG_DWORD, (BYTE*)&dwData, sizeof(DWORD));
            RegCloseKey(hKey);
            return (lResult == ERROR_SUCCESS);
        }
        else {
            // 其他错误
            RegCloseKey(hKey);
            return FALSE;
        }
    }
    else {
        // 打开或创建键失败
        return FALSE;
    }
}

调用方法如下所示:

if (SetRegistryValue(L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
    L"AutoRestartShell", 0)) {
    DWORD dwStatus = 0;
    if (!TerminateProcess(......))
    {
        bResponse = dwStatus;  // 如果调用失败,返回非零错误码
    }
    ::SetRegistryValue(L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
         L"AutoRestartShell", 1);
}else {    // 设置注册表失败
    
    bResponse = 50037;
    LogEvent(50037, TEXT("Failed to update LogonType value.\n"));
}

使用 TerminateProcess 结束当前会话的 explorer 进程的代码如下:

#include <Windows.h>
#include <iostream>
#include <WtsApi32.h>

#pragma comment(lib, "Wtsapi32.lib")

int main()
{
	PWTS_PROCESS_INFOW process_info;
	DWORD process_num = 0;

	DWORD current_session_id = 0;
	ProcessIdToSessionId(GetCurrentProcessId(), &current_session_id);

	if (!WTSEnumerateProcesses(WTS_CURRENT_SERVER_HANDLE,
		0, 1, &process_info, &process_num))
	{
		WTSFreeMemory(process_info);
		return false;
	}

	DWORD pid = 0;
	for (UINT i = 0; i < process_num; i++)
	{
		if (current_session_id == process_info[i].SessionId && 
			wcscmp(process_info[i].pProcessName, L"explorer.exe") == 0)
		{
			pid = process_info[i].ProcessId;
			break;
		}
	}
	WTSFreeMemory(process_info);

	if (pid != 0)
	{
		HANDLE hProcessHandle = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
		if (TerminateProcess(hProcessHandle, 1))  // 修改注册表后,则不需要该值为 1 
		{
			CloseHandle(hProcessHandle);
			return 0;
		}
	}
	return 1;
}

发布于:2024.03.10.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/447010.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

神经网络实战前言

应用广泛 从人脸识别到网约车&#xff0c;在生活中无处不在 未来可期 无人驾驶技术便利出行医疗健康改善民生 产业革命 第四次工业革命——人工智能 机器学习概念 机器学习不等价与人工智能20世纪50年代&#xff0c;人工智能是说机器模仿人类行为的能力 符号人工智能 …

DevOps本地搭建笔记(个人开发适用)

需求和背景 win11 wsl2 armbian(玩客云矿渣&#xff09;&#xff0c;构建个人cicd流水线&#xff0c;提高迭代效率。 具体步骤 基础设施准备 硬件准备&#xff1a;一台笔记本&#xff0c;用于开发和构建部署&#xff0c;一台服务器&#xff0c;用于日常服务运行。 笔记本…

C#,蛇梯问题(Snake and Ladder Problem)的算法与源代码

1 蛇梯问题 Snake and Ladder Problem 给定一个蛇梯板&#xff0c;找出从源单元格或第一个单元格到达目标单元格或最后一个单元格所需的最小掷骰次数。基本上&#xff0c;玩家可以完全控制掷骰子的结果&#xff0c;并希望找出到达最后一个单元格所需的最小掷骰次数。 如果玩…

【大厂AI课学习笔记NO.76】人工智能人才金字塔

人工智能领域&#xff0c;分为源头创新人才、产业研发人才、应用开发人才和实用技能人才。 人工智能领域的人才结构呈现多样化特点&#xff0c;主要可以分为源头创新人才、产业研发人才、应用开发人才和实用技能人才四大类。这四大类人才在人工智能领域的发展中各自扮演着不可或…

Day30:安全开发-JS应用NodeJS指南原型链污染Express框架功能实现审计

目录 环境搭建-NodeJS-解析安装&库安装 功能实现-NodeJS-数据库&文件&执行 安全问题-NodeJS-注入&RCE&原型链 案例分析-NodeJS-CTF题目&源码审计 开发指南-NodeJS-安全SecGuide项目 思维导图 JS知识点&#xff1a; 功能&#xff1a;登录验证&…

常见排序算法(C/C++)--- 动画演示

本篇将介绍一些常见的排序算法&#xff0c;如插入排序&#xff1a;直接插入排序、希尔排序&#xff1b;选择排序&#xff1a;选择排序、堆排序&#xff1b;交换排序&#xff1a;快速排序、冒泡排序&#xff1b;以及最后的归并排序。 对于以上的排序算法&#xff0c;我们总结了每…

VScode的列选

可以用来优化代码排布&#xff0c;让变量整齐成为一排 一、批量复制&#xff1a; 在1处左键单击&#xff0c;然后摁住SHIFTALT键的同时&#xff0c;左键单击2处&#xff0c;即可复制一整块的内容 如果所示 就可以复制了 二、批量输入 在1处左键单击&#xff0c;然后摁住SHI…

Day32:安全开发-JavaEE应用Servlet路由技术JDBCMybatis数据库生命周期

目录 JavaEE-HTTP-Servlet&路由&周期 JavaEE-数据库-JDBC&Mybatis&库 思维导图 Java知识点&#xff1a; 功能&#xff1a;数据库操作&#xff0c;文件操作&#xff0c;序列化数据&#xff0c;身份验证&#xff0c;框架开发&#xff0c;第三方库使用等. 框架…

RabbitMQ - 04 - Fanout交换机 (广播)

目录 部署demo项目 什么是Fanout交换机 实现Fanout交换机 1.控制台 声明队列 声明交换机 将交换机与队列绑定 2.编写消费者方法 3.编写生产者测试方法 部署demo项目 通过消息队列demo项目进行练习 相关配置看此贴 http://t.csdnimg.cn/hPk2T 注意 生产者消费者的…

转移表回调函数实现

回调函数实现 计算器的模拟&#xff08;函数指针数组的使用&#xff09;&#xff08;回调函数&#xff09; 简化 冗余 老的代码的问题就是 冗余 写死 不能完成不同的任务 函数调用的时候只需要知道地址就可以 calc计算器 这里也称之为转移表 #define _CRT_SECURE_NO_WAR…

微信小程序开发系列(二十五)·wxml语法·条件渲染wx:if, wx:elif, wx:else 属性组以及hidden 属性的使用

目录 1. 使用 wx:if、wx:elif、wx:else 属性组 2. 使用 hidden 属性 条件渲染主要用来控制页面结构的展示和隐藏,在微信小程序中实现条件渲染有两种方式: 1. 使用 wx:if, wx:elif, wx:else 属性组 2. 使用 hidden 属性 wx:if 和 hidden 二者的区别&#xff1a; 1. wx…

计算机网络-第4章 网络层(2)

主要内容&#xff1a;网络层提供的两种服务&#xff1a;虚电路和数据报&#xff08;前者不用&#xff09;、ip协议、网际控制报文协议ICMP、路由选择协议&#xff08;内部网关和外部网关&#xff09;、IPv6,IP多播&#xff0c;虚拟专用网、网络地址转换NAT&#xff0c;多协议标…

背包问题算法

背包问题算法 0-1背包问题二维数组一维数组 完全背包问题二维数组一维数组 多重背包问题一维数组 0-1背包问题 问题&#xff1a;背包的容量为9&#xff0c;有重量分别为[2, 4, 6, 9]的四个物品&#xff0c;价值分别为[3, 4, 5, 6]&#xff0c;求背包能装的物品的最大价值是多少…

构建LVS集群

一、集群的基本理论&#xff08;一&#xff09;什么是集群 人群或事物聚集&#xff1a;在日常用语中&#xff0c;群集指的是一大群人或事物密集地聚在一起。例如&#xff0c;“人们群集在广场上”&#xff0c;这里的“群集”是指大量人群聚集的现象。 计算机技术中的集群&…

C语言连接【MySQL】

稍等更新图片。。。。 文章目录 安装 MySQL 库连接 MySQLMYSQL 类创建 MySQL 对象连接数据库关闭数据库连接示例 发送命令设置编码格式插入、删除或修改记录查询记录示例 参考资料 安装 MySQL 库 在 CentOS7 下&#xff0c;使用命令安装 MySQL&#xff1a; yum install mysq…

arcgis栅格数据处理3——定义投影(同样适用于其他类型文件)

进行数据连接时可能出现未设置投影无法链接的情况&#xff0c;需要先定义投影 点击最右侧“目录”&#xff0c;弹出带有系统工具的面板&#xff0c;点击“data management tools”点击“投影”&#xff0c;“定义投影”

【轮式平衡机器人】——TMS320F28069片内外设之eCAP

引入 TMS320F28069的eCAP&#xff08;增强型捕获模块&#xff09;是一个强大的外设&#xff0c;用于精确测量和捕获输入信号的事件和时间戳。 在电机控制、传感器数据采集和信号处理等应用中&#xff0c;eCAP模块可以用于测量霍尔传感器、编码器或其他数字输入信号的周期、频…

计算表达式x*(2^i)的值math.ldexp(x, i)

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 计算表达式x*(2^i)的值 math.ldexp(x, i) [太阳]选择题 关于以下代码输出的结果说法正确的是&#xff1f; import math print("【执行】math.ldexp(3,2)") print(math.ldexp(3,2)) …

2024/3/10总结:数据结构教程:顺序表的创建以及基本的12个操作

首先&#xff0c;按照惯例&#xff0c;欢迎大家边听歌边看本博客&#xff01;&#xff01;&#xff01; 这里是神奇的赛尔号_张杰 (kugou.com) 一.背景&#xff1a;由于是上机实验&#xff0c;直接引用数据结构教程第6版73页的实验题1 修改第6&#xff0c;7&#xff0c;8&am…

CI/CD笔记.Gitlab系列:控制台强制修改root用户密码

CI/CD笔记.Gitlab系列 控制台强制修改root用户密码 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:https://blog.cs…