Пример #1
0
        public static IEnumerable <ProcessInfo> GetLockingProcessInfos(params string[] paths)
        {
            if (paths == null)
            {
                throw new ArgumentNullException("paths");
            }

            const int maxRetries = 6;

            // See http://blogs.msdn.com/b/oldnewthing/archive/2012/02/17/10268840.aspx.
            var key = new StringBuilder(new string('\0', NativeMethods.CCH_RM_SESSION_KEY + 1));

            uint handle;
            int  res = NativeMethods.RmStartSession(out handle, 0, key);

            if (res != 0)
            {
                throw GetException(res, "RmStartSession", "Failed to begin restart manager session.");
            }

            try
            {
                string[] resources = paths;
                res = NativeMethods.RmRegisterResources(handle, (uint)resources.Length, resources, 0, null, 0, null);
                if (res != 0)
                {
                    throw GetException(res, "RmRegisterResources", "Could not register resources.");
                }

                //
                // Obtain the list of affected applications/services.
                //
                // NOTE: Restart Manager returns the results into the buffer allocated by the caller. The first call to
                // RmGetList() will return the size of the buffer (i.e. nProcInfoNeeded) the caller needs to allocate.
                // The caller then needs to allocate the buffer (i.e. rgAffectedApps) and make another RmGetList()
                // call to ask Restart Manager to write the results into the buffer. However, since Restart Manager
                // refreshes the list every time RmGetList()is called, it is possible that the size returned by the first
                // RmGetList()call is not sufficient to hold the results discovered by the second RmGetList() call. Therefore,
                // it is recommended that the caller follows the following practice to handle this race condition:
                //
                //    Use a loop to call RmGetList() in case the buffer allocated according to the size returned in previous
                //    call is not enough.
                //
                uint pnProcInfo = 0;
                NativeMethods.RM_PROCESS_INFO[] rgAffectedApps = null;
                int retry = 0;
                do
                {
                    uint lpdwRebootReasons = (uint)NativeMethods.RM_REBOOT_REASON.RmRebootReasonNone;
                    uint pnProcInfoNeeded;
                    res = NativeMethods.RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, rgAffectedApps, ref lpdwRebootReasons);
                    if (res == 0)
                    {
                        // If pnProcInfo == 0, then there is simply no locking process (found), in this case rgAffectedApps is "null".
                        if (pnProcInfo == 0)
                        {
                            return(Enumerable.Empty <ProcessInfo>());
                        }

                        Debug.Assert(rgAffectedApps != null, "rgAffectedApps != null");
                        var lockInfos = new List <ProcessInfo>((int)pnProcInfo);
                        for (int i = 0; i < pnProcInfo; i++)
                        {
                            lockInfos.Add(ProcessInfoWindows.Create(rgAffectedApps[i]));
                        }
                        return(lockInfos);
                    }

                    if (res != NativeMethods.ERROR_MORE_DATA)
                    {
                        throw GetException(res, "RmGetList", string.Format("Failed to get entries (retry {0}).", retry));
                    }

                    pnProcInfo     = pnProcInfoNeeded;
                    rgAffectedApps = new NativeMethods.RM_PROCESS_INFO[pnProcInfo];
                } while ((res == NativeMethods.ERROR_MORE_DATA) && (retry++ < maxRetries));
            }
            finally
            {
                res = NativeMethods.RmEndSession(handle);
                if (res != 0)
                {
                    throw GetException(res, "RmEndSession", "Failed to end the restart manager session.");
                }
            }

            return(Enumerable.Empty <ProcessInfo>());
        }
Пример #2
0
        private static void GetLockingProcessInfo(string path, List <ProcessInfo> result)
        {
            if (path == null)
            {
                throw new ArgumentNullException(nameof(path));
            }

            var bufferPtr   = IntPtr.Zero;
            var statusBlock = new NativeMethods.IO_STATUS_BLOCK();

            try
            {
                using (var handle = NativeMethods.GetFileHandle(path))
                {
                    if (handle.IsInvalid)
                    {
                        // The file does not exist or is gone already. Could be a race condition. There is nothing we can contribute.
                        // Doing this, exhibits the same behavior as the RestartManager implementation.
                        return;
                    }

                    uint bufferSize = 0x4000;
                    bufferPtr = Marshal.AllocHGlobal((int)bufferSize);

                    uint status;
                    while ((status = NativeMethods.NtQueryInformationFile(handle,
                                                                          ref statusBlock, bufferPtr, bufferSize,
                                                                          NativeMethods.FILE_INFORMATION_CLASS.FileProcessIdsUsingFileInformation))
                           == NativeMethods.STATUS_INFO_LENGTH_MISMATCH)
                    {
                        Marshal.FreeHGlobal(bufferPtr);
                        bufferPtr   = IntPtr.Zero;
                        bufferSize *= 2;
                        bufferPtr   = Marshal.AllocHGlobal((int)bufferSize);
                    }

                    if (status != NativeMethods.STATUS_SUCCESS)
                    {
                        throw GetException(status, "NtQueryInformationFile", "Failed to get file process IDs");
                    }

                    // Buffer contains:
                    //    struct FILE_PROCESS_IDS_USING_FILE_INFORMATION
                    //    {
                    //        ULONG NumberOfProcessIdsInList;
                    //        ULONG_PTR ProcessIdList[1];
                    //    }

                    var readBuffer = bufferPtr;
                    int numEntries = Marshal.ReadInt32(readBuffer); // NumberOfProcessIdsInList
                    readBuffer += IntPtr.Size;

                    for (int i = 0; i < numEntries; i++)
                    {
                        int processId = Marshal.ReadIntPtr(readBuffer).ToInt32(); // A single ProcessIdList[] element
                        result.Add(ProcessInfoWindows.Create(processId));
                        readBuffer += IntPtr.Size;
                    }
                }
            }
            finally
            {
                if (bufferPtr != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(bufferPtr);
                }
            }
        }