Comment puis-je supprimer un fichier qui est verrouillé par un autre processus en C #?

voix
51

Je suis à la recherche d'un moyen de supprimer un fichier qui est verrouillé par un autre processus en utilisant C #. Je soupçonne que la méthode doit être en mesure de trouver quel processus verrouille le fichier (peut - être suivi par les poignées, bien que je ne suis pas sûr de savoir comment faire cela en C #) puis fermez ce processus avant de pouvoir compléter le dossier supprimer à l' aide File.Delete().

Créé 04/08/2008 à 06:45
source utilisateur
Dans d'autres langues...                            


8 réponses

voix
34

Tuer les autres processus ne sont pas une bonne chose à faire. Si votre scénario implique quelque chose comme la désinstallation, vous pouvez utiliser la MoveFileExfonction API pour marquer le fichier pour la suppression lors de la prochaine réinitialisation.

S'il semble que vous avez vraiment besoin de supprimer un fichier en cours d'utilisation par un autre processus, je vous recommande reconsidérant le problème réel avant d'envisager des solutions.

Créé 04/08/2008 à 07:01
source utilisateur

voix
14

La méthode typique est la suivante. Vous avez dit que vous voulez faire en C # Voici donc ce qu'il ...

  1. Si vous ne savez pas quel processus a le fichier verrouillé, vous aurez besoin d'examiner la liste de poignée de chaque processus, et d'interroger chaque poignée pour déterminer si elle identifie le fichier verrouillé. Faire cela en C #, il faudra probablement P / Invoke ou un intermédiaire C ++ / CLI pour appeler les API natives dont vous aurez besoin.
  2. Une fois que vous avez compris ce procédé (es) ont verrouillé le fichier, vous aurez besoin d'injecter en toute sécurité une petite DLL native dans le processus (vous pouvez également injecter une DLL gérée, mais c'est messier, comme vous avez alors commencer ou attacher à l'exécution .NET).
  3. Cette DLL d'amorçage ferme la poignée à l'aide CloseHandle, etc.

Pour l'essentiel: la façon de déverrouiller un fichier « verrouillé » est d'injecter un fichier DLL dans l'espace d'adressage du processus incriminé et fermez vous-même. Vous pouvez le faire en utilisant le code natif ou géré. Peu importe ce que vous allez avoir besoin d'une petite quantité de code natif ou au moins P / Invoke dans le même.

Liens utiles:

Bonne chance!

Créé 04/08/2008 à 07:15
source utilisateur

voix
7

Si vous voulez le faire programatically. Je ne suis pas sûr ... et je vous recommande vraiment contre elle. Si vous dépanner juste des trucs sur votre propre machine, Sysinternals Process Explorer peut vous aider

Exécuter, utilisez la commande Rechercher poignée (je pense qu'il est soit dans le menu trouver ou gérer) et rechercher le nom de votre fichier. Une fois la poignée (s) se trouve, vous pouvez forcer les fermer.

Vous pouvez ensuite supprimer le fichier et ainsi de suite.

Attention , cette opération peut provoquer le programme qui possède les poignées à se comporter bizarrement, comme vous l' avez tiré le tapis proverbiale de sous, mais cela fonctionne bien lorsque vous déboguez votre propre code errante, ou lorsque l' explorateur studio / windows visuelle est d' être la merde et ne pas les libérer handles de fichiers , même si vous avez dit de fermer il y a les âges de fichier ... soupir :-)

Créé 04/08/2008 à 07:12
source utilisateur

voix
4

Conseils d' utilisation Orion Edwards J'ai téléchargé le Sysinternals Process Explorer qui à son tour m'a permis de découvrir que le fichier que j'avais des difficultés la suppression était en fait détenu non par l' Excel.Applicationsobjet que je pensais, mais plutôt le fait que mon code mail envoyer du code C # avait créé un objet de fixation qui a laissé une poignée de ce fichier ouvert.

Une fois que je voyais cela, j'ai appelé tout à fait simple sur la méthode de disposer de l'objet de fixation et la poignée a été libéré.

L'explorateur Sysinternals m'a permis de découvrir ce utilisé conjointement avec le débogueur Visual Studio 2005.

Je recommande vivement cet outil!

Créé 04/03/2009 à 14:43
source utilisateur

voix
4

Vous pouvez utiliser ce programme, poignée , pour trouver ce procédé a le verrou sur votre dossier. Il est un outil de ligne de commande, donc je suppose que vous utilisez la sortie ... Je ne suis pas sûr de le trouver par programme.

Si la suppression du fichier peut attendre, vous pouvez spécifier pour suppression lorsque votre ordinateur démarre Prochaine étape:

  1. Démarrer REGEDT32 (W2K)ou REGEDIT (WXP)et accédez à:

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

    • W2K:
      Modifier
      Ajouter une valeur ...
      Type de données: REG_MULTI_SZ
      Nom de la valeur:PendingFileRenameOperations
      OK

    • WXP:
      Modifier
      Nouveau
      Valeur de chaînes multiples
      enter
      PendingFileRenameOperations

  3. Dans la zone de données, entrez "\??\" + filenameà supprimer. LFN peuvent être entrées sans être intégré entre guillemets. Pour supprimer C:\Long Directory Name\Long File Name.exe, entrez les données suivantes:

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

    Ensuite , appuyez sur OK.

  4. Le « nom du fichier de destination » est une chaîne nulle (zéro). Il est entré comme suit:

    • W2K:
      Modifier
      binaire
      sélectionnez Format de données: Hex
      cliquez à la fin de la chaîne hexagonale
      entrez 0000 (quatre zéros)
      OK

    • WXP:
      un clic droit sur la valeur
      choisissez « Modifier les données binaires »
      cliquez à la fin de la chaîne hexagonale
      entrez 0000 (quatre zéros)
      OK

  5. Fermer REGEDT32/REGEDITet redémarrer pour supprimer le fichier.

(Shamelessly volé une tribune au hasard , pour l'amour de la postérité.)

Créé 04/08/2008 à 06:59
source utilisateur

voix
3

Cela semble prometteur. Une façon de tuer le handle de fichier ....

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

Créé 25/02/2009 à 18:41
source utilisateur

voix
3

Oh, un grand bidouille j'employé il y a quelques années, est que Windows ne vous permet pas de supprimer des fichiers, mais il ne vous laisse passer les.

Pseudo-tri de code:

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

Lorsque les applications redémarrés (notez que nous n'avons pas besoin de redémarrer la machine), ils ont chargé le nouveau mfc42.dll, et tout allait bien. Cela, couplé avec PendingFileOperationspour supprimer l'ancien la prochaine fois que tout le système redémarré, a très bien fonctionné .

Créé 04/08/2008 à 07:14
source utilisateur

voix
2

Vous pouvez utiliser le code que vous fournissez le chemin complet du fichier, et il retournera un List<Processes>rien de verrouillage ce fichier:

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

Ensuite, itérer la liste des processus et de les fermer et supprimer les fichiers:

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

Et selon que le fichier se trouve sur l'ordinateur local:

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

ou un ordinateur de réseau:

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

Références:
Comment puis-je savoir quel processus est le verrouillage d' un fichier en utilisant .NET?

Supprimer un répertoire où quelqu'un a ouvert un dossier

Créé 27/01/2017 à 20:45
source utilisateur

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