2009-11-19 114 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