如何在C#中使用SetupIterateCabinet

时间:2011-05-23 23:08:49

标签: c#

我正在尝试编写代码来提取CAB文件的内容,但是我在使用SetupIterateCabinet例程时遇到了问题。

请在此处查看文档http://msdn.microsoft.com/en-us/library/aa377404(v=vs.85).aspx

我可以像这样正确导入

    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;
    }

但是,在尝试处理回调中的SPFILENOTIFY_FILEINCABINET事件时会出现问题。根据文档,这是一个结构,我需要将我想要提取文件的位置放在其中。我无法弄清楚结构应该是什么样的,也许如何将param转换为结构

1 个答案:

答案 0 :(得分:0)

我认为你的回调函数的返回值有问题。在SPFILENOTIFY_FILECABINET上,您应该返回FILEOP_DOIT。在返回之前,您应该在FILE_IN_CABINTE_INFO中设置文件名。请检查代码项目帖子http://www.codeproject.com/Articles/7165/Iterate-and-Extract-Cabinet-File 我稍后可能会添加一些代码示例。 GTG现在

编辑:

下面的代码示例。我没试过,但我相信它应该有效。我试图保持结构类似于你的代码。这应该向您展示如何定义FILE_IN_CABINET_INFO类以及在回调中设置和返回的正确值

    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;
    }