Wie lösche ich eine Datei, die von einem anderen Prozess in C # gesperrt ist?

stimmen
51

Ich bin auf der Suche nach einer Möglichkeit , eine Datei zu löschen , die von einem anderen Prozess gesperrt ist mit C #. Ich vermute , dass das Verfahren in der Lage sein muss , finden , welchen Prozess die Datei blockiert (vielleicht durch die Griffe Tracking, obwohl ich nicht sicher bin , wie dies in c # tun) , dann diesen Prozess schließen , bevor Sie in der Lage , die Datei löschen abzuschließen File.Delete().

Veröffentlicht am 04/08/2008 um 06:45
quelle vom benutzer
In anderen Sprachen...                            


8 antworten

stimmen
34

Andere Prozesse zu töten ist keine gesunde Sache zu tun. Wenn Ihr Szenario etwas wie Deinstallation beinhaltet, könnten Sie die verwenden MoveFileExAPI - Funktion die Datei zum Löschen beim nächsten Neustart zu markieren.

Wenn es scheint, dass Sie wirklich eine Datei von einem anderen Prozess löschen müssen, würde ich wieder unter Berücksichtigung der tatsächlichen Problem vor der Prüfung alle Lösungen empfehlen.

Beantwortet am 04/08/2008 um 07:01
quelle vom benutzer

stimmen
14

Das typische Verfahren ist wie folgt. Sie haben gesagt, Sie dies in C # tun wollen geht so hier ...

  1. Wenn Sie nicht wissen, welcher Prozess die Datei gesperrt hat, müssen Sie jeden Prozess Griff Liste prüfen und abfragen jeden Griff, um zu bestimmen, ob es die gesperrte Datei identifiziert. Auf diese in C # erfordert wahrscheinlich P / Invoke oder einen Vermittler C ++ / CLI die nativen APIs aufrufen, die Sie benötigen.
  2. Sobald Sie herausgefunden haben, welche (s) Verfahren hat die gesperrte Datei, müssen Sie sicher eine kleine nativen DLL in den Prozess injizieren (Sie können auch eine verwaltete DLL injizieren, aber dies ist chaotischer, wie Sie starten müssen oder heften sich an die .NET-Laufzeit).
  3. Die Bootstrap-DLL schließt dann mit dem Griff Closehandle usw.

Im Wesentlichen: die Art und Weise eine „gesperrt“ Datei zu entsperren ist eine DLL-Datei in die säumigen Prozess-Adressraum zu injizieren und diese selbst schließen. Sie können diesen mit nativen oder verwalteten Code tun. Egal was passiert, wirst du eine kleine Menge an nativen Code oder zumindest P / Invoke in denselben müssen.

Hilfreiche Links:

Viel Glück!

Beantwortet am 04/08/2008 um 07:15
quelle vom benutzer

stimmen
7

Wenn Sie wollen , dass es programmatisch zu tun. Ich bin nicht sicher ... und ich würde wirklich empfehlen dagegen. Wenn Sie nur Sachen auf Ihrem eigenen Rechner zur Fehlerbehebung Sysinternals Process Explorer können Sie helfen

Führen Sie es, verwenden Sie den Befehl finden Handle (ich glaube, es ist entweder in dem finden oder Griff-Menü), und für den Namen der Datei suchen. Sobald der Griff (e) gefunden wird, können Sie schließen sie mit Gewalt.

Anschließend können Sie die Datei löschen und so weiter.

Hüten Sie sich vor , dies zu tun kann das Programm verursachen , die die Griffe besitzen seltsam verhalten, wie Sie gerade aus dem sprichwörtlichen Teppich unter ihn gezogen haben, aber es funktioniert gut , wenn Sie Ihren eigenen verirrten Code debuggen, oder wenn Visual Studio / Windows Explorer ist Mist und nicht die Datei ist die Freigabe behandelt , obwohl man sie vor die Datei im Alter zu schließen , sagte ... seufz :-)

Beantwortet am 04/08/2008 um 07:12
quelle vom benutzer

stimmen
4

Mit Orion Edwards Rat heruntergeladen ich den Sysinternals Explorer - Prozess , der wiederum erlaubte mir , dass die Datei zu entdecken , ich Schwierigkeiten hatte in der Tat zu löschen war nicht von dem gehalten wurde Excel.ApplicationsGegenstand dachte ich, sondern die Tatsache , dass meine C # -Code Mail Code hatte erstellt ein Anlage - Objekt , das einen Griff in diese Datei offen gelassen.

Als ich das sah, ich ganz einfach auf der Dispose-Methode des Attachment-Objekts aufgerufen, und der Griff freigegeben wurde.

Die Sysinternals-Explorer erlaubt mir dies in Verbindung mit dem Visual Studio 2005-Debugger verwendet zu entdecken.

Ich empfehle dieses Werkzeug sehr!

Beantwortet am 04/03/2009 um 14:43
quelle vom benutzer

stimmen
4

Sie können dieses Programm verwenden, Handle , zu finden , welcher Prozess die Sperre auf die Dateien hat. Es ist ein Kommandozeilen - Tool, so dass ich glaube , dass Sie die Ausgabe von dem verwenden ... Ich bin nicht sicher über es programmatisch zu finden.

Wenn die Datei zu löschen warten können, können Sie es zum Löschen angeben, wenn der Computer das nächste Mal startet:

  1. Starten Sie REGEDT32 (W2K)oder REGEDIT (WXP)und navigieren Sie zu:

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

    • W2K:
      Bearbeiten
      Wert hinzufügen ...
      Datentyp: REG_MULTI_SZ
      Wertname:PendingFileRenameOperations
      OK

    • WXP:
      Bearbeiten
      Neuer
      Multi-String Value
      enter
      PendingFileRenameOperations

  3. Im Bereich Daten eingeben "\??\" + filenamegelöscht werden. LFN kann , ohne eingebettet in Anführungszeichen eingegeben werden. So löschen C:\Long Directory Name\Long File Name.exe, geben Sie die folgenden Daten:

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

    Dann drücken OK.

  4. Der „Zieldateiname“ ist eine Null (Null) Zeichenfolge. Es wird wie folgt eingegeben:

    • W2K:
      Bearbeiten
      Binary
      wählen Datenformat: Hex
      Klick am Ende des Hex - String
      geben Sie 0000 (vier Nullen)
      OK

    • WXP:
      Rechtsklick auf den Wert
      „Modify Binary Data“ wählen
      klicken Sie am Ende des Hex - String
      geben Sie 0000 (vier Nullen)
      OK

  5. Schließen REGEDT32/REGEDITund Neustart die Datei zu löschen.

(Schamlos gestohlen ein zufälliges Forum , für die Nachwelt willen.)

Beantwortet am 04/08/2008 um 06:59
quelle vom benutzer

stimmen
3

Das sieht vielversprechend aus. Ein Weg, um die Datei-Handle zu töten ....

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

Beantwortet am 25/02/2009 um 18:41
quelle vom benutzer

stimmen
3

Oh, ein großer Hack , den ich vor Jahren beschäftigt, ist , dass Windows lassen Sie nicht löschen Dateien, aber es können Sie bewegen sie.

Pseudo-Art-of-Code:

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

Wenn die Neustart - Anwendungen (beachten Sie, wir müssen nicht den Computer neu zu starten), luden sie die neue mfc42.dll, und alles war gut. Dies, gepaart mit PendingFileOperationsden alten das nächste Mal das gesamte System neu gestartet wurde , funktionierte ziemlich gut zu löschen.

Beantwortet am 04/08/2008 um 07:14
quelle vom benutzer

stimmen
2

Sie können Code verwenden , die Sie den vollständigen Dateipfad liefern, und es wird eine Rückkehr List<Processes>von etwas , das Sperren von Dateien:

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

Dann durchlaufen die Liste der Prozesse und schließen Sie sie und löschen Sie die Dateien:

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

Und je nachdem, ob die Datei auf dem lokalen Computer ist:

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

oder ein Netzwerk-Computer:

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

Referenzen:
Wie finde ich heraus , welcher Prozess eine Datei Sperren .NET?

Löscht ein Verzeichnis, in dem jemand eine Datei geöffnet hat,

Beantwortet am 27/01/2017 um 20:45
quelle vom benutzer

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