这个PInvoke代码是否正确可靠?

在这个问题中,我搜索了一个解锁文件的简单解决方案。 感谢所有的评论和回答,我找到了PInvoking DeleteFile的简单解决方案。

它工作,但因为我从来没有通过PInvoke(Win32)使用文件操作,我不知道是否有一些陷阱或是否有另一种方法调用DeleteFile来删除文件的备用流。

我还不知道的是,我是否必须在try / catch中包装调用,或者仅仅查看布尔结果就足够了。 在我的测试中,没有提出exception,但我不知道在现实世界中会发生什么。

 public class FileUnblocker { [DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool DeleteFile(string name ); public bool Unblock(string fileName) { return DeleteFile(fileName+ ":Zone.Identifier"); } } 

这段代码看起来可靠吗?

更新
我发布了一个不完整的方法(unblock方法没有将“Zone.Identifier”文字连接到文件名)。 我现在纠正了这个,抱歉。

调用本机方法永远不会引发exception。 如果文件删除失败,无论出于何种原因,对DeleteFile的调用将返回false。

你的P / Invoke代码很好。 您正确使用Unicode字符,将SetLastError设置为true并且参数编组正确。 要检查错误,请查找DeleteFile的布尔值返回值。 如果为false(即调用失败),则调用Marshal.GetLastWin32Error以找出Win32错误代码。

function失败的最明显原因是:

  1. 该文件不存在。
  2. 备用流不存在。
  3. 该进程没有足够的权限来删除备用流。

对于1和2,将返回错误代码ERROR_FILE_NOT_FOUND 。 对于3,您将收到错误代码ERROR_ACCESS_DENIED

我对代码做了一个小改进。 您现在可以将启动路径传递给UnblockPath()函数,它将自动取消阻止可执行文件的所有文件和子目录文件。 它可以进一步细化,只搜索.exe,.dll等。

 [DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool DeleteFile(string name); public static void UnblockPath(string path) { string[] files = System.IO.Directory.GetFiles(path); string[] dirs = System.IO.Directory.GetDirectories(path); foreach (string file in files) { UnblockFile(file); } foreach (string dir in dirs) { UnblockPath(dir); } } public static bool UnblockFile(string fileName) { return DeleteFile(fileName + ":Zone.Identifier"); } 
 using System; using System.IO; using System.Runtime.InteropServices; using System.Windows.Forms; internal class Zone { public static void WriteAlternateStream(string path, string text) { const int GENERIC_WRITE = 1073741824; const int FILE_SHARE_WRITE = 2; const int OPEN_ALWAYS = 4; var stream = CreateFileW(path, GENERIC_WRITE, FILE_SHARE_WRITE, IntPtr.Zero, OPEN_ALWAYS, 0, IntPtr.Zero); using (FileStream fs = new FileStream(stream, FileAccess.Write)) { using (StreamWriter sw = new StreamWriter(fs)) { sw.Write(text); } } } public static void Id() { var x = Application.ExecutablePath + ":Zone.Identifier"; WriteAlternateStream(x, "[ZoneTransfer]\r\nZoneId=3"); } # region Imports [DllImport("kernel32.dll", EntryPoint = "CreateFileW")] public static extern System.IntPtr CreateFileW( [InAttribute()] [MarshalAsAttribute(UnmanagedType.LPWStr)] string lpFileName, uint dwDesiredAccess, uint dwShareMode, [InAttribute()] IntPtr lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, [InAttribute()] IntPtr hTemplateFile ); #endregion }