c# - 如何在 C# 中使用 SetupIterateCabinet

标签 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 事件时,问题就来了。根据文档,这是一个结构,我需要将我想要将文件提取到的位置的名称放入其中。我无法弄清楚结构应该是什么样子以及如何将参数转换为结构.

最佳答案

我认为您的回调函数的返回值有问题。在 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;
    }

关于c# - 如何在 C# 中使用 SetupIterateCabinet,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6104056/

相关文章:

c# - 将数据保存在 Form2 中,帐户 ID 位于 1 列中,以查看谁拥有该数据

c# - RhinoMock - AssertWasCalled 在具有不同参数的相同方法上不起作用

C# for 循环错误 > is invalid

c# - 泛型的观察者模式

c# - Xamarin.Forms iOS 在设备在线时抛出 NSURLErrorDomain "internet connection offline"

c# - WPF DoubleUpDown 命令绑定(bind)到上下按钮

c# - 有没有办法在 c# 中获取所有线程的堆栈跟踪,比如 java.lang.Thread.getAllStackTraces()?

类的 C# 文档 <example><code>...</code></example>

c# - Asp.Net 不包含 buttonClick 的定义?

c# - 如何搜索带引号的字符串?