< Summary - Results for net8.0, Release

Information
Class: LockCheck.Windows.RestartManager
Assembly: LockCheck
File(s): D:\a\LockCheck\LockCheck\src\LockCheck\Windows\RestartManager.cs
Tag: 117_11660770947
Line coverage
82%
Covered lines: 34
Uncovered lines: 7
Coverable lines: 41
Total lines: 114
Line coverage: 82.9%
Branch coverage
75%
Covered branches: 21
Total branches: 28
Branch coverage: 75%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
GetLockingProcessInfos(...)75%30.652885%
GetException(...)100%210%

File(s)

D:\a\LockCheck\LockCheck\src\LockCheck\Windows\RestartManager.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.ComponentModel;
 4using System.Diagnostics;
 5using System.Diagnostics.CodeAnalysis;
 6using System.IO;
 7using System.Linq;
 8using System.Text;
 9
 10namespace LockCheck.Windows;
 11
 12internal static class RestartManager
 13{
 14    public static HashSet<ProcessInfo> GetLockingProcessInfos(string[] paths,
 15#if NET
 16        [NotNullIfNotNull(nameof(directories))]
 17#endif
 18        ref List<string>? directories)
 19    {
 220        if (paths == null)
 221            throw new ArgumentNullException(nameof(paths));
 22
 23        const int maxRetries = 6;
 24
 25        // See http://blogs.msdn.com/b/oldnewthing/archive/2012/02/17/10268840.aspx.
 226        var key = new StringBuilder(new string('\0', NativeMethods.CCH_RM_SESSION_KEY + 1));
 27
 28        uint handle;
 229        int res = NativeMethods.RmStartSession(out handle, 0, key);
 230        if (res != 0)
 031            throw GetException(res, "Failed to begin restart manager session");
 32
 33        try
 34        {
 235            var files = new HashSet<string>(paths.Length, StringComparer.OrdinalIgnoreCase);
 236            foreach (string path in paths)
 37            {
 238                if (Directory.Exists(path))
 39                {
 240                    directories?.Add(path);
 41                }
 42                else
 43                {
 244                    files.Add(path);
 45                }
 46            }
 47
 248            res = NativeMethods.RmRegisterResources(handle, (uint)files.Count, files.ToArray(), 0, null, 0, null);
 249            if (res != 0)
 050                throw GetException(res, "Could not register resources");
 51
 52            //
 53            // Obtain the list of affected applications/services.
 54            //
 55            // NOTE: Restart Manager returns the results into the buffer allocated by the caller. The first call to
 56            // RmGetList() will return the size of the buffer (i.e. nProcInfoNeeded) the caller needs to allocate.
 57            // The caller then needs to allocate the buffer (i.e. rgAffectedApps) and make another RmGetList()
 58            // call to ask Restart Manager to write the results into the buffer. However, since Restart Manager
 59            // refreshes the list every time RmGetList()is called, it is possible that the size returned by the first
 60            // RmGetList()call is not sufficient to hold the results discovered by the second RmGetList() call. Therefor
 61            // it is recommended that the caller follows the following practice to handle this race condition:
 62            //
 63            //    Use a loop to call RmGetList() in case the buffer allocated according to the size returned in previous
 64            //    call is not enough.
 65            //
 266            uint pnProcInfo = 0;
 267            NativeMethods.RM_PROCESS_INFO[]? rgAffectedApps = null;
 268            int retry = 0;
 69            do
 70            {
 271                uint lpdwRebootReasons = (uint)NativeMethods.RM_REBOOT_REASON.RmRebootReasonNone;
 72                uint pnProcInfoNeeded;
 273                res = NativeMethods.RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, rgAffectedApps, ref lpdwRebo
 274                if (res == 0)
 75                {
 76                    // If pnProcInfo == 0, then there is simply no locking process (found), in this case rgAffectedApps 
 277                    if (pnProcInfo == 0)
 278                        return [];
 79
 80                    Debug.Assert(rgAffectedApps != null);
 281                    var lockInfos = new HashSet<ProcessInfo>((int)pnProcInfo);
 282                    for (int i = 0; i < pnProcInfo; i++)
 83                    {
 284                        var info = ProcessInfoWindows.Create(rgAffectedApps![i]);
 285                        if (info != null)
 86                        {
 287                            lockInfos.Add(info);
 88                        }
 89                    }
 290                    return lockInfos;
 91                }
 92
 293                if (res != NativeMethods.ERROR_MORE_DATA)
 094                    throw GetException(res, $"Failed to get entries (retry {retry})");
 95
 296                pnProcInfo = pnProcInfoNeeded;
 297                rgAffectedApps = new NativeMethods.RM_PROCESS_INFO[pnProcInfo];
 298            } while ((res == NativeMethods.ERROR_MORE_DATA) && (retry++ < maxRetries));
 099        }
 100        finally
 101        {
 2102            res = NativeMethods.RmEndSession(handle);
 2103            if (res != 0)
 0104                throw GetException(res, "Failed to end the restart manager session");
 2105        }
 106
 0107        return [];
 2108    }
 109
 110    internal static Win32Exception GetException(int res, string message)
 111    {
 0112        return new Win32Exception(res, $"{message}: {NativeMethods.GetMessage(res)}");
 113    }
 114}