22

この質問では、ファイルのブロックを解除する簡単な解決策を探しました。すべてのコメントと回答のおかげで、 PInvoking による簡単な解決策を見つけましたDeleteFile

動作しますが、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」リテラルをファイル名に連結しませんでした)。今訂正しました、すみません。

4

3 に答える 3

20

ネイティブ メソッドを呼び出しても例外は発生しません。何らかの理由でファイルの削除に失敗した場合、 への呼び出しDeleteFileは false を返します。

あなたの P/Invoke コードは適切です。Unicode 文字を正しく使用しており、パラメータのマーシャリングが正しく設定SetLastErrorされています。trueエラーをチェックするには、 から返されるブール値の値を探しますDeleteFile。false の場合 (つまり、呼び出しが失敗した場合) を呼び出しMarshal.GetLastWin32Errorて、Win32 エラー コードを調べます。

関数が失敗する最も明白な原因は次のとおりです。

  1. ファイルが存在しません。
  2. 代替ストリームが存在しません。
  3. プロセスには、代替ストリームを削除するための十分な権限がありません。

1 と 2 の場合、エラー コードERROR_FILE_NOT_FOUNDが返されます。3 の場合、エラー コード が表示されますERROR_ACCESS_DENIED

于 2011-06-16T18:36:07.113 に答える
8

コードを少し改良しました。起動パスを 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");
}
于 2014-01-21T18:18:44.190 に答える
3
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
}
于 2016-07-21T16:36:41.523 に答える