You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Task.WhenAll批量解密Word文件时无法捕获异常求助

问题分析与解决方案

核心问题根源

你的批量解密异常无法捕获,本质原因是错误使用了ContinueWith:你添加到tasks列表的是ContinueWith返回的任务,而非原始的解密任务。当解密任务抛出异常时,ContinueWith默认会无视前置任务的失败状态继续执行,且自身不会传递前置任务的异常,导致Task.WhenAll认为所有任务都成功完成,自然无法触发catch块。

同时代码还存在其他隐患:跨线程操作UI、文件流未释放、异步事件处理不规范。


修正后的完整代码

GetPathOrExtention gte = new GetPathOrExtention();

// 优化解密方法:用using自动释放资源,避免文件锁定
private void DecryptDOCXFiles(string fileName, string password)
{
    using (FileStream inputStream = new FileStream(fileName, FileMode.Open, FileAccess.Read))
    using (WordDocument document = new WordDocument(inputStream, FormatType.Docx, password))
    {
        // 用Path.Combine避免路径拼接错误
        string outputPath = Path.Combine(gte.GetDirPath(fileName), gte.GetfileName(fileName).Replace("Encrypted-", ""));
        using (FileStream outputStream = new FileStream(outputPath, FileMode.Create, FileAccess.Write))
        {
            document.Save(outputStream, FormatType.Docx);
        }
    }
}

private async Task DecryptWordFiles()
{
    OpenFileDialog ofd = new OpenFileDialog();
    ofd.Filter = "docx files (*.docx)|*.docx|All files (*.*)|*.*";
    ofd.Multiselect = true;
    var tasks = new List<Task>();

    // 提前校验密码是否为空
    if (string.IsNullOrEmpty(TbDecPwd1.Text))
    {
        MessageBox.Show("请输入解密密码!", "P-GEN", MessageBoxButtons.OK, MessageBoxIcon.Warning);
        return;
    }

    if (ofd.ShowDialog() != DialogResult.OK)
        return;

    // 初始化进度条
    progressBar1.Visible = true;
    progressBar1.Maximum = ofd.FileNames.Length;
    progressBar1.Value = 0;
    LblProceeding.Text = "处理中...请勿关闭软件!";

    string password = TbDecPwd1.Text;
    foreach (string file in ofd.FileNames)
    {
        if (Path.GetExtension(file).ToLower() != ".docx")
        {
            LblProceeding.ResetText();
            MessageBox.Show("不支持该文件格式!\n\n仅支持Word 2019及以上版本的docx文件!", "P-GEN", MessageBoxButtons.OK, MessageBoxIcon.Error);
            return;
        }

        // 直接收集原始解密任务,确保异常能被Task.WhenAll捕获
        var decryptTask = Task.Run(() => DecryptDOCXFiles(file, password));
        // 单独用ContinueWith处理进度更新,通过Invoke确保UI操作在主线程执行
        decryptTask.ContinueWith(t => 
        {
            if (this.InvokeRequired)
                this.Invoke((Action)(() => progressBar1.PerformStep()));
            else
                progressBar1.PerformStep();
        }, TaskContinuationOptions.ExecuteSynchronously);
        
        tasks.Add(decryptTask);
    }

    try
    {
        await Task.WhenAll(tasks);
        LblProceeding.Text = "完成!";
        MessageBox.Show("文件解密成功!", "P-GEN", MessageBoxButtons.OK, MessageBoxIcon.Information);
    }
    catch (AggregateException ex)
    {
        // 区分异常类型,给出精准提示
        foreach (var innerEx in ex.InnerExceptions)
        {
            if (innerEx.Message.Contains("password"))
            {
                MessageBox.Show("密码错误!\n\n请确认密码正确,且文件未被其他软件打开!", "P-GEN", MessageBoxButtons.OK, MessageBoxIcon.Error);
                break;
            }
            else if (innerEx is IOException)
            {
                MessageBox.Show("文件被占用!\n\n请关闭正在打开的目标文件!", "P-GEN", MessageBoxButtons.OK, MessageBoxIcon.Error);
                break;
            }
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show($"解密失败:{ex.Message}\n\n请确认密码正确,且文件未被其他软件打开!", "P-GEN", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
    finally
    {
        // 无论成功失败,都重置UI状态
        LblProceeding.ResetText();
        progressBar1.Visible = false;
        progressBar1.Value = 0;
    }
}

// 修改为async void,正确处理异步事件
private async void BtnWordFilesDec_Click(object sender, EventArgs e)
{
    await DecryptWordFiles();
}

关键修改说明

  1. 异常捕获修复:将原始解密任务直接加入tasks列表,而非ContinueWith的任务,确保Task.WhenAll能感知到解密任务的异常。
  2. 资源管理优化:用using语句自动释放FileStream和WordDocument,避免文件被锁定或资源泄漏。
  3. 线程安全UI操作:通过Invoke确保进度条更新在主线程执行,解决WinForms跨线程操作异常。
  4. 异步事件规范:将按钮点击事件改为async void,正确等待异步任务完成,避免未捕获的后台异常。
  5. 用户体验优化:提前校验密码、区分异常类型给出精准提示、统一重置UI状态。

内容的提问来源于stack exchange,提问作者HB21

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 04:42:03