C #을 사용하여 어떤 프로세스가 파일을 잠 갔는지 어떻게 알 수 있습니까?
Windows에서 파일을 잠근 프로세스 (C # 사용)를 어떻게 확인합니까?
타사 도구는 도움이되지만 내가 찾고있는 것은 아닙니다.
이 질문에는 현재 7 년이 넘은 원래의 답변이 있습니다. 이 코드는 https://gist.github.com/ieb/2290426에 보존되어 있습니다. 이 이전 버전은 어떤 이유로 Windows XP를 사용해야하는 경우 사용할 수 있습니다.
훨씬 더 나은 대답은 파일 잠금을 확인하는 방법에 있습니다.
아래에 Eric J의 답변을 복제했습니다 ( using
문이 추가되고 여기에 있던 이전 코드와 일치하는 클래스 및 메서드 이름이 포함됨)이 답변에 대한 주석이 오래되었을 수 있습니다.
다음과 같이 사용하십시오.
List<Process> locks = Win32Processes.GetProcessesLockingFile(@"C:\Hello.docx");
암호:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace FileLockInfo
{
public static class Win32Processes
{
/// <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> GetProcessesLockingFile(string path)
{
uint handle;
string key = Guid.NewGuid().ToString();
int res = RmStartSession(out handle, 0, key);
if (res != 0) throw new Exception("Could not begin restart session. Unable to determine file locker.");
try
{
const int MORE_DATA = 234;
uint pnProcInfoNeeded, pnProcInfo = 0, lpdwRebootReasons = RmRebootReasonNone;
string[] resources = {path}; // Just checking on one resource.
res = RmRegisterResources(handle, (uint) resources.Length, resources, 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 pnProcInfoNeeded, ref pnProcInfo, null, ref lpdwRebootReasons);
if (res == MORE_DATA)
{
return EnumerateProcesses(pnProcInfoNeeded, handle, lpdwRebootReasons);
}
else if (res != 0) throw new Exception("Could not list processes locking resource. Failed to get size of result.");
}
finally
{
RmEndSession(handle);
}
return new List<Process>();
}
[StructLayout(LayoutKind.Sequential)]
public struct RM_UNIQUE_PROCESS
{
public int dwProcessId;
public System.Runtime.InteropServices.ComTypes.FILETIME ProcessStartTime;
}
const int RmRebootReasonNone = 0;
const int CCH_RM_MAX_APP_NAME = 255;
const int CCH_RM_MAX_SVC_NAME = 63;
public enum RM_APP_TYPE
{
RmUnknownApp = 0,
RmMainWindow = 1,
RmOtherWindow = 2,
RmService = 3,
RmExplorer = 4,
RmConsole = 5,
RmCritical = 1000
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct RM_PROCESS_INFO
{
public RM_UNIQUE_PROCESS Process;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_APP_NAME + 1)] public string strAppName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_SVC_NAME + 1)] public string strServiceShortName;
public RM_APP_TYPE ApplicationType;
public uint AppStatus;
public uint TSSessionId;
[MarshalAs(UnmanagedType.Bool)] public bool bRestartable;
}
[DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)]
static extern int RmRegisterResources(uint pSessionHandle, uint nFiles, string[] rgsFilenames,
uint nApplications, [In] RM_UNIQUE_PROCESS[] rgApplications, uint 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);
private static List<Process> EnumerateProcesses(uint pnProcInfoNeeded, uint handle, uint lpdwRebootReasons)
{
var processes = new List<Process>(10);
// Create an array to store the process results
var processInfo = new RM_PROCESS_INFO[pnProcInfoNeeded];
var pnProcInfo = pnProcInfoNeeded;
// Get the list
var res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, processInfo, ref lpdwRebootReasons);
if (res != 0) throw new Exception("Could not list processes locking resource.");
for (int i = 0; i < pnProcInfo; i++)
{
try
{
processes.Add(Process.GetProcessById(processInfo[i].Process.dwProcessId));
}
catch (ArgumentException) { } // catch the error -- in case the process is no longer running
}
return processes;
}
}
}
여기에서 찾은 코드, https://vmccontroller.svn.codeplex.com/svn/VmcController/VmcServices/DetectOpenFiles.cs
Iain이 제공하는 코드보다 훨씬 더 잘 작동합니다. Iain의 코드는 자체 잠금을 획득하는 것처럼 보였습니다. 다음은 FileSystemInfo 개체 대신 잠긴 파일의 문자열 경로를 반환하도록 수정 된 위 코드의 약간 수정 된 버전입니다.
using System;
using System.Collections.Generic;
//using System.EnterpriseServices;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using Microsoft.Win32.SafeHandles;
namespace Crmc.Core.BuildTasks
{
using System.Diagnostics;
using System.Linq;
#region ENUMs
internal enum NT_STATUS
{
STATUS_SUCCESS = 0x00000000,
STATUS_BUFFER_OVERFLOW = unchecked((int)0x80000005L),
STATUS_INFO_LENGTH_MISMATCH = unchecked((int)0xC0000004L)
}
internal enum SYSTEM_INFORMATION_CLASS
{
SystemBasicInformation = 0,
SystemPerformanceInformation = 2,
SystemTimeOfDayInformation = 3,
SystemProcessInformation = 5,
SystemProcessorPerformanceInformation = 8,
SystemHandleInformation = 16,
SystemInterruptInformation = 23,
SystemExceptionInformation = 33,
SystemRegistryQuotaInformation = 37,
SystemLookasideInformation = 45
}
internal enum OBJECT_INFORMATION_CLASS
{
ObjectBasicInformation = 0,
ObjectNameInformation = 1,
ObjectTypeInformation = 2,
ObjectAllTypesInformation = 3,
ObjectHandleInformation = 4
}
[Flags]
internal enum ProcessAccessRights
{
PROCESS_DUP_HANDLE = 0x00000040
}
[Flags]
internal enum DuplicateHandleOptions
{
DUPLICATE_CLOSE_SOURCE = 0x1,
DUPLICATE_SAME_ACCESS = 0x2
}
#endregion
[SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
internal sealed class SafeObjectHandle : SafeHandleZeroOrMinusOneIsInvalid
{
private SafeObjectHandle()
: base(true)
{ }
internal SafeObjectHandle(IntPtr preexistingHandle, bool ownsHandle)
: base(ownsHandle)
{
base.SetHandle(preexistingHandle);
}
protected override bool ReleaseHandle()
{
return NativeMethods.CloseHandle(base.handle);
}
}
[SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
internal sealed class SafeProcessHandle : SafeHandleZeroOrMinusOneIsInvalid
{
private SafeProcessHandle()
: base(true)
{ }
internal SafeProcessHandle(IntPtr preexistingHandle, bool ownsHandle)
: base(ownsHandle)
{
base.SetHandle(preexistingHandle);
}
protected override bool ReleaseHandle()
{
return NativeMethods.CloseHandle(base.handle);
}
}
#region Native Methods
internal static class NativeMethods
{
[DllImport("ntdll.dll")]
internal static extern NT_STATUS NtQuerySystemInformation(
[In] SYSTEM_INFORMATION_CLASS SystemInformationClass,
[In] IntPtr SystemInformation,
[In] int SystemInformationLength,
[Out] out int ReturnLength);
[DllImport("ntdll.dll")]
internal static extern NT_STATUS NtQueryObject(
[In] IntPtr Handle,
[In] OBJECT_INFORMATION_CLASS ObjectInformationClass,
[In] IntPtr ObjectInformation,
[In] int ObjectInformationLength,
[Out] out int ReturnLength);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern SafeProcessHandle OpenProcess(
[In] ProcessAccessRights dwDesiredAccess,
[In, MarshalAs(UnmanagedType.Bool)] bool bInheritHandle,
[In] int dwProcessId);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool DuplicateHandle(
[In] IntPtr hSourceProcessHandle,
[In] IntPtr hSourceHandle,
[In] IntPtr hTargetProcessHandle,
[Out] out SafeObjectHandle lpTargetHandle,
[In] int dwDesiredAccess,
[In, MarshalAs(UnmanagedType.Bool)] bool bInheritHandle,
[In] DuplicateHandleOptions dwOptions);
[DllImport("kernel32.dll")]
internal static extern IntPtr GetCurrentProcess();
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern int GetProcessId(
[In] IntPtr Process);
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool CloseHandle(
[In] IntPtr hObject);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern int QueryDosDevice(
[In] string lpDeviceName,
[Out] StringBuilder lpTargetPath,
[In] int ucchMax);
}
#endregion
//[ComVisible(true), EventTrackingEnabled(true)]
public class DetectOpenFiles// : ServicedComponent
{
private static Dictionary<string, string> deviceMap;
private const string networkDevicePrefix = "\\Device\\LanmanRedirector\\";
private const int MAX_PATH = 260;
private enum SystemHandleType
{
OB_TYPE_UNKNOWN = 0,
OB_TYPE_TYPE = 1,
OB_TYPE_DIRECTORY,
OB_TYPE_SYMBOLIC_LINK,
OB_TYPE_TOKEN,
OB_TYPE_PROCESS,
OB_TYPE_THREAD,
OB_TYPE_UNKNOWN_7,
OB_TYPE_EVENT,
OB_TYPE_EVENT_PAIR,
OB_TYPE_MUTANT,
OB_TYPE_UNKNOWN_11,
OB_TYPE_SEMAPHORE,
OB_TYPE_TIMER,
OB_TYPE_PROFILE,
OB_TYPE_WINDOW_STATION,
OB_TYPE_DESKTOP,
OB_TYPE_SECTION,
OB_TYPE_KEY,
OB_TYPE_PORT,
OB_TYPE_WAITABLE_PORT,
OB_TYPE_UNKNOWN_21,
OB_TYPE_UNKNOWN_22,
OB_TYPE_UNKNOWN_23,
OB_TYPE_UNKNOWN_24,
//OB_TYPE_CONTROLLER,
//OB_TYPE_DEVICE,
//OB_TYPE_DRIVER,
OB_TYPE_IO_COMPLETION,
OB_TYPE_FILE
};
private const int handleTypeTokenCount = 27;
private static readonly string[] handleTypeTokens = new string[] {
"", "", "Directory", "SymbolicLink", "Token",
"Process", "Thread", "Unknown7", "Event", "EventPair", "Mutant",
"Unknown11", "Semaphore", "Timer", "Profile", "WindowStation",
"Desktop", "Section", "Key", "Port", "WaitablePort",
"Unknown21", "Unknown22", "Unknown23", "Unknown24",
"IoCompletion", "File"
};
[StructLayout(LayoutKind.Sequential)]
private struct SYSTEM_HANDLE_ENTRY
{
public int OwnerPid;
public byte ObjectType;
public byte HandleFlags;
public short HandleValue;
public int ObjectPointer;
public int AccessMask;
}
/// <summary>
/// Gets the open files enumerator.
/// </summary>
/// <param name="processId">The process id.</param>
/// <returns></returns>
public static IEnumerable<String> GetOpenFilesEnumerator(int processId)
{
return new OpenFiles(processId);
}
public static List<Process> GetProcessesUsingFile(string fName)
{
List<Process> result = new List<Process>();
foreach (var p in Process.GetProcesses())
{
try
{
if (DetectOpenFiles.GetOpenFilesEnumerator(p.Id).Contains(fName))
{
result.Add(p);
}
}
catch { }//some processes will fail
}
return result;
}
private sealed class OpenFiles : IEnumerable<String>
{
private readonly int processId;
internal OpenFiles(int processId)
{
this.processId = processId;
}
#region IEnumerable<FileSystemInfo> Members
public IEnumerator<String> GetEnumerator()
{
NT_STATUS ret;
int length = 0x10000;
// Loop, probing for required memory.
do
{
IntPtr ptr = IntPtr.Zero;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
RuntimeHelpers.PrepareConstrainedRegions();
try { }
finally
{
// CER guarantees that the address of the allocated
// memory is actually assigned to ptr if an
// asynchronous exception occurs.
ptr = Marshal.AllocHGlobal(length);
}
int returnLength;
ret = NativeMethods.NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS.SystemHandleInformation, ptr, length, out returnLength);
if (ret == NT_STATUS.STATUS_INFO_LENGTH_MISMATCH)
{
// Round required memory up to the nearest 64KB boundary.
length = ((returnLength + 0xffff) & ~0xffff);
}
else if (ret == NT_STATUS.STATUS_SUCCESS)
{
int handleCount = Marshal.ReadInt32(ptr);
int offset = sizeof(int);
int size = Marshal.SizeOf(typeof(SYSTEM_HANDLE_ENTRY));
for (int i = 0; i < handleCount; i++)
{
SYSTEM_HANDLE_ENTRY handleEntry = (SYSTEM_HANDLE_ENTRY)Marshal.PtrToStructure((IntPtr)((int)ptr + offset), typeof(SYSTEM_HANDLE_ENTRY));
if (handleEntry.OwnerPid == processId)
{
IntPtr handle = (IntPtr)handleEntry.HandleValue;
SystemHandleType handleType;
if (GetHandleType(handle, handleEntry.OwnerPid, out handleType) && handleType == SystemHandleType.OB_TYPE_FILE)
{
string devicePath;
if (GetFileNameFromHandle(handle, handleEntry.OwnerPid, out devicePath))
{
string dosPath;
if (ConvertDevicePathToDosPath(devicePath, out dosPath))
{
if (File.Exists(dosPath))
{
yield return dosPath; // return new FileInfo(dosPath);
}
else if (Directory.Exists(dosPath))
{
yield return dosPath; // new DirectoryInfo(dosPath);
}
}
}
}
}
offset += size;
}
}
}
finally
{
// CER guarantees that the allocated memory is freed,
// if an asynchronous exception occurs.
Marshal.FreeHGlobal(ptr);
//sw.Flush();
//sw.Close();
}
}
while (ret == NT_STATUS.STATUS_INFO_LENGTH_MISMATCH);
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
}
#region Private Members
private static bool GetFileNameFromHandle(IntPtr handle, int processId, out string fileName)
{
IntPtr currentProcess = NativeMethods.GetCurrentProcess();
bool remote = (processId != NativeMethods.GetProcessId(currentProcess));
SafeProcessHandle processHandle = null;
SafeObjectHandle objectHandle = null;
try
{
if (remote)
{
processHandle = NativeMethods.OpenProcess(ProcessAccessRights.PROCESS_DUP_HANDLE, true, processId);
if (NativeMethods.DuplicateHandle(processHandle.DangerousGetHandle(), handle, currentProcess, out objectHandle, 0, false, DuplicateHandleOptions.DUPLICATE_SAME_ACCESS))
{
handle = objectHandle.DangerousGetHandle();
}
}
return GetFileNameFromHandle(handle, out fileName, 200);
}
finally
{
if (remote)
{
if (processHandle != null)
{
processHandle.Close();
}
if (objectHandle != null)
{
objectHandle.Close();
}
}
}
}
private static bool GetFileNameFromHandle(IntPtr handle, out string fileName, int wait)
{
using (FileNameFromHandleState f = new FileNameFromHandleState(handle))
{
ThreadPool.QueueUserWorkItem(new WaitCallback(GetFileNameFromHandle), f);
if (f.WaitOne(wait))
{
fileName = f.FileName;
return f.RetValue;
}
else
{
fileName = string.Empty;
return false;
}
}
}
private class FileNameFromHandleState : IDisposable
{
private ManualResetEvent _mr;
private IntPtr _handle;
private string _fileName;
private bool _retValue;
public IntPtr Handle
{
get
{
return _handle;
}
}
public string FileName
{
get
{
return _fileName;
}
set
{
_fileName = value;
}
}
public bool RetValue
{
get
{
return _retValue;
}
set
{
_retValue = value;
}
}
public FileNameFromHandleState(IntPtr handle)
{
_mr = new ManualResetEvent(false);
this._handle = handle;
}
public bool WaitOne(int wait)
{
return _mr.WaitOne(wait, false);
}
public void Set()
{
try
{
_mr.Set();
}
catch{}
}
#region IDisposable Members
public void Dispose()
{
if (_mr != null)
_mr.Close();
}
#endregion
}
private static void GetFileNameFromHandle(object state)
{
FileNameFromHandleState s = (FileNameFromHandleState)state;
string fileName;
s.RetValue = GetFileNameFromHandle(s.Handle, out fileName);
s.FileName = fileName;
s.Set();
}
private static bool GetFileNameFromHandle(IntPtr handle, out string fileName)
{
IntPtr ptr = IntPtr.Zero;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
int length = 0x200; // 512 bytes
RuntimeHelpers.PrepareConstrainedRegions();
try { }
finally
{
// CER guarantees the assignment of the allocated
// memory address to ptr, if an ansynchronous exception
// occurs.
ptr = Marshal.AllocHGlobal(length);
}
NT_STATUS ret = NativeMethods.NtQueryObject(handle, OBJECT_INFORMATION_CLASS.ObjectNameInformation, ptr, length, out length);
if (ret == NT_STATUS.STATUS_BUFFER_OVERFLOW)
{
RuntimeHelpers.PrepareConstrainedRegions();
try { }
finally
{
// CER guarantees that the previous allocation is freed,
// and that the newly allocated memory address is
// assigned to ptr if an asynchronous exception occurs.
Marshal.FreeHGlobal(ptr);
ptr = Marshal.AllocHGlobal(length);
}
ret = NativeMethods.NtQueryObject(handle, OBJECT_INFORMATION_CLASS.ObjectNameInformation, ptr, length, out length);
}
if (ret == NT_STATUS.STATUS_SUCCESS)
{
fileName = Marshal.PtrToStringUni((IntPtr)((int)ptr + 8), (length - 9) / 2);
return fileName.Length != 0;
}
}
finally
{
// CER guarantees that the allocated memory is freed,
// if an asynchronous exception occurs.
Marshal.FreeHGlobal(ptr);
}
fileName = string.Empty;
return false;
}
private static bool GetHandleType(IntPtr handle, int processId, out SystemHandleType handleType)
{
string token = GetHandleTypeToken(handle, processId);
return GetHandleTypeFromToken(token, out handleType);
}
private static bool GetHandleType(IntPtr handle, out SystemHandleType handleType)
{
string token = GetHandleTypeToken(handle);
return GetHandleTypeFromToken(token, out handleType);
}
private static bool GetHandleTypeFromToken(string token, out SystemHandleType handleType)
{
for (int i = 1; i < handleTypeTokenCount; i++)
{
if (handleTypeTokens[i] == token)
{
handleType = (SystemHandleType)i;
return true;
}
}
handleType = SystemHandleType.OB_TYPE_UNKNOWN;
return false;
}
private static string GetHandleTypeToken(IntPtr handle, int processId)
{
IntPtr currentProcess = NativeMethods.GetCurrentProcess();
bool remote = (processId != NativeMethods.GetProcessId(currentProcess));
SafeProcessHandle processHandle = null;
SafeObjectHandle objectHandle = null;
try
{
if (remote)
{
processHandle = NativeMethods.OpenProcess(ProcessAccessRights.PROCESS_DUP_HANDLE, true, processId);
if (NativeMethods.DuplicateHandle(processHandle.DangerousGetHandle(), handle, currentProcess, out objectHandle, 0, false, DuplicateHandleOptions.DUPLICATE_SAME_ACCESS))
{
handle = objectHandle.DangerousGetHandle();
}
}
return GetHandleTypeToken(handle);
}
finally
{
if (remote)
{
if (processHandle != null)
{
processHandle.Close();
}
if (objectHandle != null)
{
objectHandle.Close();
}
}
}
}
private static string GetHandleTypeToken(IntPtr handle)
{
int length;
NativeMethods.NtQueryObject(handle, OBJECT_INFORMATION_CLASS.ObjectTypeInformation, IntPtr.Zero, 0, out length);
IntPtr ptr = IntPtr.Zero;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
RuntimeHelpers.PrepareConstrainedRegions();
try { }
finally
{
ptr = Marshal.AllocHGlobal(length);
}
if (NativeMethods.NtQueryObject(handle, OBJECT_INFORMATION_CLASS.ObjectTypeInformation, ptr, length, out length) == NT_STATUS.STATUS_SUCCESS)
{
return Marshal.PtrToStringUni((IntPtr)((int)ptr + 0x60));
}
}
finally
{
Marshal.FreeHGlobal(ptr);
}
return string.Empty;
}
private static bool ConvertDevicePathToDosPath(string devicePath, out string dosPath)
{
EnsureDeviceMap();
int i = devicePath.Length;
while (i > 0 && (i = devicePath.LastIndexOf('\\', i - 1)) != -1)
{
string drive;
if (deviceMap.TryGetValue(devicePath.Substring(0, i), out drive))
{
dosPath = string.Concat(drive, devicePath.Substring(i));
return dosPath.Length != 0;
}
}
dosPath = string.Empty;
return false;
}
private static void EnsureDeviceMap()
{
if (deviceMap == null)
{
Dictionary<string, string> localDeviceMap = BuildDeviceMap();
Interlocked.CompareExchange<Dictionary<string, string>>(ref deviceMap, localDeviceMap, null);
}
}
private static Dictionary<string, string> BuildDeviceMap()
{
string[] logicalDrives = Environment.GetLogicalDrives();
Dictionary<string, string> localDeviceMap = new Dictionary<string, string>(logicalDrives.Length);
StringBuilder lpTargetPath = new StringBuilder(MAX_PATH);
foreach (string drive in logicalDrives)
{
string lpDeviceName = drive.Substring(0, 2);
NativeMethods.QueryDosDevice(lpDeviceName, lpTargetPath, MAX_PATH);
localDeviceMap.Add(NormalizeDeviceName(lpTargetPath.ToString()), lpDeviceName);
}
localDeviceMap.Add(networkDevicePrefix.Substring(0, networkDevicePrefix.Length - 1), "\\");
return localDeviceMap;
}
private static string NormalizeDeviceName(string deviceName)
{
if (string.Compare(deviceName, 0, networkDevicePrefix, 0, networkDevicePrefix.Length, StringComparison.InvariantCulture) == 0)
{
string shareName = deviceName.Substring(deviceName.IndexOf('\\', networkDevicePrefix.Length) + 1);
return string.Concat(networkDevicePrefix, shareName);
}
return deviceName;
}
#endregion
}
}
그리 간단하지는 않지만 Windows Vista 이상에서는 Restart Manager API 를 사용하여 누가 파일을 사용하고 있는지 확인할 수 있습니다 . Internet Explorer 캐시 설정 에는이 기능을 사용하여 iexplore.exe
열려 있는 프로세스를 감지하는 방법에 대한 세부 정보가 포함되어 있습니다.
많은 세부 사항 생략 :
// Start an RM session
RmStartSession(&sessionHandle, 0, sessionKey);
// Register the file you are checking
RmRegisterResources(sessionHandle, 1, filePathArray, 0, NULL, 0, NULL);
// Get all processes that have that file open.
RmGetList(sessionHAndle, &nProcInfoNeeded, &nProcInfo, processes, &rebootReason);
RmEndSession(sessionHandle);
처리 에서, 윈도우 시스 인 터널 . 이것은 Microsoft에서 제공하는 무료 명령 줄 유틸리티입니다.
그것을 실행하고 결과를 구문 분석 할 수 있습니다.
다음은 Iain Ballard의 코드 덤프를 기반으로 생성되었습니다. 그것은됩니다 깨진 : 그것은 것 때때로 당신이 핸들의 이름을 검색 할 때까지 잠급니다. 이 코드에는 해당 문제에 대한 해결 방법이 포함되어 있지 않으며 .NET은 몇 가지 옵션을 남깁니다 Thread.Abort
. 현재 네이티브 메서드에있는 스레드를 더 이상 중단 할 수 없습니다.
따라서 해당 고지 사항과 함께 32 비트 및 64 비트 모드 모두에서 작동하도록 조정 된 핸들을 검색하는 코드가 있습니다 (비정기적인 잠금은 제외).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
namespace BrokenHandleRetrieval
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Enumerates open handles.");
Console.WriteLine("This *will* lock up on calling HandleInfo.Name from time to time. Thread.Abort() won't help.");
foreach (var hi in HandleUtil.GetHandles().Where(hi => hi.Type == HandleType.File))
Console.WriteLine("pid: " + hi.ProcessId + ", name: " + hi.Name);
}
}
public enum HandleType
{
Unknown,
Other,
File, Directory, SymbolicLink, Key,
Process, Thread, Job, Session, WindowStation,
Timer, Desktop, Semaphore, Token,
Mutant, Section, Event, KeyedEvent, IoCompletion, IoCompletionReserve,
TpWorkerFactory, AlpcPort, WmiGuid, UserApcReserve,
}
public class HandleInfo
{
public int ProcessId { get; private set; }
public ushort Handle { get; private set; }
public int GrantedAccess { get; private set; }
public byte RawType { get; private set; }
public HandleInfo(int processId, ushort handle, int grantedAccess, byte rawType)
{
ProcessId = processId;
Handle = handle;
GrantedAccess = grantedAccess;
RawType = rawType;
}
private static Dictionary<byte, string> _rawTypeMap = new Dictionary<byte, string>();
private string _name, _typeStr;
private HandleType _type;
public string Name { get { if (_name == null) initTypeAndName(); return _name; } }
public string TypeString { get { if (_typeStr == null) initType(); return _typeStr; } }
public HandleType Type { get { if (_typeStr == null) initType(); return _type; } }
private void initType()
{
if (_rawTypeMap.ContainsKey(RawType))
{
_typeStr = _rawTypeMap[RawType];
_type = HandleTypeFromString(_typeStr);
}
else
initTypeAndName();
}
bool _typeAndNameAttempted = false;
private void initTypeAndName()
{
if (_typeAndNameAttempted)
return;
_typeAndNameAttempted = true;
IntPtr sourceProcessHandle = IntPtr.Zero;
IntPtr handleDuplicate = IntPtr.Zero;
try
{
sourceProcessHandle = NativeMethods.OpenProcess(0x40 /* dup_handle */, true, ProcessId);
// To read info about a handle owned by another process we must duplicate it into ours
// For simplicity, current process handles will also get duplicated; remember that process handles cannot be compared for equality
if (!NativeMethods.DuplicateHandle(sourceProcessHandle, (IntPtr) Handle, NativeMethods.GetCurrentProcess(), out handleDuplicate, 0, false, 2 /* same_access */))
return;
// Query the object type
if (_rawTypeMap.ContainsKey(RawType))
_typeStr = _rawTypeMap[RawType];
else
{
int length;
NativeMethods.NtQueryObject(handleDuplicate, OBJECT_INFORMATION_CLASS.ObjectTypeInformation, IntPtr.Zero, 0, out length);
IntPtr ptr = IntPtr.Zero;
try
{
ptr = Marshal.AllocHGlobal(length);
if (NativeMethods.NtQueryObject(handleDuplicate, OBJECT_INFORMATION_CLASS.ObjectTypeInformation, ptr, length, out length) != NT_STATUS.STATUS_SUCCESS)
return;
_typeStr = Marshal.PtrToStringUni((IntPtr) ((int) ptr + 0x58 + 2 * IntPtr.Size));
_rawTypeMap[RawType] = _typeStr;
}
finally
{
Marshal.FreeHGlobal(ptr);
}
}
_type = HandleTypeFromString(_typeStr);
// Query the object name
if (_typeStr != null && GrantedAccess != 0x0012019f && GrantedAccess != 0x00120189 && GrantedAccess != 0x120089) // don't query some objects that could get stuck
{
int length;
NativeMethods.NtQueryObject(handleDuplicate, OBJECT_INFORMATION_CLASS.ObjectNameInformation, IntPtr.Zero, 0, out length);
IntPtr ptr = IntPtr.Zero;
try
{
ptr = Marshal.AllocHGlobal(length);
if (NativeMethods.NtQueryObject(handleDuplicate, OBJECT_INFORMATION_CLASS.ObjectNameInformation, ptr, length, out length) != NT_STATUS.STATUS_SUCCESS)
return;
_name = Marshal.PtrToStringUni((IntPtr) ((int) ptr + 2 * IntPtr.Size));
}
finally
{
Marshal.FreeHGlobal(ptr);
}
}
}
finally
{
NativeMethods.CloseHandle(sourceProcessHandle);
if (handleDuplicate != IntPtr.Zero)
NativeMethods.CloseHandle(handleDuplicate);
}
}
public static HandleType HandleTypeFromString(string typeStr)
{
switch (typeStr)
{
case null: return HandleType.Unknown;
case "File": return HandleType.File;
case "IoCompletion": return HandleType.IoCompletion;
case "TpWorkerFactory": return HandleType.TpWorkerFactory;
case "ALPC Port": return HandleType.AlpcPort;
case "Event": return HandleType.Event;
case "Section": return HandleType.Section;
case "Directory": return HandleType.Directory;
case "KeyedEvent": return HandleType.KeyedEvent;
case "Process": return HandleType.Process;
case "Key": return HandleType.Key;
case "SymbolicLink": return HandleType.SymbolicLink;
case "Thread": return HandleType.Thread;
case "Mutant": return HandleType.Mutant;
case "WindowStation": return HandleType.WindowStation;
case "Timer": return HandleType.Timer;
case "Semaphore": return HandleType.Semaphore;
case "Desktop": return HandleType.Desktop;
case "Token": return HandleType.Token;
case "Job": return HandleType.Job;
case "Session": return HandleType.Session;
case "IoCompletionReserve": return HandleType.IoCompletionReserve;
case "WmiGuid": return HandleType.WmiGuid;
case "UserApcReserve": return HandleType.UserApcReserve;
default: return HandleType.Other;
}
}
}
public static class HandleUtil
{
public static IEnumerable<HandleInfo> GetHandles()
{
// Attempt to retrieve the handle information
int length = 0x10000;
IntPtr ptr = IntPtr.Zero;
try
{
while (true)
{
ptr = Marshal.AllocHGlobal(length);
int wantedLength;
var result = NativeMethods.NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS.SystemHandleInformation, ptr, length, out wantedLength);
if (result == NT_STATUS.STATUS_INFO_LENGTH_MISMATCH)
{
length = Math.Max(length, wantedLength);
Marshal.FreeHGlobal(ptr);
ptr = IntPtr.Zero;
}
else if (result == NT_STATUS.STATUS_SUCCESS)
break;
else
throw new Exception("Failed to retrieve system handle information.");
}
int handleCount = IntPtr.Size == 4 ? Marshal.ReadInt32(ptr) : (int) Marshal.ReadInt64(ptr);
int offset = IntPtr.Size;
int size = Marshal.SizeOf(typeof(SystemHandleEntry));
for (int i = 0; i < handleCount; i++)
{
var struc = (SystemHandleEntry) Marshal.PtrToStructure((IntPtr) ((int) ptr + offset), typeof(SystemHandleEntry));
yield return new HandleInfo(struc.OwnerProcessId, struc.Handle, struc.GrantedAccess, struc.ObjectTypeNumber);
offset += size;
}
}
finally
{
if (ptr != IntPtr.Zero)
Marshal.FreeHGlobal(ptr);
}
}
[StructLayout(LayoutKind.Sequential)]
private struct SystemHandleEntry
{
public int OwnerProcessId;
public byte ObjectTypeNumber;
public byte Flags;
public ushort Handle;
public IntPtr Object;
public int GrantedAccess;
}
}
enum NT_STATUS
{
STATUS_SUCCESS = 0x00000000,
STATUS_BUFFER_OVERFLOW = unchecked((int) 0x80000005L),
STATUS_INFO_LENGTH_MISMATCH = unchecked((int) 0xC0000004L)
}
enum SYSTEM_INFORMATION_CLASS
{
SystemBasicInformation = 0,
SystemPerformanceInformation = 2,
SystemTimeOfDayInformation = 3,
SystemProcessInformation = 5,
SystemProcessorPerformanceInformation = 8,
SystemHandleInformation = 16,
SystemInterruptInformation = 23,
SystemExceptionInformation = 33,
SystemRegistryQuotaInformation = 37,
SystemLookasideInformation = 45
}
enum OBJECT_INFORMATION_CLASS
{
ObjectBasicInformation = 0,
ObjectNameInformation = 1,
ObjectTypeInformation = 2,
ObjectAllTypesInformation = 3,
ObjectHandleInformation = 4
}
static class NativeMethods
{
[DllImport("ntdll.dll")]
internal static extern NT_STATUS NtQuerySystemInformation(
[In] SYSTEM_INFORMATION_CLASS SystemInformationClass,
[In] IntPtr SystemInformation,
[In] int SystemInformationLength,
[Out] out int ReturnLength);
[DllImport("ntdll.dll")]
internal static extern NT_STATUS NtQueryObject(
[In] IntPtr Handle,
[In] OBJECT_INFORMATION_CLASS ObjectInformationClass,
[In] IntPtr ObjectInformation,
[In] int ObjectInformationLength,
[Out] out int ReturnLength);
[DllImport("kernel32.dll")]
internal static extern IntPtr GetCurrentProcess();
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr OpenProcess(
[In] int dwDesiredAccess,
[In, MarshalAs(UnmanagedType.Bool)] bool bInheritHandle,
[In] int dwProcessId);
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool CloseHandle(
[In] IntPtr hObject);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool DuplicateHandle(
[In] IntPtr hSourceProcessHandle,
[In] IntPtr hSourceHandle,
[In] IntPtr hTargetProcessHandle,
[Out] out IntPtr lpTargetHandle,
[In] int dwDesiredAccess,
[In, MarshalAs(UnmanagedType.Bool)] bool bInheritHandle,
[In] int dwOptions);
}
}
Unlocker를 사용해보십시오 . 다른 프로세스에서 잠근 파일을 삭제하려고하면 파일이 잠긴 프로세스가 나열됩니다. 그런 다음 해당 프로세스를 종료하여 파일을 잠금 해제 할 수 있습니다.
솔루션에서 GetProcessesLockingFile () 메서드를 다시 작성합니다. 코드가 작동하지 않았습니다. 예를 들어 "C:\folder1\folder2"
folder2 (process1)에 폴더 와 프로세스가 있습니다. 프로세스가 실행 중이면 GetProcessesLockingFile ()이 나를 반환했습니다 "C:\folder1\folder2"
. 따라서 조건 if (files.Contains(filePath))
=> if ("C:\folder1\folder2".contains("C:\folder1\folder2\process1"))
는 결코 사실이 아닙니다.
그래서 이것은 내 해결책입니다.
public static List<Process> GetProcessesLockingFile(FileInfo file)
{
var procs = new List<Process>();
var processListSnapshot = Process.GetProcesses();
foreach (var process in processListSnapshot)
{
if (process.Id <= 4) { continue; } // system processes
List<string> paths = GetFilesLockedBy(process);
foreach (string path in paths)
{
string pathDirectory = path;
if (!pathDirectory.EndsWith(Constants.DOUBLE_BACKSLASH))
{
pathDirectory = pathDirectory + Constants.DOUBLE_BACKSLASH;
}
string lastFolderName = Path.GetFileName(Path.GetDirectoryName(pathDirectory));
if (file.FullName.Contains(lastFolderName))
{
procs.Add(process);
}
}
}
return procs;
}
또는 문자열 매개 변수 사용 :
public static List<Process> GetProcessesLockingFile(string filePath)
{
var procs = new List<Process>();
var processListSnapshot = Process.GetProcesses();
foreach (var process in processListSnapshot)
{
if (process.Id <= 4) { continue; } // system processes
List<string> paths = GetFilesLockedBy(process);
foreach (string path in paths)
{
string pathDirectory = path;
if (!pathDirectory.EndsWith(Constants.DOUBLE_BACKSLASH))
{
pathDirectory = pathDirectory + Constants.DOUBLE_BACKSLASH;
}
string lastFolderName = Path.GetFileName(Path.GetDirectoryName(pathDirectory));
if (filePath.Contains(lastFolderName))
{
procs.Add(process);
}
}
}
return procs;
}
질문에 완전히 답하려면 커널 모드에서 실행되는 코드가 필요하다고 생각합니다 (하지만 다시 시작 관리자 API를 살펴 보지 않았습니다).
모든 프로세스와 해당 모듈을 열거 할 수 있습니다. 따라서 찾고있는 파일이 모듈 (DLL, EXE, OCX ...) 인 경우 사용할 수 있습니다. 하지만 예를 들어 텍스트 파일이라면 사용자 모드에서는 볼 수없는 커널 핸들 테이블을 봐야합니다. Handle.exe에는이를 수행하기위한 커널 드라이버가 있습니다.
You absolutely don't need to run in Kernel mode (!!!)
It's a Win32 FAQ since Windows 95 (!) (in C, Google groups, Win32) : read the handle table, from User mode of course, and get the PID from the File handle ...
'programing' 카테고리의 다른 글
Maven의 종속성 jar 파일 목록 (0) | 2020.12.04 |
---|---|
3D 포인트 클라우드에서 표면 재구성을위한 강력한 알고리즘? (0) | 2020.12.04 |
TEXT 또는 VARCHAR을 사용하는 것이 더 나은 DATATYPE은 무엇입니까? (0) | 2020.12.04 |
IFRAME의 내용을 지우는 방법은 무엇입니까? (0) | 2020.12.04 |
C # new 문 뒤의 중괄호는 무엇을합니까? (0) | 2020.12.04 |