2011-06-16 70 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 
}