I18NCommander/I18N Commander/Processor/GetBlockingProcesses.cs

135 lines
5.0 KiB
C#
Raw Permalink Normal View History

namespace Processor;
//
// Source: https://stackoverflow.com/a/20623311/2258393
//
using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Runtime.InteropServices;
public static class SystemUtil
{
[StructLayout(LayoutKind.Sequential)]
private struct RM_UNIQUE_PROCESS
{
public readonly int dwProcessId;
private readonly System.Runtime.InteropServices.ComTypes.FILETIME ProcessStartTime;
}
private const int RM_REBOOT_REASON_NONE = 0;
private const int CCH_RM_MAX_APP_NAME = 255;
private const int CCH_RM_MAX_SVC_NAME = 63;
private enum RM_APP_TYPE
{
RM_UNKNOWN_APP = 0,
RM_MAIN_WINDOW = 1,
RM_OTHER_WINDOW = 2,
RM_SERVICE = 3,
RM_EXPLORER = 4,
RM_CONSOLE = 5,
RM_CRITICAL = 1000
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct RM_PROCESS_INFO
{
public readonly RM_UNIQUE_PROCESS Process;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_APP_NAME + 1)]
private readonly string strAppName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_SVC_NAME + 1)]
private readonly string strServiceShortName;
private readonly RM_APP_TYPE ApplicationType;
private readonly uint AppStatus;
private readonly uint TSSessionId;
[MarshalAs(UnmanagedType.Bool)]
private readonly bool bRestartable;
}
[DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)]
static extern int RmRegisterResources(uint pSessionHandle, UInt32 nFiles, string[] rgsFilenames, UInt32 nApplications, [In] RM_UNIQUE_PROCESS[] rgApplications, UInt32 nServices, string[] rgsServiceNames);
[DllImport("rstrtmgr.dll", CharSet = CharSet.Auto)]
static extern int RmStartSession(out uint pSessionHandle, int dwSessionFlags, string strSessionKey);
[DllImport("rstrtmgr.dll")]
static extern int RmEndSession(uint pSessionHandle);
[DllImport("rstrtmgr.dll")]
static extern int RmGetList(uint dwSessionHandle, out uint pnProcInfoNeeded, ref uint pnProcInfo, [In, Out] RM_PROCESS_INFO[] rgAffectedApps, ref uint lpdwRebootReasons);
/// <summary>
/// Find out what process(es) have a lock on the specified file.
/// </summary>
/// <param name="path">Path of the file.</param>
/// <returns>Processes locking the file</returns>
/// <remarks>See also:
/// http://msdn.microsoft.com/en-us/library/windows/desktop/aa373661(v=vs.85).aspx
/// http://wyupdate.googlecode.com/svn-history/r401/trunk/frmFilesInUse.cs (no copyright in code at time of viewing)
/// </remarks>
public static List<Process> WhoIsLocking(string path)
{
var key = Guid.NewGuid().ToString();
var processes = new List<Process>();
var res = RmStartSession(out var handle, 0, key);
if (res != 0)
return processes;
try
{
const int ERROR_MORE_DATA = 234;
uint pnProcInfoNeeded = 0, pnProcInfo = 0, lpdwRebootReasons = RM_REBOOT_REASON_NONE;
var resources = new[] { path }; // Just checking on one resource.
res = RmRegisterResources(handle, (uint)resources.Length, resources, 0, null!, 0, null!);
if (res != 0)
return processes;
//Note: there's a race condition here -- the first call to RmGetList() returns
// the total number of process. However, when we call RmGetList() again to get
// the actual processes this number may have increased.
res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, null!, ref lpdwRebootReasons);
if (res == ERROR_MORE_DATA)
{
// Create an array to store the process results
var processInfo = new RM_PROCESS_INFO[pnProcInfoNeeded];
pnProcInfo = pnProcInfoNeeded;
// Get the list
res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, processInfo, ref lpdwRebootReasons);
if (res == 0)
{
// Enumerate all of the results and add them to the list to be returned
for (var i = 0; i < pnProcInfo; i++)
{
try
{
processes.Add(Process.GetProcessById(processInfo[i].Process.dwProcessId));
}
// catch the error -- in case the process is no longer running
catch (ArgumentException)
{
}
}
}
else
return processes;
}
else if (res != 0)
return processes;
}
finally
{
RmEndSession(handle);
}
return processes;
}
}