2011-06-16 21 views
19

En this question 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.¿Este código de PInvoke es correcto y confiable?

Funciona, pero como nunca he usado operaciones de archivos a través de PInvoke (Win32), no sé si hay algún inconveniente o si hay otro método para llamar al DeleteFile para eliminar la secuencia alternativa de un archivo .

Lo que tampoco sé es si tengo que envolver la llamada en un try/catch o si es suficiente con mirar el resultado booleano. En mis pruebas, no se plantearon 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 es confiable?

actualización
que había publicado un método incompleto (el método de desbloqueo no concatenar los "Zone.Identifier" literal al nombre del archivo). Lo he corregido ahora, lo siento.

+1

Para quien pasó por y ciegamente downvoted respuestas: tener la cortesía de explicar por qué la respuesta fue incorrecta. –

+0

@Chris En realidad, me gustaría saber quién votó 2 respuestas que: 1) No hizo nada más que dar firmas P/Invocar equivalentes a eso en la pregunta, y en un caso utilizando cadenas Ansi y 2) No respondió la pregunta de cualquier manera. –

+0

Lo hice, y nunca me atraparás. Muah ja ja ja. > :) –

Respuesta

15

Llamar al método nativo nunca generará una excepción. Si la eliminación del archivo falla, por cualquier razón, la llamada al DeleteFile devuelve falso.

Su código de P/Invoke es bueno. Está utilizando correctamente caracteres Unicode, estableciendo SetLastError en true y la clasificación de parámetros es correcta. Para comprobar si hay errores, busque el valor del retorno booleano de DeleteFile. Si es falso (es decir, la llamada falló), llame al Marshal.GetLastWin32Error para averiguar el código de error de Win32.

Las causas más evidentes de la función a fallar son: no existe

  1. El archivo.
  2. La secuencia alternativa no está presente.
  3. 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_ACCESS_DENIED.

+1

+1 Disculpa, tenía demasiada prisa por publicar el código y no lo he mencionado, que olvidé agregar el identificador de transmisión en el método Desbloquear. He editado mi publicación. Lo siento, generalmente trato de no publicar preguntas pobres y perder el tiempo de las personas. Tendré más cuidado la próxima vez. – HCL

+0

@HCL Sí, fui un poco arrojado. ¡Creo que ya he cubierto todas las bases! –

6

He realizado un pequeño refinamiento del código. Ahora puede simplemente pasar su ruta de inicio a la función UnblockPath() y desbloqueará automáticamente todos los archivos de subdirectorio y de su archivo ejecutable. Podría ser refinado hasta quedar en buscar .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"); 
} 
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 
}