2009-11-19 215 views
5

我有一种情况,人们连接到共享上的文件,并阻止我覆盖文件。我正在尝试编写一个方法,它将查看我提供的filePath是否当前被锁定,并关闭此资源的网络会话。使用C关闭打开的文件

我查看了ADSI Winnt提供程序,但是Resources.Remove成员未实现。然后,我看着Win32_ServerSession,同时我可以使用Delete成员,它会杀死给定用户的所有资源。我需要弄清楚如何更具体。

我一直在走GetRelationsShips和属性,但我现在只是难住。

+0

喜克里斯。在我看来,在网络上自动部署读/写资源文件总是错误的。唯一的情况是我会这样做,就是如果这些文件本身全部是只读的设计 - 然后再次作为设置开发人员,我们总是面对“只是做”的心态。我使用C#和FileSystemWatcher实现了用于写入网络共享中文件的检查器。它从来没有工作,因为提出的事件是不同的,取决于下面的硬件。这里有一些细节:http://www.codeproject。com/KB/files/AdvancedFileSystemWatcher.aspx?msg = 2982716 – 2010-11-29 23:32:45

+0

实际上,这个问题与部署/设置没有任何关系。这是一种自动构建尝试将文件归档到已知文件夹并且存在阻塞的文件的情况。 – 2012-04-01 22:01:00

+0

我不知道你是否可以做到这一点 - 如果你可以明智吗? 替代 - 你能以某种方式向用户发送消息 - 电子邮件,通过应用程序等? – 2009-11-19 03:37:44

回答

1

这样做很难考虑这样做的所有后果,因为您无法预测当前锁定文件的应用程序的结果行为。

有没有其他方法可以做到这一点?例如,您是否必须立即覆盖文件,或者您是否有一些外部进程每隔几分钟不断尝试覆盖文件,直到成功为止?

+0

我会给你“不要那样做”的答案。 :-) 我知道我没有给出为什么我需要这样做的原因,但他们是真实的。尽管我很幸运地把任务交给了别人。 :-) – 2010-03-20 14:30:26

1

我面临同样的问题。 到目前为止,我知道,要做到这一点的唯一方法,是使用的Win32 API:

 
[DllImport("Netapi32.dll", SetLastError=true, CharSet = CharSet.Unicode)] 
public static extern int NetFileClose(string servername, int id); 

我做了简短的尝试意识到这一点,我可以枚举文件正确, 但在我的代码 - 我有只是看看它 - 关闭文件 的代码被设置为一个评论。如果你想尝试一下,我可以发送一个库[NetFileXXX的包装器]和一个简短的演示,但正如我所说:我从来没有关闭过一个文件。但这可能是一个很简单的方法。

我不知道,如何在交换文件计算器现在:-(

BR - ?!?mabra

1

您可以使用您提供完整的文件路径的代码,它会返回的任何一个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); 
      } 
     } 
    } 

,并根据该文件是否在本地计算机上:

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

参考文献:
How do I find out which process is locking a file using .NET?

Delete a directory where someone has opened a file