1

我从 rarlab.com 下载了适用于 Windows 软件开发人员unrar.dll,将 unrar.dll 和 unrar.cs 类包含到我的 C# WPF 项目中。

它提取单个档案(即使设置了密码):

string source = "d:\\unrartest\\compressed\\myarchive.part1.rar";
string dest = "d:\\unrartest\\extracted";
Unrar unrar = new Unrar();
unrar.Password = "password_of_myarchive";
unrar.Open(@source, Unrar.OpenMode.Extract);
while (unrar.ReadHeader())
{
    unrar.ExtractToDirectory(@dest);
}
unrar.Close();

...但不是拆分的:

System.IO.IOException: "File CRC Error"

由于周围没有文档,我想知道

  1. 如何处理unrar.ReadHeader()拆分存档的下一个文件
  2. 通常如何确定拆分存档的第一个文件
  3. (可选)如何确定整个提取过程的进度(在运行时输出我的程序中的进度)
4

3 回答 3

3

The c# wrapper and example included in the unrardll is outdated and does not work well with multivolume rar files because there are new callback messaged that are not handled. To fix it change:

private enum CallbackMessages : uint
{
    VolumeChange = 0,
    ProcessData = 1,
    NeedPassword = 2
}

to

private enum CallbackMessages : uint
{
    VolumeChange=0,
    ProcessData=1,
    NeedPassword=2,
    VolumeChangeW = 3,
    NeedPasswordW = 4,
}

And handle the new callback message for VolumeChangeW:

private int RARCallback(uint msg, int UserData, IntPtr p1, int p2)
{
    string volume=string.Empty;
    string newVolume=string.Empty;
    int result=-1;

    switch((CallbackMessages)msg)
    {
        case CallbackMessages.VolumeChange:
        case CallbackMessages.VolumeChangeW:

            if ((CallbackMessages)msg == CallbackMessages.VolumeChange)
                volume =Marshal.PtrToStringAnsi(p1);
            else
                volume = Marshal.PtrToStringAuto(p1);

            if ((VolumeMessage)p2==VolumeMessage.Notify)
                result=OnNewVolume(volume);
            else if((VolumeMessage)p2==VolumeMessage.Ask)
            {
                newVolume=OnMissingVolume(volume);
                if(newVolume.Length==0)
                    result=-1;
                else
                {
                    if(newVolume!=volume)
                    {
                        for(int i=0; i<newVolume.Length; i++)
                        {
                            Marshal.WriteByte(p1, i, (byte)newVolume[i]);
                        }
                        Marshal.WriteByte(p1, newVolume.Length, (byte)0);
                    }
                    result=1;
                }
            }
            break;

        case CallbackMessages.ProcessData:
            result=OnDataAvailable(p1, p2);
            break;

        case CallbackMessages.NeedPassword:
            result=OnPasswordRequired(p1, p2);
            break;
        default:
            break;
    }
    return result;
}
于 2020-05-05T09:28:52.067 回答
1

我遇到了这个问题,希望能找到我所有问题的答案。但我刚刚找到了我的解决方案并愿意分享。

  1. 如何处理 unrar.ReadHeader() 以继续拆分存档的下一个文件

如果您使用 Unrar 中的 C# 示例,则应删除IOException("File CRC Error")inProcessFileError()或抛出错误。如果您以读取模式打开,则文件打开错误也是如此。如果continuedOnNext == false.

case RARError.BadData:
    if (!currentFile.continuedOnNext) throw new IOException("File CRC Error");
    else break;

下一个文件将是完全相同的文件名并且将成功提取(假设第 2 部分中的文件没有损坏)。请注意,如果您列出新文件,则需要在以下位置修改此语句ReadHeader()

// Determine if new file
if (((header.Flags & 0x01) != 0) && currentFile != null)
        currentFile.ContinuedFromPrevious = true;

对此:

// Determine if new file
if ((header.Flags & 0x01) != 0) return true;

如果您不想停止 while 读取循环,则希望返回 true。

通常如何确定拆分存档的第一个文件

如果您的意思是如何确定档案是否是第一卷,您应该将 Unrar.cs 中的私有属性更改archiveFlags为更易于访问的修饰符(例如:内部或公共)。

要检查它是否是卷/拆分存档:

bool isVolume = (RARObj.archiveFlags & RAR.ArchiveFlags.Volume) == RAR.ArchiveFlags.Volume

要检查它是否是第一个卷/拆分存档:

bool isFirstVolume = (RARObj.archiveFlags & RAR.ArchiveFlags.FirstVolume) == RAR.ArchiveFlags.FirstVolume

如何确定整个提取过程的进度(在运行时输出我的程序中的进度)

您可以使用ListFiles获取存档文件计数并将其用作主要的存档提取过程。然后提取并创建一个事件RARObj.ExtractionProgress以更新您拥有的任何 ProgressBar。

ExtractionProgressEventArgs e具有PercentComplete更新进度条的属性。我建议你分析一下 WinRAR 应用程序是如何做到的,这样你就可以更好地了解它是如何工作的。

哦还有一件事。

RAR RARObj = new Unrar(archive.path);
于 2021-08-08T21:45:27.050 回答
0

Solution:

Basically, it works with SharpCompress as suggested by @Viezevingertjes in the comments above. But unfortunately, SharpCompress does not yet support RAR5 decryption, which means that RAR5 password protected files are not extracted, at all and therefore SharpCompress has a limited usage.

As workaround, you can only use rar.exe, unrar.exe or winrar.exe directly by a process call like this:

string rarExec = "\"c:\\Program Files\\WinRAR\\Rar.exe\"";
string sourceRar = "\"c:\\sourceFolder\\myfile.part001.rar\"";
string targetPath = "\"c:\\destinationFolder\"";
string password = "topsecret";

using (System.Diagnostics.Process process = new System.Diagnostics.Process())
{
    process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
    process.StartInfo.FileName = rarExec;
    if (password != "")
        process.StartInfo.Arguments = "/c x -cfg- -inul -y " + "-p" + password + sourceRar + " " + targetPath;
    else
        process.StartInfo.Arguments = "/c x -cfg- -inul -y " + sourceRar + " " + targetPath;

    process.Start();
    process.WaitForExit();

    switch (process.ExitCode)
    {
        case 0:
            // "OK: extracted";
            break;
        case 10:
            // "Error: wrong password";
            break;
        default:
            // "Error: unknown";
            break;
    }
}
于 2020-01-06T16:53:09.300 回答