2011-06-16 40 views
19

this question我已经搜索了解封文件的简单解决方案。 感谢所有的评论和回答,我找到了一个简单的解决方案PInvoking DeleteFile这个PInvoke代码是否正确可靠?

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

我也不知道的是,如果我必须将调用包装在try/catch中,或者只需查看布尔结果就足够了。在我的测试中,没有例外,但我不知道现实世界会发生什么。

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

此代码看起来可靠吗?

更新
我已经发布了一个不完整的方法(该方法疏通没有串联的“Zone.Identifier”文本的文件名)。我现在纠正了这个,对不起。

+1

给谁就给谁经历了盲目downvoted答案:有解释为什么答案是错的礼貌。 – 2011-06-16 18:34:49

+0

@Chris实际上我想知道的是谁提出了2个答案:1)没有什么比给出相同的P/Invoke签名,在一个例子中使用Ansi字符串和2)没有解决这个问题以任何方式。 – 2011-06-16 18:38:37

+0

我做到了,你永远不会抓到我。嗯哈哈。 > :) – 2011-06-16 18:40:13

回答

15

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

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

为失败的功能,最明显的原因是:

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

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

+1

+1对不起,我太急于发布代码,并没有提到,我忘记了在Unblock-method中添加流标识符。我编辑了我的帖子。对不起,我通常尽量不要发布可怜的问题,并浪费时间。下次我会更加小心。 – HCL 2011-06-16 18:50:10

+0

@HCL是的,我有点被抛出。我想我现在已经覆盖了所有的基地! – 2011-06-16 19:04:55

6

我对代码进行了细化。您现在只需将您的启动路径传递给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"); 
} 
1
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 
}