programing

C #에서 다른 프로세스에 의해 잠긴 파일을 어떻게 삭제합니까?

kingscode 2021. 1. 15. 08:27
반응형

C #에서 다른 프로세스에 의해 잠긴 파일을 어떻게 삭제합니까?


C #을 사용하여 다른 프로세스에 의해 잠긴 파일을 삭제하는 방법을 찾고 있습니다. 메서드가 파일을 잠그는 프로세스를 찾을 수 있어야한다고 생각합니다 (아마도 C #에서이 작업을 수행하는 방법을 잘 모르겠지만 핸들을 추적하여). 다음을 사용하여 파일 삭제를 완료하기 전에 해당 프로세스를 닫습니다 File.Delete().


다른 프로세스를 죽이는 것은 건강한 일이 아닙니다. 시나리오에 제거와 같은 것이 포함 된 경우 MoveFileExAPI 기능사용 하여 다음에 재부팅 할 때 파일을 삭제하도록 표시 할 수 있습니다 .

다른 프로세스에서 사용중인 파일을 정말로 삭제해야한다고 생각되면 해결책을 고려하기 전에 실제 문제를 다시 고려하는 것이 좋습니다.


일반적인 방법은 다음과 같습니다. C #에서이 작업을 수행하고 싶다고 말 했으므로 여기에 있습니다.

  1. 파일이 잠긴 프로세스를 모르는 경우 각 프로세스의 핸들 목록을 검사하고 각 핸들을 쿼리하여 잠긴 파일을 식별하는지 확인해야합니다. C #에서이 작업을 수행하려면 필요한 네이티브 API를 호출하기 위해 P / Invoke 또는 중개 C ++ / CLI가 필요할 수 있습니다.
  2. 파일이 잠긴 프로세스를 파악한 후에는 작은 네이티브 DLL을 프로세스에 안전하게 주입해야합니다 (관리되는 DLL을 주입 할 수도 있지만이 작업은 더 복잡합니다. 또는 .NET 런타임에 연결).
  3. 그런 다음 해당 부트 스트랩 DLL은 CloseHandle 등을 사용하여 핸들을 닫습니다.

기본적으로 "잠긴"파일을 잠금 해제하는 방법은 문제가되는 프로세스의 주소 공간에 DLL 파일을 삽입하고 직접 닫는 것입니다. 네이티브 또는 관리 코드를 사용하여이 작업을 수행 할 수 있습니다. 어쨌든 소량의 네이티브 코드 또는 최소한 P / Invoke가 필요합니다.

유용한 링크 :

행운을 빕니다!


프로그래밍 방식으로 수행하려는 경우. 잘 모르겠습니다. 정말 반대하는 것이 좋습니다. 자신의 컴퓨터에서 문제를 해결 하려는 경우 SysInternals Process Explorer 가 도움이 될 수 있습니다.

실행하고 핸들 찾기 명령 (찾기 또는 핸들 메뉴에 있다고 생각)을 사용하고 파일 이름을 검색합니다. 핸들을 찾으면 강제로 닫을 수 있습니다.

그런 다음 파일을 삭제할 수 있습니다.

조심 당신은 그냥 아래에서 속담 러그를 꺼내 한 바와 같이, 이상하게 행동 핸들을 소유하는 프로그램을 일으킬 수 있습니다 이렇게, 그러나 당신이 당신의 자신의 잘못된 코드를 디버깅 할 때 잘 작동 할 때 또는 비주얼 스튜디오 / Windows 탐색기 오래 전에 파일을 닫으라고 말했지만 파일 핸들을 해제하지 않고 쓰레기입니다 ... 한숨 :-)


이 프로그램 Handle을 사용 하여 파일에 잠금이있는 프로세스를 찾을 수 있습니다. 이 도구는 명령 줄 도구이므로 출력을 사용하는 것 같습니다. 프로그래밍 방식으로 찾을 수 있을지 모르겠습니다.

파일 삭제가 기다릴 수 있다면 다음에 컴퓨터를 시작할 때 삭제할 파일을 지정할 수 있습니다.

  1. 시작 REGEDT32 (W2K)하거나 다음 REGEDIT (WXP)으로 이동합니다.

    HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager
    
  2. W2K 및 WXP

    • W2K : 값 추가
      편집
      ...
      데이터 유형 : REG_MULTI_SZ
      값 이름 :PendingFileRenameOperations
      OK

    • WXP :다중 문자열 값
      편집


      enter
      PendingFileRenameOperations

  3. 데이터 영역에 "\??\" + filename삭제할 항목을 입력 합니다. LFN은 따옴표로 묶지 않고 입력 할 수 있습니다. 을 삭제하려면 C:\Long Directory Name\Long File Name.exe다음 데이터를 입력하십시오.

    \??\C:\Long Directory Name\Long File Name.exe
    

    그런 다음을 누릅니다 OK.

  4. "대상 파일 이름"은 null (영) 문자열입니다. 다음과 같이 입력됩니다.

    • W2K : 이진
      편집 데이터 형식 선택 : 16 진수 문자열 끝에서 16 진수 클릭 0000 (4 개의 0) 입력




      OK

    • WXP :
      값을 마우스 오른쪽 버튼으로 클릭하고
      "이진 데이터 수정"을 선택
      합니다. 16 진수 문자열의 끝을 클릭하고
      0000을 입력합니다 (4 개의 0).
      OK

  5. REGEDT32/REGEDIT파일을 삭제하려면 닫고 재부팅하십시오.

( 후손을 위해 임의의 포럼 에서 뻔뻔스럽게 도난당했습니다 .)


Orion Edwards의 조언을 사용하여 Sysinternals Process Explorer다운로드하여 삭제하는 데 어려움을 겪고있는 파일이 실제로 Excel.Applications내가 생각한 개체가 아니라 내 C # 코드 전송 메일 코드가 생성했다는 사실을 발견 할 수있었습니다. 이 파일에 대한 핸들을 열어 둔 Attachment 객체

이것을 본 후에는 Attachment 객체의 dispose 메서드를 아주 간단하게 호출했고 핸들이 해제되었습니다.

Sysinternals 탐색기를 통해 Visual Studio 2005 디버거와 함께 사용되는 것을 발견 할 수있었습니다.

이 도구를 강력히 추천합니다!


오, 내가 몇 년 전에 사용한 한 가지 큰 해킹은 Windows가 파일 삭제할 수는 없지만 파일을 이동할 수 있다는 것입니다.

의사 분류 코드 :

mv %WINDIR%\System32\mfc42.dll %WINDIR\System32\mfc42.dll.old
Install new mfc42.dll
Tell user to save work and restart applications

응용 프로그램이 다시 시작되면 (시스템을 재부팅 할 필요가 없음) 새를로드했으며 mfc42.dll모두 정상적으로 작동했습니다 . PendingFileOperations다음 번에 전체 시스템이 다시 시작될 때 이전 항목을 삭제하는 것과 함께 꽤 잘 작동했습니다.


이것은 유망 해 보입니다. 파일 핸들을 죽이는 방법 ....

http://www.timstall.com/2009/02/killing-file-handles-but-not-process.html


전체 파일 경로를 제공하는 코드를 사용할 수 있으며 List<Processes>해당 파일을 잠그는 모든 항목 을 반환 합니다.

using System.Runtime.InteropServices;
using System.Diagnostics;

static public class FileUtil
{
    [StructLayout(LayoutKind.Sequential)]
    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;

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

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    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,
                                          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>
    static public List<Process> WhoIsLocking(string path)
    {
        uint handle;
        string key = Guid.NewGuid().ToString();
        List<Process> processes = new List<Process>();

        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 ERROR_MORE_DATA = 234;
            uint pnProcInfoNeeded = 0,
                 pnProcInfo = 0,
                 lpdwRebootReasons = RmRebootReasonNone;

            string[] resources = new string[] { 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 == ERROR_MORE_DATA)
            {
                // Create an array to store the process results
                RM_PROCESS_INFO[] processInfo = new RM_PROCESS_INFO[pnProcInfoNeeded];
                pnProcInfo = pnProcInfoNeeded;

                // Get the list
                res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, processInfo, ref lpdwRebootReasons);
                if (res == 0)
                {
                    processes = new List<Process>((int)pnProcInfo);

                    // Enumerate all of the results and add them to the 
                    // list to be returned
                    for (int 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 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 processes;
    }
}

그런 다음 프로세스 목록을 반복하고 닫고 파일을 삭제합니다.

    string[] files = Directory.GetFiles(target_dir);
    List<Process> lstProcs = new List<Process>();

    foreach (string file in files)
    {
        lstProcs = ProcessHandler.WhoIsLocking(file);
        if (lstProcs.Count > 0) // deal with the file lock
        {
            foreach (Process p in lstProcs)
            {
                if (p.MachineName == ".")
                    ProcessHandler.localProcessKill(p.ProcessName);
                else
                    ProcessHandler.remoteProcessKill(p.MachineName, txtUserName.Text, txtPassword.Password, p.ProcessName);
            }
            File.Delete(file);
        }
        else
            File.Delete(file);
    }

파일이 로컬 컴퓨터에 있는지 여부에 따라 :

public static void localProcessKill(string processName)
{
    foreach (Process p in Process.GetProcessesByName(processName))
    {
        p.Kill();
    }
}

또는 네트워크 컴퓨터 :

public static void remoteProcessKill(string computerName, string fullUserName, string pword, string processName)
{
    var connectoptions = new ConnectionOptions();
    connectoptions.Username = fullUserName;  // @"YourDomainName\UserName";
    connectoptions.Password = pword;

    ManagementScope scope = new ManagementScope(@"\\" + computerName + @"\root\cimv2", connectoptions);

    // WMI query
    var query = new SelectQuery("select * from Win32_process where name = '" + processName + "'");

    using (var searcher = new ManagementObjectSearcher(scope, query))
    {
        foreach (ManagementObject process in searcher.Get()) 
        {
            process.InvokeMethod("Terminate", null);
            process.Dispose();
        }
    }
}

References:
How do I find out which process is locking a file using .NET?

Delete a directory where someone has opened a file

ReferenceURL : https://stackoverflow.com/questions/1040/how-do-i-delete-a-file-which-is-locked-by-another-process-in-c

반응형