Является ли этот код PInvoke правильным и надежным? - PullRequest
21 голосов
/ 16 июня 2011

В этот вопрос Я искал простое решение для разблокировки файлов. Благодаря всем комментариям и ответам я нашел простое решение с помощью 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» с именем файла). Я исправил это сейчас, извините.

Ответы [ 3 ]

18 голосов
/ 16 июня 2011

Вызов собственного метода никогда не вызовет исключения. Если по какой-либо причине удаление файла завершается неудачно, вызов DeleteFile возвращает false.

Ваш код P / Invoke хорош. Вы правильно используете символы Юникода, устанавливая SetLastError в true, и маршаллинг параметров правильный. Чтобы проверить наличие ошибок, ищите значение логического возврата от DeleteFile. Если оно ложно (т.е. вызов не удался), то позвоните Marshal.GetLastWin32Error, чтобы узнать код ошибки Win32.

Наиболее очевидные причины сбоя функции:

  1. Файл не существует.
  2. Альтернативного потока нет.
  3. У процесса недостаточно прав для удаления альтернативного потока.

Для 1 и 2 будет возвращен код ошибки ERROR_FILE_NOT_FOUND. Для 3 вам будет выдан код ошибки ERROR_ACCESS_DENIED.

6 голосов
/ 21 января 2014

Я внес небольшое уточнение в код. Теперь вы можете просто передать путь запуска функции 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 голос
/ 21 июля 2016
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
}
...