views:

6349

answers:

6

I've seen several of answers about using Handle or Process Monitor, but I would like to be able to find out in my own code (C#) which process is locking a file.

I have a nasty feeling that I'm going to have to spelunk around in the win32 API, but if anyone has already done this and can put me on the right track, I'd really appreciate the help.

Update

Links to similar questions

+4  A: 

One of the good things about handle.exe is that you can run it as a subprocess and parse the output.

We do this in our deployment script - works like a charm.

orip
Thanks. I might just have to do that.
AJ
+3  A: 

This works for dlls locked by other processes. This routine will not find out for example that a textfile is locked by a wordprocess.

C#:

using System.Management; 
using System.IO;   

static class Module1 
{ 
static internal ArrayList myProcessArray = new ArrayList(); 
private static Process myProcess; 

public static void Main() 
{ 

    string strFile = "c:\\windows\\system32\\msi.dll"; 
    ArrayList a = getFileProcesses(strFile); 
    foreach (Process p in a) { 
        Debug.Print(p.ProcessName); 
    } 
} 


private static ArrayList getFileProcesses(string strFile) 
{ 
    myProcessArray.Clear(); 
    Process[] processes = Process.GetProcesses; 
    int i = 0; 
    for (i = 0; i <= processes.GetUpperBound(0) - 1; i++) { 
        myProcess = processes(i); 
        if (!myProcess.HasExited) { 
            try { 
                ProcessModuleCollection modules = myProcess.Modules; 
                int j = 0; 
                for (j = 0; j <= modules.Count - 1; j++) { 
                    if ((modules.Item(j).FileName.ToLower.CompareTo(strFile.ToLower) == 0)) { 
                        myProcessArray.Add(myProcess); 
                        break; // TODO: might not be correct. Was : Exit For 
                    } 
                } 
            } 
            catch (Exception exception) { 
            } 
            //MsgBox(("Error : " & exception.Message)) 
        } 
    } 
    return myProcessArray; 
} 
}

VB.Net:

Imports System.Management
Imports System.IO

Module Module1
Friend myProcessArray As New ArrayList
Private myProcess As Process

Sub Main()

    Dim strFile As String = "c:\windows\system32\msi.dll"
    Dim a As ArrayList = getFileProcesses(strFile)
    For Each p As Process In a
        Debug.Print(p.ProcessName)
    Next
End Sub


Private Function getFileProcesses(ByVal strFile As String) As ArrayList
    myProcessArray.Clear()
    Dim processes As Process() = Process.GetProcesses
    Dim i As Integer
    For i = 0 To processes.GetUpperBound(0) - 1
        myProcess = processes(i)
        If Not myProcess.HasExited Then
            Try
                Dim modules As ProcessModuleCollection = myProcess.Modules
                Dim j As Integer
                For j = 0 To modules.Count - 1
                    If (modules.Item(j).FileName.ToLower.CompareTo(strFile.ToLower) = 0) Then
                        myProcessArray.Add(myProcess)
                        Exit For
                    End If
                Next j
            Catch exception As Exception
                'MsgBox(("Error : " & exception.Message))
            End Try
        End If
    Next i
    Return myProcessArray
End Function
End Module
Stefan
does this work for all DLLs, or just for .NET DLLs?
AJ
In my Example I use msi.dll wich is not a .Net DLL.
Stefan
+2  A: 

I had issues with the above code. Below is a modified version which seems to work well.

using System;
using System.Collections;
using System.Diagnostics;
using System.Management;
using System.IO;

static class Module1
{
    static internal ArrayList myProcessArray = new ArrayList();
    private static Process myProcess;

    public static void Main()
    {
        string strFile = "c:\\windows\\system32\\msi.dll";
        ArrayList a = getFileProcesses(strFile);
        foreach (Process p in a)
        {
            Debug.Print(p.ProcessName);
        }
    }

    private static ArrayList getFileProcesses(string strFile)
    {
        myProcessArray.Clear();
        Process[] processes = Process.GetProcesses();
        int i = 0;
        for (i = 0; i <= processes.GetUpperBound(0) - 1; i++)
        {
            myProcess = processes[i];
            //if (!myProcess.HasExited) //This will cause an "Access is denied" error
            if (myProcess.Threads.Count > 0)
            {
                try
                {
                    ProcessModuleCollection modules = myProcess.Modules;
                    int j = 0;
                    for (j = 0; j <= modules.Count - 1; j++)
                    {
                        if ((modules[j].FileName.ToLower().CompareTo(strFile.ToLower()) == 0))
                        {
                            myProcessArray.Add(myProcess);
                            break;
                            // TODO: might not be correct. Was : Exit For
                        }
                    }
                }
                catch (Exception exception)
                {
                    //MsgBox(("Error : " & exception.Message)) 
                }
            }
        }

        return myProcessArray;
    }
}
+1  A: 

See if any of the answers for "How does one figure out what process locked a file using c#?" work for you.

outis
+4  A: 

It is very complex way to invoke Win32 from C#.

You should use tool Handle.exe from http://technet.microsoft.com/en-us/sysinternals/bb896655.aspx

After that your C# code have to be the following:

  string fileName = @"c:\aaa.doc";//Path to locked file

  Process tool = new Process();
  tool.StartInfo.FileName = "handle.exe";
  tool.StartInfo.Arguments = fileName;
  tool.StartInfo.UseShellExecute = false;
  tool.StartInfo.RedirectStandardOutput = true;
  tool.Start();   
  tool.WaitForExit();
  string outputTool = tool.StandardOutput.ReadToEnd();

  string matchPattern = @"(?<=\s+pid:\s+)\b(\d+)\b(?=\s+)";
  foreach(Match match in Regex.Matches(outputTool, matchPattern))
  {
   Process.GetProcessById(int.Parse(match.Value)).Kill();
  }
A: 

This doesn't work ! For example try to find which of excel files are opened.

Serge
It may be that excel does not lock the file once it has read it.
AJ