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

本文介绍了如何正确重启Windows资源管理器,指出使用TerminateProcess和结束代码1的传统方法并非最佳实践,推荐通过修改注册表中的AutoRestartShell值来临时禁用自动重启功能,然后在结束后恢复设置。
摘要由CSDN通过智能技术生成

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

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

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

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

系列文章:

在注册表中,有一个叫 “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.

  • 9
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

涟幽516

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值