You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中如何调用Win API的RestartManager?是否有.NET封装?

在C#中使用RestartManager检查文件占用状态

1. .NET 内置封装情况

目前.NET框架(包括.NET Core/.NET 5+)并没有直接封装RestartManager的完整API,需要通过P/Invoke调用原生Windows API来实现功能。

2. C#中高效使用RestartManager的实现方式

你可以通过P/Invoke封装RestartManager的核心函数,完成目录下文件占用状态的检查,核心步骤包括启动会话、注册目标目录、获取占用进程列表、结束会话。以下是核心实现代码:

using System;
using System.Runtime.InteropServices;

public static class RestartManagerHelper
{
    [DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)]
    private static extern int RmStartSession(out uint pSessionHandle, int dwSessionFlags, string strSessionKey);

    [DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)]
    private static extern int RmRegisterResources(uint sessionHandle, uint nFiles, string[] rgsFilenames, uint nApplications, [In] RM_UNIQUE_PROCESS[] rgApplications, uint nServices, string[] rgsServiceNames);

    [DllImport("rstrtmgr.dll")]
    private static extern int RmGetList(uint sessionHandle, out uint pnProcInfoNeeded, ref uint pnProcInfo, [Out] RM_PROCESS_INFO[] rgAffectedApps, ref uint lpdwRebootReasons);

    [DllImport("rstrtmgr.dll")]
    private static extern int RmEndSession(uint sessionHandle);

    [StructLayout(LayoutKind.Sequential)]
    private struct RM_UNIQUE_PROCESS
    {
        public uint dwProcessId;
        public System.Runtime.InteropServices.ComTypes.FILETIME ProcessStartTime;
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    private struct RM_PROCESS_INFO
    {
        public RM_UNIQUE_PROCESS Process;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
        public string strAppName;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)]
        public string strServiceShortName;
        public RM_APP_TYPE ApplicationType;
        public uint AppStatus;
        public uint TSSessionId;
        [MarshalAs(UnmanagedType.Bool)]
        public bool bRestartable;
    }

    private enum RM_APP_TYPE
    {
        RmUnknownApp = 0,
        RmMainWindow = 1,
        RmOtherWindow = 2,
        RmService = 3,
        RmExplorer = 4,
        RmConsole = 5,
        RmCritical = 1000
    }

    public static bool IsDirectoryInUse(string directoryPath)
    {
        uint sessionHandle = 0;
        string sessionKey = Guid.NewGuid().ToString();
        int result = RmStartSession(out sessionHandle, 0, sessionKey);
        if (result != 0)
            throw new System.ComponentModel.Win32Exception(result);

        try
        {
            string[] resources = new string[] { directoryPath };
            result = RmRegisterResources(sessionHandle, (uint)resources.Length, resources, 0, null, 0, null);
            if (result != 0)
                throw new System.ComponentModel.Win32Exception(result);

            uint procInfoNeeded = 0;
            uint procInfo = 0;
            uint rebootReasons = 0;
            result = RmGetList(sessionHandle, out procInfoNeeded, ref procInfo, null, ref rebootReasons);
            if (result != 0 && result != 234) // 234表示需要分配更大缓冲区
                throw new System.ComponentModel.Win32Exception(result);

            if (procInfoNeeded == 0)
                return false;

            RM_PROCESS_INFO[] processInfo = new RM_PROCESS_INFO[procInfoNeeded];
            procInfo = procInfoNeeded;
            result = RmGetList(sessionHandle, out procInfoNeeded, ref procInfo, processInfo, ref rebootReasons);
            if (result != 0)
                throw new System.ComponentModel.Win32Exception(result);

            return procInfo > 0;
        }
        finally
        {
            RmEndSession(sessionHandle);
        }
    }
}

3. 删除前检查文件可删除性的补充说明

  • 仅通过File.GetAccessControl这类权限检查无法完全判断文件是否可删除,因为文件可能被进程占用、处于锁定状态,或存在其他系统级限制。
  • RestartManager是Windows原生的可靠方案,能准确识别占用文件的进程,效率优于遍历文件逐一检查的方式。
  • 另一种替代方案是尝试获取文件的排他锁:若能成功获取则文件未被占用,若抛出IOException则表示文件被占用,但这种方式无法获取具体占用进程,且需要遍历目录下所有文件,效率较低。

内容的提问来源于stack exchange,提问作者Tripp Sautner

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 22:25:14