2016-11-07 52 views
2

有什么办法强制关闭Server 2012上特定文件的任何实例?用C关闭Windows Server 2012上的开放网络文件#

为了讨论各种情形,调用链接到文件D:\Shares\Shared\Sharedfile.exe

我有C#代码拷贝最新版本的程序到这个目录,其中往往有在白天使用该程序的人。关闭打开的文件句柄并替换文件运行良好,因为这意味着下次用户打开程序时,它们会有所有最新的更改。

然而,它从服务器上的计算机管理中得到了一点单调,所以我想知道是否有办法从C#代码做到这一点?

我试过这个,但它没有我需要的正确的重载。也许在我可以使用的File课程中有什么?

编辑的C#代码以关闭该文件将主机服务器上运行。

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

[此问题](http://stackoverflow.com/q/10945105/15498)从另一个方向着眼于问题 - 寻找避免在应用程序运行时锁定文件的方法 - 也许这可能是一种替代方法进场? –

回答

2

您可以包装NetFileClose API,这也需要包装的NetFileEnum API。类似这样的:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 
struct FILE_INFO_3 { 
    public int fi3_id; 
    public int fi3_permissions; 
    public int fi3_num_locks; 
    public string fi3_pathname; 
    public string fi3_username; 
} 

static class NativeMethods { 
    [DllImport("netapi32.dll", CharSet = CharSet.Unicode)] 
    public extern static int NetFileEnum(
     string servername, 
     string basepath, 
     string username, 
     int level, 
     out IntPtr bufptr, 
     int prefmaxlen, 
     out int entriesread, 
     out int totalentries, 
     ref IntPtr resume_handle 
    ); 

    [DllImport("netapi32.dll", CharSet = CharSet.Unicode)] 
    public extern static int NetFileClose(string servername, int fileid); 

    [DllImport("netapi32.dll")] 
    public extern static int NetApiBufferFree(IntPtr buffer); 
} 

漂亮难看的签名,对不对?让我们围绕它围绕一点点管理爱。

class RemoteFile { 
    public RemoteFile(string serverName, int id, string path, string userName) { 
     ServerName = serverName; 
     Id = id; 
     Path = path; 
     UserName = userName; 
    } 
    public string ServerName { get; } 
    public int Id { get; } 
    public string Path { get; } 
    public string UserName { get; } 

    public void Close() { 
     int result = NativeMethods.NetFileClose(ServerName, Id); 
     if (result != 0) { 
      // handle error decently, omitted for laziness 
      throw new Exception($"Error: {result}"); 
     } 
    } 
} 

IEnumerable<RemoteFile> EnumRemoteFiles(string serverName, string basePath = null) { 
    int entriesRead; 
    int totalEntries; 
    IntPtr resumeHandle = IntPtr.Zero; 
    IntPtr fileEntriesPtr = IntPtr.Zero; 
    try { 
     int result = NativeMethods.NetFileEnum(
      servername: serverName, 
      basepath: basePath, 
      username: null, 
      level: 3, 
      bufptr: out fileEntriesPtr, 
      prefmaxlen: -1, 
      entriesread: out entriesRead, 
      totalentries: out totalEntries, 
      resume_handle: ref resumeHandle 
     ); 
     if (result != 0) { 
      // handle error decently, omitted for laziness 
      throw new Exception($"Error: {result}"); 
     } 
     for (int i = 0; i != entriesRead; ++i) { 
      FILE_INFO_3 fileInfo = (FILE_INFO_3) Marshal.PtrToStructure(
       fileEntriesPtr + i * Marshal.SizeOf(typeof(FILE_INFO_3)), 
       typeof(FILE_INFO_3) 
      ); 
      yield return new RemoteFile(
       serverName, 
       fileInfo.fi3_id, 
       fileInfo.fi3_pathname, 
       fileInfo.fi3_username 
      ); 
     } 
    } finally { 
     if (fileEntriesPtr != IntPtr.Zero) { 
      NativeMethods.NetApiBufferFree(fileEntriesPtr); 
     } 
    } 
} 

现在关闭一个特定的文件很简单:关闭所有打开的实例。

foreach (var file in EnumRemoteFiles(server, path)) { 
    Console.WriteLine($"Closing {file.Path} at {file.ServerName} (opened by {file.UserName})"); 
    file.Close(); 
} 

请注意,这段代码并没有完全准备好生产,特别是错误处理很糟糕。另外,在我的测试中,看起来文件路径可能会受到一些破坏,具体取决于它们是如何打开的(例如文件显示为C:\\Path\File,在驱动器根目录后面有一个额外的反斜杠),因此您可能需要先进行标准化验证名称。不过,这覆盖了地面。