Windows RestartManeger重启管理器
介绍
重启管理器API可以消除或是减少在完成安装或是更新的过程中系统需要重启的次数。软件安装或是更新过程之所以需要重启系统的原因在于一些需要更新的文件正在被运行中的程序或服务使用。而重启管理器可以关闭或重启除了关键系统服务之外的所有程序和服务。
重启管理器DLL导出了一些可以被标准或是自定义的安装包加载的公共C接口。安装程序可以使用重启管理器注册在安装或是更新过程中将被替换的文件,查看是否有程序或服务正在使用该文件,从而找到正在被使用以至于无法对其更新的文件。重启管理器可以关闭和重启那些正在使用待更新文件的非关键进程和服务。安装程序可以利用正在被使用的文件名、进程ID(PID)、windows服务的短名(short-name),以关闭和重启对应的应用程序和服务。
重启管理器为桌面应用程序开发而提供。使用windows installer version 4.0的安装程序自动使用重启管理器以减少系统重启次数。
重启管理器API从windows vista和windows Server 2008开始提供。所有API由一个单独的DLL提供。
关键系统服务
判断程序是否是关键系统服务:
关键系统服务无法通过重启管理器在不重启系统的情况下关闭和重启,更新任何被这些服务使用的文件需要系统重启。
确定一个进程是否为关键系统服务:
- 使用函数RmRegisterResources注册该进程;
- 调用函数RmGetList 获取结构体RM_PROCESS_INFO;
- 返回的RM_PROCESS_INFO结构体中的成员ApplicationType包含了一个RM_APP_TYPE枚举值。如果这个值被设置为RmCriticial即表示该进程为关键系统进程。
关键系统服务包括smss.exe、csrss.exe、wininit.exe、logonui.exe、lsass.exe、services.exe、winlogon.exe、System、启动RPCSS的svchost.exe、启动Dcom/PnP的svchost.exe等。
重启管理器API使用
重启管理器提供了一系列的API以供开发人员使用。
下面尝试简单使用重启管理器关闭占用文件C:\\Windows\\SysWOW64\\gpapi.dll
的进程,根据我在windows 10上的测试,使用RmGetList
时需要指定nProcInfo
参数值,也就是需要填写的RM_PROCESS_INFO
结构体数量。看API资料时msdn又没说清楚,花了我好久时间,又是修改测试,又是debug,网上的一些代码也不对,++。关于nProcInfo
,可以通过传入NULL值执行RmGetList,执行结束后nProcInfoNeeded
参数值即为需要的结构体大小,此时的函数返回值为ERROR_MORE_DATA(0xEA),具体见MSDN。
/*
使用重启管理器关闭指定资源的相关进程
*/
#include "windows.h"
#include "stdio.h"
#include "restartmanager.h"
#pragma comment(lib, "Rstrtmgr.lib")
LPCSTR getAppType(INT type) {
if (1000 == type)
return "RmCritical";
LPCSTR appTypeArr[] = { "RmUnknownApp","RmMainWindow","RmOtherWindow","RmService","RmExplorer","RmConsole" };
return appTypeArr[type];
}
LPCSTR getAppStatus(INT status) {
LPCSTR appStatusArr[] = { "RmStatusUnknown", "RmStatusRunning", "RmStatusStopped", "RmStatusStoppedOther",
"RmStatusRestarted", "RmStatusErrorOnStop", "RmStatusErrorOnRestart", "RmStatusShutdownMasked",
"RmStatusRestartMasked" };
int idx = 0;
while (status) {
status >>= 1;
idx++;
}
return appStatusArr[idx];
}
void printRgAffectedAppsList(INT nProcInfo, RM_PROCESS_INFO *rgAffectedApps) {
printf("%8s%35s%35s%20s%30s%15s%15s\n",
"PID", "AppName", "ServiceShortName", "ApplicationType",
"AppStatus", "TSSessionID", "RestartAble");
// PID AppName ServiceName ApplicationType AppStatus TSSessionID RestartAble
for (int i = 0; i < nProcInfo; i++) {
printf("%8d", rgAffectedApps[i].Process.dwProcessId); // pid
printf("%35ws", rgAffectedApps[i].strAppName); // appname
printf("%35ws", rgAffectedApps[i].strServiceShortName); // ServiceName
printf("%20s", getAppType(rgAffectedApps[i].ApplicationType)); // ApplicationType
printf("%30s", getAppStatus(rgAffectedApps[i].AppStatus)); // AppStatus
printf("%15d", rgAffectedApps[i].TSSessionId);
printf("%15s\n", rgAffectedApps[i].bRestartable ? "True" : "False");
}
}
int main() {
DWORD ret = -1, RMSessionHandle = -1;
WCHAR pSessionKey[CCH_RM_SESSION_KEY + 2];
UINT nFiles = 1, nApplications = 0, nServices = 0;
LPCWSTR rgsFilenames[] = { L"C:\\Windows\\SysWOW64\\gpapi.dll" }; // 注册的文件资源
PRM_UNIQUE_PROCESS rgsApplications = NULL;
LPCWSTR *rgsServiceNames = NULL;
UINT nProcInfoNeeded = 0, nProcInfo = 0;
PRM_PROCESS_INFO rgAffectedApps = NULL; // 接收正在使用注册资源的进程或服务列表,
// 分配空间过小会报错ERROR_MORE_DATA,可根据nProcInfoNeeded申请内存
//RM_PROCESS_INFO rgAffectedApps[30];
DWORD dwRebootReasons = -1; // 接收一个枚举值,表示是否需要系统重启,以及重启的理由
// 启动一个新的重启管理器会话,每个用户只能同时开启64个重启管理器会话
if (!(ret = RmStartSession(&RMSessionHandle, 0, pSessionKey))) {
printf("[SUCCESS] 启动重启管理器会话成功...\n");
if (!(ret = RmRegisterResources(RMSessionHandle,
nFiles, rgsFilenames,
nApplications, rgsApplications,
nServices, rgsServiceNames))) {
printf("[SUCCESS] 注册资源成功...\n");
ret = RmGetList(RMSessionHandle, &nProcInfoNeeded, &nProcInfo, rgAffectedApps, &dwRebootReasons);
if (ERROR_MORE_DATA == ret) {
ret = -1;
printf("\t需要结构体 RM_PROCESS_INFO %d 个...\n", nProcInfoNeeded);
rgAffectedApps = new RM_PROCESS_INFO[nProcInfoNeeded + 1];
nProcInfo = nProcInfoNeeded; // 重点,这里需要注意一下,要指定接收的结构体数量
memset(rgAffectedApps, 0, sizeof(rgAffectedApps));
if (!(ret = RmGetList(RMSessionHandle,
&nProcInfoNeeded, &nProcInfo,
rgAffectedApps, &dwRebootReasons))) {
printf("[SUCCESS] 获取受影响进程(服务)列表成功...\n\t列表如下:\n");
printRgAffectedAppsList(nProcInfo, rgAffectedApps);
ret = -1;
if (!(ret = RmShutdown(RMSessionHandle, 0, NULL))) {
printf("[SUCCESS] 调用RmShutDown关闭占用注册资源的进程(服务)成功...\n");
}
else
printf("[FAILED] RmShutDown调用失败 %d!!!\n", ret);
}
else
printf("[FAILED] 获取受影响进程(服务)列表失败 %d!!!\n", ret);
free(rgAffectedApps);
rgAffectedApps = NULL;
}
}
else
printf("[FAILED] 注册资源失败 %d!!!\n", ret);
RmEndSession(RMSessionHandle);
}
else
printf("[FAILED] 启动重启管理器会话失败 %d!!!\n", ret);
return 0;
}
MoveFileEx
但是如果在安装或是更新的时候,重启管理器无法关闭或是重启服务(进程),必须要系统重启,这个时候可以使用MoveFileEx API,相比于API MoveFile,多了一个参数dwFlag
。
使用MOVEFILE_DELAY_UNTIL_REBOOT
参数,可以在系统重启时将文件进行替换,此时无任何进程占用目标。
原理是通过在注册表键值HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\ Control\Session Manager\PendingFileRenameOperations
下创建一定格式的字符串,以指定文件是被删除还是替换。
有两种形式:
- szDstFile\0\0
- szSrcFile\0szDstFile\0
其中的\0\0表示两个0值"00 00",前者表示文件删除操作(可认为是重命名为NULL);后者则是文件替换操作,如果MoveFileEx还指定了MOVEFILE_REPLACE_EXISTING
标志,在目标文件前还会加上一个感叹号前缀('!')。
参考:
https://docs.microsoft.com/en-us/windows/win32/api/_rstmgr/
Windows RestartManeger重启管理器的更多相关文章
- Windows 程序包管理器 Chocolatey:一条命令装软件
Windows 程序包管理器 Chocolatey:一条命令装软件 本文原始地址:https://sitoi.cn/posts/46278.html 介绍 Chocolatey 是一种软件管理解决方案 ...
- Windows Restart Manager 重启管理器
Restart Manager(以下简称RM)可以减少或避免安装或更新程序所需要的系统重启次数.安装(或更新)过程中需要重启的主要原因是需要更新的某些文件当前正被一些其它程序或服务所使用.RM允许除关 ...
- 【Windows】Windows Restart Manager 重启管理器
Restart Manager(以下简称RM)可以减少或避免安装或更新程序所需要的系统重启次数.安装(或更新)过程中需要重启的主要原因是需要更新的某些文件当前正被一些其它程序或服务所使用.RM允许除关 ...
- 使用 Windows 包管理器 (winget) 安装 .Net
用户可以在 Windows 10 和 Windows 11 计算机上使用 winget 命令行工具来发现.安装.升级.删除和配置应用程序. 此工具是 Windows 程序包管理器服务的客户端接口. 以 ...
- AHKManager.ahk AHK管理器 2019年12月15日
AHKManager.ahk AHK管理器 2019年12月15日 快捷键 {Alt} + {F1} ///////////////////////////////////////////// ...
- Windows Azure Web Site (11) 使用源代码管理器管理Azure Web Site
<Windows Azure Platform 系列文章目录> 熟悉Azure Web Site平台的读者都知道,我们可以通过FTP等方式,把本地的Web Application部署到微软 ...
- Windows下安装Cygwin及包管理器apt-cyg(转)
本文为转载文章: http://www.2cto.com/os/201212/176551.html Cygwin可以在Windows下使用unix环境Bash和各种功能强大的工具,对于Linux管理 ...
- Chocolatey:Windows软件包管理器
Chocolatey 2016-08-03 https://chocolatey.org/ Chocolatey是一个Windows软件包管理器,就像Nuget或者npm,或者说类似Linux上的ap ...
- Windows Server 2012 R2 服务器管理器介绍和配置使用
1. 服务管理器是用于管理系统服务的管理工具.一般常用于windows系统,使用这个工具你可以启动.停止服务:设置服务是自动.手动启动或禁用:查看某个服务的相关信息:设置服务以什么用户启动等等(一般包 ...
随机推荐
- HttpRunner3的HTTP请求是怎么发出去的
在HttpRunner3的示例代码中,发送HTTP请求的代码是这样写的: from httprunner import HttpRunner, Config, Step, RunRequest, Ru ...
- 如何让 Hexo 在服务器稳定运行
声明 本文地址:如何让 Hexo 在服务器稳定运行 背景 博客系统终于又搭建起来了(好一个又),但是每隔一段时间去访问自己的网站总是访问不到,去服务器查询 ps aux | grep hexo,发现 ...
- 性能优化-使用双buffer实现无锁队列
借助本文,实现一种在"读多写一"场景下的无锁实现方式 在我们的工作中,多线程编程是一件太稀松平常的事.在多线程环境下操作一个变量或者一块缓存,如果不对其操作加以限制,轻则变量值或者 ...
- 【笔记】golang中使用protocol buffers的底层库直接解码二进制数据
背景 一个简单的代理程序,发现单核QPS达到2万/s左右就上不去了,40%的CPU消耗在pb的decode/encode上面. 于是我想,对于特定的场景,直接从[]byte中取出字段,而不用完全的把整 ...
- 使用3D Tiles Overview学习3D Tiles
Cesium中文网:http://cesiumcn.org/ | 国内快速访问:http://cesium.coinidea.com/ 3D Tiles的创建是为了在web上传输大量的3D数据集.作为 ...
- 一文读懂HarmonyOS服务卡片怎么换肤
作者:zhenyu,华为软件开发工程师 关注HarmonyOS的小伙伴肯定对服务卡片已经很熟悉了.服务卡片(也简称为"卡片")是FA(FeatureAbility,元服务)的一种界 ...
- 推荐召回--基于内容的召回:Content Based
目录 1. 前言 2. 构建画像 3. 内容召回的算法 1. 前言 在之前总结过协同过滤的召回通路后,今天我们来总结下召回策略中的重头戏:基于内容的召回通路,也即我们常说的基于标签的召回.这里就要涉及 ...
- Java方法内联
一.概念 方法内联就是把调用方函数代码"复制"到调用方函数中,减少因函数调用开销的技术 函数调用过程 1.首先会有个执行栈,存储它们的局部变量.方法名.动态连接 2.当一个方法 ...
- Mysql自序整理集
1.事务 mysql事务是用于处理操作量大.复杂性高的数据 1. 事务特性 原子性:保证每个事务所有操作要么全部完成或全部不完成,不可能停滞在中间环节:如事务在执行过程中出现错误,则会回滚到事务开始之 ...
- Vue2和Vue3技术整理3 - 高级篇
3.高级篇 前言 基础篇链接:https://www.cnblogs.com/xiegongzi/p/15782921.html 组件化开发篇链接:https://www.cnblogs.com/xi ...