c# - ¿Es este código de PInvoke correcto y confiable?
.net .net-4.0 (3)
En esta pregunta he buscado una solución simple para desbloquear archivos. Gracias a todos los comentarios y respuestas, he encontrado una solución simple mediante PInvoking DeleteFile
.
Funciona, pero como nunca he usado operaciones de archivos a través de PInvoke (Win32), no sé si hay algunas trampas o si hay otro método para llamar a DeleteFile
para eliminar la secuencia alternativa de un archivo.
Lo que tampoco sé es si tengo que ajustar la llamada en un try / catch o si es suficiente solo para ver el resultado booleano. En mis pruebas, no se generaron excepciones, pero no sé qué sucederá en el mundo real.
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");
}
}
¿Este código parece confiable?
Actualizar
Había publicado un método incompleto (el método de desbloqueo no concatenaba el literal "Zone.Identifier" con el nombre del archivo). Lo he corregido ahora, lo siento.
Hice un pequeño refinamiento al código. Ahora puede pasar su ruta de inicio a la función UnblockPath () y automáticamente desbloqueará todos los archivos y archivos de subdirectorio para su ejecutable. Se podría refinar aún más para buscar solo .exe, .dll, etc.
[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");
}
Llamar al método nativo nunca generará una excepción. Si la eliminación del archivo falla, por cualquier motivo, la llamada a DeleteFile
devuelve false.
Su código P / Invoke es bueno. Está utilizando correctamente los caracteres Unicode, estableciendo SetLastError
en true
y el ordenamiento de parámetros es correcto. Para verificar errores, busque el valor del retorno booleano desde DeleteFile
. Si es falso (es decir, falló la llamada), llame a Marshal.GetLastWin32Error
para averiguar el código de error de Win32.
Las causas más obvias para que la función falle son:
- El archivo no existe.
- La secuencia alternativa no está presente.
- El proceso no tiene suficientes derechos para eliminar la secuencia alternativa.
Para 1 y 2 se devolverá un código de error de ERROR_FILE_NOT_FOUND
. Para 3 se le dará un código de error de ERROR_FILE_NOT_FOUND .
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
}