Hvordan sletter jeg en fil som er låst av en annen prosess i C #?

stemmer
52

Jeg leter etter en måte å slette en fil som er låst av en annen prosess ved hjelp av C #. Jeg mistenker at metoden må være i stand til å finne hvilken prosess låser filen (kanskje ved å spore håndtakene, selv om jeg ikke er sikker på hvordan du gjør dette i C #) og deretter lukke den prosessen før du kan fullføre filen slette med File.Delete().

Publisert på 04/08/2008 klokken 05:45
kilden bruker
På andre språk...                            


8 svar

stemmer
34

Killing andre prosesser er ikke en sunn ting å gjøre. Hvis scenariet innebærer noe som avinstallering, kan du bruke MoveFileExAPI-funksjonen for å markere filen for sletting ved neste omstart.

Hvis det viser seg at du virkelig trenger å slette en fil er i bruk av en annen prosess, vil jeg anbefale re-vurderer selve problemet før du vurderer noen løsninger.

Svarte 04/08/2008 kl. 06:01
kilden bruker

stemmer
15

Den typiske metode er som følger. Du har sagt at du ønsker å gjøre dette i C # så her går ...

  1. Hvis du ikke vet hvilken prosess som har filen låst, må du undersøke håndtaket liste hver prosess-tallet, og spørre hvert håndtak for å fastslå om det identifiserer låst fil. Å gjøre dette i C # vil trolig kreve P / Invoke eller en mellommann C ++ / CLI å kalle de innfødte APIer du trenger.
  2. Når du har funnet ut hvilken prosess (es) har filen låst, må du trygt injisere en liten innfødt DLL inn i prosessen (du kan også injisere en administrert DLL, men dette er Messier, som du da må starte eller feste til den NET kjøretids).
  3. Det bootstrap DLL lukkes deretter ved hjelp av håndtaket CloseHandle, etc.

Hovedsak: måten å låse opp en "låst" filen er å injisere en DLL-fil til den fornærmende prosessen adresse plass og lukk det selv. Du kan gjøre dette ved hjelp av innfødte eller forvaltet kode. Uansett hva, du kommer til å trenge en liten mengde av egen kode eller minst P / Invoke inn det samme.

Hjelpsomme linker:

Lykke til!

Svarte 04/08/2008 kl. 06:15
kilden bruker

stemmer
7

Hvis du ønsker å gjøre det auto. Jeg er ikke sikker ... og jeg vil virkelig anbefale mot den. Hvis du bare feilsøking ting på din egen maskin, Sysinternals Process Explorer kan hjelpe deg

Kjør den, bruker Finn Handle kommando (jeg tror det er enten i finne eller håndtere menyen), og søk etter navnet på filen. Når håndtaket (e) er funnet, kan du tvangsflyttet lukke dem.

Du kan deretter slette filen og så videre.

Pass opp , gjør dette kan føre til at programmet som eier håndtakene for å oppføre seg merkelig, som du nettopp har trukket den velkjente teppet ut fra under det, men det fungerer godt når du feilsøker ditt eget ærend kode, eller når Visual Studio / windows explorer er å være dritt og ikke slippe filen håndterer selv om du fortalte dem til å lukke filen for lenge siden ... sukk :-)

Svarte 04/08/2008 kl. 06:12
kilden bruker

stemmer
4

Ved hjelp av Orion Edwards råd jeg lastet ned Sysinternals Process Explorer som igjen tillot meg å oppdage at filen jeg hadde problemer sletting var faktisk blir holdt ikke av Excel.Applicationsobjektet tenkte jeg, men heller det faktum at min C # -kode send mail koden hadde skapt et vedlegg objekt som forlot et håndtak til denne filen åpen.

Når jeg så dette, jeg ganske enkelt kalt på kast metoden i vedlegg objekt, og håndtaket ble utgitt.

Den Sysinternals explorer tillatt meg å oppdage dette brukes sammen med Visual Studio 2005 debugger.

Jeg anbefaler dette verktøyet!

Svarte 04/03/2009 kl. 13:43
kilden bruker

stemmer
4

Du kan bruke dette programmet, håndtak , for å finne hvilken prosess har låsen på filen. Det er et kommandolinjeverktøy, så jeg antar du bruker output fra det ... Jeg er ikke sikker på om å finne det programmatisk.

Hvis du sletter filen kan vente, kan du angi det for sletting når datamaskinen neste starter opp:

  1. Starte REGEDT32 (W2K)eller REGEDIT (WXP)og gå til:

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

    • W2K:
      Rediger
      Legg til verdi ...
      Datatype: REG_MULTI_SZ
      Verdi Navn:PendingFileRenameOperations
      OK

    • WXP:
      Edit
      New
      Multistrengverdi
      enter
      PendingFileRenameOperations

  3. I dataområdet, skriv "\??\" + filenamesom skal slettes. LFNs kan legges inn uten å bli innebygd i anførselstegn. For å slette C:\Long Directory Name\Long File Name.exe, skrive inn følgende data:

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

    Deretter trykker OK.

  4. Den "destinasjon filnavn" er en null (null) streng. Det legges inn som følger:

    • W2K:
      Edit
      Binary
      velg Data Format: Hex
      klikk på slutten av hex streng
      angir 0000 (fire nuller)
      OK

    • WXP:
      Høyreklikk verdien
      velg "Endre Binary data"
      klikk på slutten av hex streng
      angir 0000 (fire nuller)
      OK

  5. Lukk REGEDT32/REGEDITog omstart for å slette filen.

(Shamelessly stjålet fra noen tilfeldig forum , for ettertiden skyld.)

Svarte 04/08/2008 kl. 05:59
kilden bruker

stemmer
3

Du kan bruke kode som du leverer den fullstendige filbanen til, og det vil returnere en List<Processes>noe låsing denne filen:

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;
    }
}

Deretter gjenta listen over prosesser og lukke dem og slette filene:

    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);
    }

Og avhengig av om filen er på den lokale datamaskinen:

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

eller en datamaskin i nettverket:

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();
        }
    }
}

Referanser:
Hvordan finner jeg ut hvilken prosess er å låse en fil ved hjelp av .NET?

Slett en katalog der noen har åpnet en fil

Svarte 27/01/2017 kl. 20:45
kilden bruker

stemmer
3

Dette ser lovende ut. En måte å drepe filen håndtaket ....

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

Svarte 25/02/2009 kl. 17:41
kilden bruker

stemmer
3

Oh, en stor hack jeg ansatt år siden, er at Windows ikke vil la deg slette filer, men det betyr at du flytter dem.

Pseudo-sort-of-kode:

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

Når programmene startet på nytt (merk at vi ikke trenger å starte maskinen på nytt), lastet de nye mfc42.dll, og alt var vel. Det, kombinert med PendingFileOperationså slette den gamle neste gang hele systemet startes på nytt, virket ganske bra.

Svarte 04/08/2008 kl. 06:14
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more