2011-05-23 23 views
5

Estoy intentando escribir código para extraer el contenido de un archivo CAB; sin embargo, tengo problemas para usar la rutina SetupIterateCabinet.Cómo usar SetupIterateCabinet con C#

véanse los documentos aquí http://msdn.microsoft.com/en-us/library/aa377404(v=vs.85).aspx

me puede importar correctamente como esto

private const uint SPFILENOTIFY_CABINETINFO = 0x00000010; 
    private const uint SPFILENOTIFY_FILEINCABINET = 0x00000011; 
    private const uint SPFILENOTIFY_NEEDNEWCABINET = 0x00000012; 
    private const uint SPFILENOTIFY_FILEEXTRACTED = 0x00000013; 
    private const uint SPFILENOTIFY_FILEOPDELAYED = 0x00000014; 
    private const uint NO_ERROR = 0; 

    private const uint FILEOP_ABORT = 0; 
    private const uint FILEOP_DOIT=      1; 
    private const uint FILEOP_SKIP=      2; 
    private const uint FILEOP_NEWPATH=     4; 

    static void Main(string[] args) 
    { 
     SetupIterateCabinet("c:\\SomeCab.cab", 0, new PSP_FILE_CALLBACK(CallBack), 0); 


     Console.ReadKey(); 
    } 

    [DllImport("SetupApi.dll", CharSet = CharSet.Auto)] 
    public static extern bool SetupIterateCabinet(string cabinetFile, 
         uint reserved, PSP_FILE_CALLBACK callBack, uint context); 

    public delegate uint PSP_FILE_CALLBACK(uint context, uint notification, 
              IntPtr param1, IntPtr param2); 

    private static uint CallBack(uint context, uint notification, IntPtr param1, 
         IntPtr param2) 
    { 
     uint rtnValue = NO_ERROR; 
     switch (notification) 
     { 
      case SPFILENOTIFY_FILEINCABINET: 
       rtnValue = OnFileFound(context, notification, param1, param2); 
       break; 
      case SPFILENOTIFY_FILEEXTRACTED: 
       rtnValue = OnFileExtractComplete(param1); 
       break; 
      case SPFILENOTIFY_NEEDNEWCABINET: 
       rtnValue = NO_ERROR; 
       break; 
     } 
     return rtnValue; 
    } 

    private static uint OnFileExtractComplete(IntPtr param1) 
    { 
     Console.WriteLine("Complete"); 
     return FILEOP_DOIT; 
    } 


    [StructLayout(LayoutKind.Sequential)] 
    struct _FILE_IN_CABINET_INFO { 
     IntPtr NameInCabinet; 
     int FileSize; 
     int Win32Error; 
     int DosDate; 
     int DosTime; 
     int DosAttribs; 
     StringBuilder FullTargetName; 
    }; 

    static private uint OnFileFound(uint context, uint notification, IntPtr param1, IntPtr param2) 
    { 
     _FILE_IN_CABINET_INFO fc = new _FILE_IN_CABINET_INFO() ; 
     Marshal.PtrToStructure(param1, fc); 

     return 1; 
    } 

Sin embargo, el problema surge al intentar procesar el evento SPFILENOTIFY_FILEINCABINET en la devolución de llamada. De acuerdo con la documentación, esta es una estructura, que necesito poner el nombre de donde quiero que se extraiga el archivo. Tengo problemas para descubrir cómo debería ser la estructura y quizás cómo convertir el parámetro en una estructura .

Respuesta

0

Creo que tiene un problema con los valores devueltos de su función de devolución de llamada. En SPFILENOTIFY_FILECABINET, deberías devolver FILEOP_DOIT. Antes de regresar, debe configurar el nombre de archivo en FILE_IN_CABINTE_INFO. Por favor, consulte la publicación del proyecto de código http://www.codeproject.com/Articles/7165/Iterate-and-Extract-Cabinet-File Podría agregar algo de código de muestra más adelante. GTG ahora

EDIT:

Ejemplo de código a continuación. No lo he intentado, pero creo que debería funcionar. Intenté mantener la estructura similar a tu código. Esto debería mostrarle cómo definir la clase FILE_IN_CABINET_INFO y los valores correctos para establecer y devolver en la devolución de llamada

public delegate uint PSP_FILE_CALLBACK(uint context, uint notification, IntPtr param1, IntPtr param2); 

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 
    public class FILE_IN_CABINET_INFO { 
     public String NameInCabinet; 
     public uint FileSize; 
     public uint Win32Error; 
     public ushort DosDate; 
     public ushort DosTime; 
     public ushort DosAttribs; 

     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] 
     public System.String FullTargetName; 
    } 

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 
    public class FILEPATHS { 
     public String Target; 
     public String Source; 
     public uint Win32Error; 
     public uint Flags; 
    } 


    public const uint SPFILENOTIFY_FILEINCABINET = 0x00000011; // The file has been extracted from the cabinet. 
    public const uint SPFILENOTIFY_NEEDNEWCABINET = 0x00000012; // file is encountered in the cabinet. 
    public const uint SPFILENOTIFY_FILEEXTRACTED = 0x00000013; // The current file is continued in the next cabinet. 

    public const uint NO_ERROR = 0; 

    public const uint FILEOP_ABORT = 0; // Abort cabinet processing. 
    public const uint FILEOP_DOIT = 1; // Extract the current file. 
    public const uint FILEOP_SKIP = 2; // Skip the current file. 

    [DllImport("SetupApi.dll", CharSet = CharSet.Auto)] 
    public static extern bool SetupIterateCabinet(string cabinetFile, uint reserved, PSP_FILE_CALLBACK callBack, uint context); 

    [DllImport("Kernel32.dll", CharSet = CharSet.Auto)] 
    public static extern uint GetLastError(); 

    static void Main(string[] args) { 
     IterateCabinet(@"c:\SomeCab.cab"); 
    } 

    public static void IterateCabinet(string filePath) { 
     PSP_FILE_CALLBACK callback = new PSP_FILE_CALLBACK(CallBack); 

     if (!SetupIterateCabinet(filePath, 0, callback, 0)) 
      throw new Win32Exception((int)GetLastError()); 
    } 

    static uint CallBack(uint context, uint notification, IntPtr param1, IntPtr param2) { 
     if (notification == SPFILENOTIFY_FILEINCABINET) 
      return OnFileFound(context, notification, param1, param2); 
     else if (notification == SPFILENOTIFY_FILEEXTRACTED) 
      return OnFileExtractComplete(param1); 
     else if (notification == SPFILENOTIFY_NEEDNEWCABINET) 
      return NO_ERROR; 
     return NO_ERROR; 
    } 

    static uint OnFileFound(uint context, uint notification, IntPtr param1, IntPtr param2) { 
     FILE_IN_CABINET_INFO fileInCabinetInfo = (FILE_IN_CABINET_INFO)Marshal.PtrToStructure(param1, typeof(FILE_IN_CABINET_INFO)); 
     fileInCabinetInfo.FullTargetName = fileInCabinetInfo.NameInCabinet; // extract to current directory 
     return FILEOP_DOIT; 
    } 

    static uint OnFileExtractComplete(IntPtr param1) { 
     FILEPATHS filePaths = (FILEPATHS)Marshal.PtrToStructure(param1, typeof(FILEPATHS)); 

     if (filePaths.Win32Error == NO_ERROR) 
      Console.WriteLine("File {0} extracted to {1} " + filePaths.Source, filePaths.Target); 
     else 
      Console.WriteLine("Errors occurred while extracting cab File {0} to {1} ", filePaths.Source, filePaths.Target); 

     return filePaths.Win32Error; 
    }