How can I rewrite this project using C#?

I want to implement a way to copy Chrome’s Cookies file to a specific directory, but the Cookies file will be occupied by Chrome making it impossible to copy it, I have learned that I can find the handles that occupy this file by traversing all the process handles and shutting them down so that I can copy the Cookies file without shutting down Chrome, but I only I found sample code written in C++, I tried to implement it in C#, but it didn’t close all handles successfully. How can I implement this C++ project completely using C#? Project address:
https://www.dima.to/blog/how-to-enumerate-all-open-handles-for-all-processes-on-a-windows-machine/
:grinning:

program.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.IO;
using System.Threading.Tasks;
using static ConsoleApp1.Win32;

namespace ConsoleApp1
{
    class Program
    {
		static string fullPath = @"C:\\Users\\admin\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Network\\Cookies";
		static string destinationPath = @"C:\\Temp\\Cookies";
		static void Main(string[] args)
        {
			
			//Unlock(sourcePath);

			

			ListProcesses();

            try
            {
                CopyFile(fullPath, destinationPath);
                Console.WriteLine("Successful");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"error:{ex.Message}");
            }


        }

		static void ListProcesses()
		{
			Process[] processCollection = Process.GetProcesses();
			foreach (Process p in processCollection)
			{

				if (p.ProcessName == "chrome")
				{
					Console.WriteLine($"ProcessName={p.ProcessName}   ProcessID={p.Id}");

					var hCurrentProcess = Process.GetCurrentProcess().Handle;

					uint targetProcessId = (uint)p.Id;

					
					var hProcess = OpenProcess(OpenProcessDesiredAccess.ProcessDupHandle, false, targetProcessId);
					if (hProcess == IntPtr.Zero)
					{
						throw new UnauthorizedAccessException();  
					}
					var handles = SearchFileHandles(targetProcessId, hProcess, fullPath);  
					foreach (var handle in handles)
					{
						
						DuplicateHandle(hProcess, handle, hCurrentProcess, out var duplicatedHandle, 0, false, 1);
						
						CloseHandle(duplicatedHandle);
					}
					

				}


			}
		}


		static void CopyFile(string sourcePath, string destinationPath)
		{
			
			if (!File.Exists(sourcePath))
			{
				throw new FileNotFoundException("FileNotFound", sourcePath);
			}

			try
			{
				
				File.Copy(sourcePath, destinationPath, true);
			}
			catch (Exception ex)
			{
				
				throw new Exception($"{ex.Message}");
			}
		}


		public static List<IntPtr> SearchFileHandles(uint targetPid, IntPtr hProcess, string fullPath, uint bufSize = 0x8000, uint maxRetry = 8)
		{

			var diskDosName = Marshal.AllocHGlobal(120);
			//if (QueryDosDevice(fullPath[..2], diskDosName, 120) == 0)
			if (QueryDosDevice(fullPath.Substring(0, 2), diskDosName, 120) == 0)
			{
				Marshal.FreeHGlobal(diskDosName);
				throw new Win32Exception();
			}
			var dosPath = Marshal.PtrToStringUni(diskDosName) + fullPath.Substring(0, 2);
			Marshal.FreeHGlobal(diskDosName);
			var currentHandle = Process.GetCurrentProcess().Handle;
			var pHandle = Marshal.AllocHGlobal((int)bufSize);
			var length = 0U;
			for (var i = 0; i < maxRetry; i++)
			{
				if (ZwQuerySystemInformation(SystemInformationClass.SystemExtendedHandleInformation, pHandle, bufSize, ref length) == 0)
				{
					var result = new List<IntPtr>();

					var nInfos = Marshal.ReadInt64(pHandle);
					pHandle += 0x10;

					var objTypeInfo = Marshal.AllocHGlobal(128);
					var objNameInfo = Marshal.AllocHGlobal(1024);
					for (var j = 0; j < nInfos; j++)
					{
						//var ptr = pHandle + Marshal.SizeOf<SystemHandleTableEntryInfoEx>() * j;
						SystemHandleTableEntryInfoEx dummyInstance = new SystemHandleTableEntryInfoEx(); 
						var ptr = pHandle + Marshal.SizeOf(dummyInstance) * j;
						var pid = (uint)Marshal.ReadInt32(ptr + sizeof(ulong));
						if (pid == targetPid)
						{
							var sourceHandle = Marshal.ReadIntPtr(ptr + 2 * sizeof(ulong));
							if (!DuplicateHandle(hProcess, sourceHandle, currentHandle, out var duplicatedHandle, 0, false, 2))
							{
								continue;
							}
							Task.Run(() => {
								if (ZwQueryObject(duplicatedHandle, ObjectInformationClass.ObjectTypeInformation, objTypeInfo, 128, IntPtr.Zero) != 0)
								{
									return;
								}
								
								unsafe
								{
									if (*(short*)objTypeInfo == 0)
									{
										return;
									}
									var typePtr = *(byte**)(objTypeInfo + 8);
									// File ASCII
									if (*typePtr != 70 || *(typePtr + 2) != 105 || *(typePtr + 4) != 108 || *(typePtr + 6) != 101)
									{
										return;
									}
								}
								if (ZwQueryObject(duplicatedHandle, ObjectInformationClass.ObjectNameInformation, objNameInfo, 1024, IntPtr.Zero) != 0)
								{
									return;
								}
								var strLength = Marshal.ReadInt16(objNameInfo);
								if (strLength == 0)
								{
									return;
								}
								var str = Marshal.PtrToStringUni(objNameInfo + 16, strLength / 2);

								if (str == dosPath)
								{
									result.Add(sourceHandle);
								}
								CloseHandle(duplicatedHandle);
							}).Wait(10);
						}
					}

					Marshal.FreeHGlobal(objTypeInfo);
					Marshal.FreeHGlobal(objNameInfo);

					Marshal.FreeHGlobal(pHandle - 0x10);
					return result;
				}
				bufSize = length + 1024;  
				pHandle = Marshal.ReAllocHGlobal(pHandle, new IntPtr(bufSize));
			}
			throw new Win32Exception();
		}




		public static uint[]? GetFileOccupiedPidList(params string[] fullPaths)
		{
			uint[]? pidList = null;

			var res = RmStartSession(out var handle, 0, Guid.NewGuid().ToString());

			if (res != 0)
			{
				throw new Exception("Could not begin restart session. Unable to determine file locker.");
			}

			try
			{
				uint pnProcInfo = 0, rebootReasons = 0;

				res = RmRegisterResources(handle, (uint)fullPaths.Length, fullPaths, 0, null, 0, null);

				if (res != 0)
				{
					throw new Exception("Could not register resource.");
				}

				//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 var pnProcInfoNeeded, ref pnProcInfo, null, ref rebootReasons);

				if (res == 234)
				{  // ErrorMoreData
				   // Create an array to store the process results
					var processInfo = new RmProcessInfo[pnProcInfoNeeded];
					pnProcInfo = pnProcInfoNeeded;

					// Get the list
					res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, processInfo, ref rebootReasons);

					if (res == 0)
					{
						pidList = new uint[pnProcInfo];

						// Enumerate all of the results and add them to the 
						// list to be returned
						for (var i = 0; i < pnProcInfo; i++)
						{
							pidList[i] = processInfo[i].Process.dwProcessId;
						}
					}
					else
					{
						throw new Exception("Could not list processes locking resource.");
					}
				}
				else if (res != 0)
				{
					throw new Exception("Could not list processes locking resource. Failed to get size of result.");
				}
			}
			finally
			{
				RmEndSession(handle);
			}

			return pidList;
		}

		public static void Unlock(string fullPath)
		{
			
			var pidList = GetFileOccupiedPidList(fullPath);
			if (pidList == null)
			{
				return;
			}
			var hCurrentProcess = Process.GetCurrentProcess().Handle;
			foreach (var pid in pidList)
			{
				
				var hProcess = OpenProcess(OpenProcessDesiredAccess.ProcessDupHandle, false, pid);
				if (hProcess == IntPtr.Zero)
				{
					throw new UnauthorizedAccessException();  
				}
				var handles = SearchFileHandles(pid, hProcess, fullPath);  
				foreach (var handle in handles)
				{
					
					DuplicateHandle(hProcess, handle, hCurrentProcess, out var duplicatedHandle, 0, false, 1);
					
					CloseHandle(duplicatedHandle);
				}
			}
		}
	}
}

win32.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1
{
	public static class Win32
	{
		private const string Gdi32 = "gdi32.dll";
		private const string User32 = "user32.dll";
		private const string Kernel32 = "kernel32.dll";

		private const string Ntdll = "ntdll.dll";
		private const string Dwmapi = "dwmapi.dll";
		private const string Rstrtmgr = "rstrtmgr.dll";



		[DllImport(Rstrtmgr, CharSet = CharSet.Unicode)]
		public static extern int RmRegisterResources(uint pSessionHandle, uint nFiles, string[] rgsFilenames, uint nApplications, [In] RmUniqueProcess[]? rgApplications, uint nServices, string[]? rgsServiceNames);

		[DllImport(Rstrtmgr, CharSet = CharSet.Auto)]
		public static extern int RmStartSession(out uint pSessionHandle, int dwSessionFlags, string strSessionKey);

		[DllImport(Rstrtmgr)]
		public static extern int RmEndSession(uint pSessionHandle);

		[DllImport(Rstrtmgr)]
		public static extern int RmGetList(uint dwSessionHandle, out uint pnProcInfoNeeded, ref uint pnProcInfo, [In, Out] RmProcessInfo[]? rgAffectedApps, ref uint lpdwRebootReasons);

		[DllImport(Ntdll)]
		public static extern uint NtQueryInformationProcess(IntPtr ProcessHandle, uint ProcessInformationClass, IntPtr ProcessInformation, uint ProcessInformationLength, out uint ReturnLength);

		[DllImport(Kernel32)]
		public static extern IntPtr OpenProcess(OpenProcessDesiredAccess dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwProcessId);

		[DllImport(Kernel32)]
		public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, IntPtr lpBuffer, uint nSize, out uint lpNumberOfBytesRead);


		/// <summary>
		/// https://docs.microsoft.com/en-us/windows/win32/sysinfo/zwquerysysteminformation
		/// </summary>
		/// <param name="SystemInformationClass"></param>
		/// <param name="SystemInformation"></param>
		/// <param name="SystemInformationLength"></param>
		/// <param name="ReturnLength"></param>
		/// <returns></returns>
		[DllImport(Ntdll)]
		public static extern uint ZwQuerySystemInformation(SystemInformationClass SystemInformationClass, IntPtr SystemInformation, uint SystemInformationLength, ref uint ReturnLength);


		[DllImport(Ntdll)]
		public static extern uint ZwQueryObject(IntPtr Handle, ObjectInformationClass ObjectInformationClass, IntPtr ObjectInformation, uint ObjectInformationLength, IntPtr ReturnLength);

		[DllImport(Kernel32, SetLastError = true)]
		public static extern bool DuplicateHandle(IntPtr hSourceProcessHandle, IntPtr hSourceHandle, IntPtr hTargetProcessHandle, out IntPtr lpTargetHandle, uint dwDesiredAccess, bool bInheritHandle, uint dwOptions);

		[DllImport(Kernel32, CharSet = CharSet.Unicode)]
		public static extern uint QueryDosDevice(string deviceName, IntPtr targetPath, uint chMax);

		[DllImport(Kernel32)]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CloseHandle(IntPtr handle);

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

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
		public struct RmProcessInfo
		{
			public RmUniqueProcess Process;

			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
			public string strAppName;

			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
			public string strServiceShortName;

			public RmAppType ApplicationType;
			public uint AppStatus;
			public uint TSSessionId;
			[MarshalAs(UnmanagedType.Bool)]
			public bool bRestartable;
		}

		[StructLayout(LayoutKind.Sequential)]
		public struct SystemHandleTableEntryInfoEx
		{
			public ulong Object;

			public ulong UniqueProcessId;
	
			public ulong HandleValue;
			public uint GrantedAccess;
			public ushort CreatorBackTraceIndex;
			public ushort ObjectTypeIndex;
			public uint HandleAttributes;
			public uint Reserved;
		}
		public enum RmAppType
		{
			RmUnknownApp = 0,
			RmMainWindow = 1,
			RmOtherWindow = 2,
			RmService = 3,
			RmExplorer = 4,
			RmConsole = 5,
			RmCritical = 1000
		}




		[Flags]
		public enum OpenProcessDesiredAccess : uint
		{
			VmRead = 0x0010,
			ProcessDupHandle = 0x0040,
			QueryInformation = 0x0400,
			QueryLimitedInformation = 0x1000
		}

		public enum ObjectInformationClass
		{
			ObjectBasicInformation,
			ObjectNameInformation,
			ObjectTypeInformation
		}


		public enum SystemInformationClass
		{
			SystemExtendedHandleInformation = 64
		}

	}
}

win32

using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;

namespace ConsoleApp1
{
    public static class Win32
    {
        private const string Gdi32 = "gdi32.dll";
        private const string User32 = "user32.dll";
        private const string Kernel32 = "kernel32.dll";

        private const string Ntdll = "ntdll.dll";
        private const string Dwmapi = "dwmapi.dll";
        private const string Rstrtmgr = "rstrtmgr.dll";

        [DllImport(Rstrtmgr, CharSet = CharSet.Unicode)]
        public static extern int RmRegisterResources(uint pSessionHandle, uint nFiles, string[] rgsFilenames, uint nApplications, [In] RmUniqueProcess[]? rgApplications, uint nServices, string[]? rgsServiceNames);

        [DllImport(Rstrtmgr, CharSet = CharSet.Auto)]
        public static extern int RmStartSession(out uint pSessionHandle, int dwSessionFlags, string strSessionKey);

        [DllImport(Rstrtmgr)]
        public static extern int RmEndSession(uint pSessionHandle);

        [DllImport(Rstrtmgr)]
        public static extern int RmGetList(uint dwSessionHandle, out uint pnProcInfoNeeded, ref uint pnProcInfo, [In, Out] RmProcessInfo[]? rgAffectedApps, ref uint lpdwRebootReasons);

        [DllImport(Ntdll)]
        public static extern uint NtQueryInformationProcess(IntPtr ProcessHandle, uint ProcessInformationClass, IntPtr ProcessInformation, uint ProcessInformationLength, out uint ReturnLength);

        [DllImport(Kernel32)]
        public static extern IntPtr OpenProcess(OpenProcessDesiredAccess dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwProcessId);

        [DllImport(Kernel32)]
        public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, IntPtr lpBuffer, uint nSize, out uint lpNumberOfBytesRead);

        [DllImport(Ntdll)]
        public static extern uint ZwQuerySystemInformation(SystemInformationClass SystemInformationClass, IntPtr SystemInformation, uint SystemInformationLength, ref uint ReturnLength);

        [DllImport(Ntdll)]
        public static extern uint ZwQueryObject(IntPtr Handle, ObjectInformationClass ObjectInformationClass, IntPtr ObjectInformation, uint ObjectInformationLength, IntPtr ReturnLength);

        [DllImport(Kernel32, SetLastError = true)]
        public static extern bool DuplicateHandle(IntPtr hSourceProcessHandle, IntPtr hSourceHandle, IntPtr hTargetProcessHandle, out IntPtr lpTargetHandle, uint dwDesiredAccess, bool bInheritHandle, uint dwOptions);

        [DllImport(Kernel32, CharSet = CharSet.Unicode)]
        public static extern uint QueryDosDevice(string deviceName, IntPtr targetPath, uint chMax);

        [DllImport(Kernel32)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool CloseHandle(IntPtr handle);

        [StructLayout(LayoutKind.Sequential)]
        public struct RmUniqueProcess
        {
            public uint dwProcessId;
            public FILETIME ProcessStartTime;
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public struct RmProcessInfo
        {
            public RmUniqueProcess Process;

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string strAppName;

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
            public string strServiceShortName;

            public RmAppType ApplicationType;
            public uint AppStatus;
            public uint TSSessionId;
            [MarshalAs(UnmanagedType.Bool)]
            public bool bRestartable;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct SystemHandleTableEntryInfoEx
        {
            public ulong Object;
            public ulong UniqueProcessId;
            public ulong HandleValue;
            public uint GrantedAccess;
            public ushort CreatorBackTraceIndex;
            public ushort ObjectTypeIndex;
            public uint HandleAttributes;
            public uint Reserved;
        }

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

        [Flags]
        public enum OpenProcessDesiredAccess : uint
        {
            VmRead = 0x0010,
            ProcessDupHandle = 0x0040,
            QueryInformation = 0x0400,
            QueryLimitedInformation = 0x1000
        }

        public enum ObjectInformationClass
        {
            ObjectBasicInformation,
            ObjectNameInformation,
            ObjectTypeInformation
        }

        public enum SystemInformationClass
        {
            SystemExtendedHandleInformation = 64
        }
    }
}

Program

using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using static ConsoleApp1.Win32;

namespace ConsoleApp1
{
    class Program
    {
        static string fullPath = @"C:\\Users\\admin\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Network\\Cookies";
        static string destinationPath = @"C:\\Temp\\Cookies";
        static void Main(string[] args)
        {

            //Unlock(sourcePath);

            ListProcesses();

            try
            {
                CopyFile(fullPath, destinationPath);
                Console.WriteLine("Successful");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"error: {ex.Message}");
            }
        }

        static void ListProcesses()
        {
            Process[] processCollection = Process.GetProcesses();
            foreach (Process p in processCollection)
            {
                if (p.ProcessName == "chrome")
                {
                    Console.WriteLine($"ProcessName={p.ProcessName}   ProcessID={p.Id}");

                    var hCurrentProcess = Process.GetCurrentProcess().Handle;

                    uint targetProcessId = (uint)p.Id;

                    var hProcess = OpenProcess(OpenProcessDesiredAccess.ProcessDupHandle, false, targetProcessId);
                    if (hProcess == IntPtr.Zero)
                    {
                        throw new UnauthorizedAccessException();
                    }
                    var handles = SearchFileHandles(targetProcessId, hProcess, fullPath);
                    foreach (var handle in handles)
                    {
                        DuplicateHandle(hProcess, handle, hCurrentProcess, out var duplicatedHandle, 0, false, 1);
                        CloseHandle(duplicatedHandle);
                    }
                }
            }
        }

        static void CopyFile(string sourcePath, string destinationPath)
        {
            if (!File.Exists(sourcePath))
            {
                throw new FileNotFoundException("FileNotFound", sourcePath);
            }

            try
            {
                File.Copy(sourcePath, destinationPath, true);
            }
            catch (Exception ex)
            {
                throw new Exception($"{ex.Message}");
            }
        }

        public static List<IntPtr> SearchFileHandles(uint targetPid, IntPtr hProcess, string fullPath, uint bufSize = 0x8000, uint maxRetry = 8)
        {
            var diskDosName = Marshal.AllocHGlobal(120);
            if (QueryDosDevice(fullPath.Substring(0, 2), diskDosName, 120) == 0)
            {
                Marshal.FreeHGlobal(diskDosName);
                throw new Win32Exception();
            }
            var dosPath = Marshal.PtrToStringUni(diskDosName) + fullPath.Substring(0, 2);
            Marshal.FreeHGlobal(diskDosName);
            var currentHandle = Process.GetCurrentProcess().Handle;
            var pHandle = Marshal.AllocHGlobal((int)bufSize);
            var length = 0U;
            for (var i = 0; i < maxRetry; i++)
            {
                if (ZwQuerySystemInformation(SystemInformationClass.SystemExtendedHandleInformation, pHandle, bufSize, ref length) == 0)
                {
                    var result = new List<IntPtr>();

                    var nInfos = Marshal.ReadInt64(pHandle);
                    pHandle += 0x10;

                    var objTypeInfo = Marshal.AllocHGlobal(128);
                    var objNameInfo = Marshal.AllocHGlobal(1024);
                    for (var j = 0; j < nInfos; j++)
                    {
                        SystemHandleTableEntryInfoEx dummyInstance = new SystemHandleTableEntryInfoEx();
                        var ptr = pHandle + Marshal.SizeOf(dummyInstance) * j;
                        var pid = (uint)Marshal.ReadInt32(ptr + sizeof(ulong));
                        if (pid == targetPid)
                        {
                            var sourceHandle = Marshal.ReadIntPtr(ptr + 2 * sizeof(ulong));
                            if (!DuplicateHandle(hProcess, sourceHandle, currentHandle, out var duplicatedHandle, 0, false, 2))
                            {
                                continue;
                            }
                            Task.Run(() => {
                                if (ZwQueryObject(duplicatedHandle, ObjectInformationClass.ObjectTypeInformation, objTypeInfo, 128, IntPtr.Zero) != 0)
                                {
                                    return;
                                }

                                unsafe
                                {
                                    if (*(short*)objTypeInfo == 0)
                                    {
                                        return;
                                    }
                                    var typePtr = *(byte**)(objTypeInfo + 8);
                                    // File ASCII
                                    if (*typePtr != 70 || *(typePtr + 2) != 105 || *(typePtr + 4) != 108 || *(typePtr + 6) != 101)
                                    {
                                        return;
                                    }
                                }
                                if (ZwQueryObject(duplicatedHandle, ObjectInformationClass.ObjectNameInformation, objNameInfo, 1024, IntPtr.Zero) != 0)
                                {
                                    return;
                                }
                                var strLength = Marshal.ReadInt16(objNameInfo);
                                if (strLength == 0)
                                {
                                    return;
                                }
                                var str = Marshal.PtrToStringUni(objNameInfo + 16, strLength / 2);

                                if (str == dosPath)
                                {
                                    result.Add(sourceHandle);
                                }
                                CloseHandle(duplicatedHandle);
                            }).Wait(10);
                        }
                    }

                    Marshal.FreeHGlobal(objTypeInfo);
                    Marshal.FreeHGlobal(objNameInfo);

                    Marshal.FreeHGlobal(pHandle - 0x10);
                    return result;
                }
                bufSize = length + 1024;
                pHandle = Marshal.ReAllocHGlobal(pHandle, new IntPtr(bufSize));
            }
            throw new Win32Exception();
        }

        public static uint[]? GetFileOccupiedPidList(params string[] fullPaths)
        {
            uint[]? pidList = null;

            var res = RmStartSession(out var handle, 0, Guid.NewGuid().ToString());

            if (res != 0)
            {
                throw new Exception("Could not begin restart session. Unable to determine file locker.");
            }

            try
            {
                uint pnProcInfo = 0, rebootReasons = 0;

                res = RmRegisterResources(handle, (uint)fullPaths.Length, fullPaths, 0, null, 0, null);

                if (res != 0)
                {
                    throw new Exception("Could not register resource.");
                }

                res = RmGetList(handle, out var pnProcInfoNeeded, ref pnProcInfo, null, ref rebootReasons);

                if (res == 234)
                {
                    var processInfo = new RmProcessInfo[pnProcInfoNeeded];
                    pnProcInfo = pnProcInfoNeeded;

                    res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, processInfo, ref rebootReasons);

                    if (res == 0)
                    {
                        pidList = new uint[pnProcInfo];

                        for (var i = 0; i < pnProcInfo; i++)
                        {
                            pidList[i] = processInfo[i].Process.dwProcessId;
                        }
                    }
                    else
                    {
                        throw new Exception("Could not list processes locking resource.");
                    }
                }
                else if (res != 0)
                {
                    throw new Exception("Could not list processes locking resource. Failed to get size of result.");
                }
            }
            finally
            {
                RmEndSession(handle);
            }

            return pidList;
        }

        public static void Unlock(string fullPath)
        {
            var pidList = GetFileOccupiedPidList(fullPath);
            if (pidList == null)
            {
                return;
            }
            var hCurrentProcess = Process.GetCurrentProcess().Handle;
            foreach (var pid in pidList)
            {
                var hProcess = OpenProcess(OpenProcessDesiredAccess.ProcessDupHandle, false, pid);
                if (hProcess == IntPtr.Zero)
                {
                    throw new UnauthorizedAccessException();
                }
                var handles = SearchFileHandles(pid, hProcess, fullPath);
                foreach (var handle in handles)
                {
                    DuplicateHandle(hProcess, handle, hCurrentProcess, out var duplicatedHandle, 0, false, 1);
                    CloseHandle(duplicatedHandle);
                }
            }
        }
    }
}

Use AI :smiley: