InUseDetection
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Relativity.Transfer
{
internal static class InUseDetection
{
private struct RM_UNIQUE_PROCESS
{
public int dwProcessId;
public 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 = 64)]
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
}
private const int RmRebootReasonNone = 0;
private const int CCH_RM_MAX_APP_NAME = 255;
private const int CCH_RM_MAX_SVC_NAME = 63;
[DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int RmStartSession(out uint pSessionHandle, int dwSessionFlags, string strSessionKey);
[DllImport("rstrtmgr.dll")]
private static extern int RmEndSession(uint pSessionHandle);
[DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int RmRegisterResources(uint pSessionHandle, uint nFiles, string[] rgsFilenames, uint nApplications, [In] RM_UNIQUE_PROCESS[] rgApplications, uint nServices, string[] rgsServiceNames);
[DllImport("rstrtmgr.dll", SetLastError = true)]
private static extern int RmGetList(uint dwSessionHandle, out uint pnProcInfoNeeded, ref uint pnProcInfo, [In] [Out] RM_PROCESS_INFO[] rgAffectedApps, ref uint lpdwRebootReasons);
public static IList<Process> GetProcessesUsingFiles(IList<string> filePaths)
{
uint num = CreateSession();
try {
RegisterResources(filePaths, num);
return GetProcesses(num);
} finally {
RmEndSession(num);
}
}
private static List<Process> GetProcesses(uint sessionHandle)
{
List<Process> list = new List<Process>();
uint pnProcInfoNeeded = 0;
uint pnProcInfo = 0;
uint lpdwRebootReasons = 0;
switch (RmGetList(sessionHandle, out pnProcInfoNeeded, ref pnProcInfo, null, ref lpdwRebootReasons)) {
case 234: {
RM_PROCESS_INFO[] array = new RM_PROCESS_INFO[pnProcInfoNeeded];
pnProcInfo = (uint)array.Length;
if (RmGetList(sessionHandle, out pnProcInfoNeeded, ref pnProcInfo, array, ref lpdwRebootReasons) != 0) {
int lastWin32Error2 = Marshal.GetLastWin32Error();
throw new Win32Exception($"""{lastWin32Error2}");
}
AddFoundProcesses(pnProcInfo, list, array);
break;
}
default: {
int lastWin32Error = Marshal.GetLastWin32Error();
throw new Win32Exception($"""{lastWin32Error}");
}
case 0:
break;
}
return list;
}
private static void AddFoundProcesses(uint pnProcInfo, List<Process> processes, RM_PROCESS_INFO[] processInfo)
{
for (int i = 0; i < pnProcInfo; i++) {
try {
processes.Add(Process.GetProcessById(processInfo[i].Process.dwProcessId));
} catch (ArgumentException) {
}
}
}
private static uint CreateSession()
{
uint pSessionHandle = default(uint);
if (RmStartSession(out pSessionHandle, 0, Guid.NewGuid().ToString("N")) == 0)
return pSessionHandle;
int lastWin32Error = Marshal.GetLastWin32Error();
throw new Win32Exception($"""{lastWin32Error}");
}
private static void RegisterResources(IList<string> filePaths, uint sessionHandle)
{
string[] array = new string[filePaths.Count];
filePaths.CopyTo(array, 0);
if (RmRegisterResources(sessionHandle, (uint)array.Length, array, 0, null, 0, null) != 0) {
int lastWin32Error = Marshal.GetLastWin32Error();
throw new Win32Exception($"""{lastWin32Error}");
}
}
}
}