5

我正在循环浏览一个包含数百个 excel 文件的目录,并尝试一次刷新一个 excel 文件。例如,我不断收到此错误,这表明刷新操作仍在文件 A 上运行,而 FileB 正在尝试启动刷新操作。循环太快了,不知何故,我必须等待文件 A 上的先前刷新操作完成,然后才能开始刷新文件 B。

未处理的异常:System.Runtime.InteropServices.COMException:消息过滤器指示应用程序正忙。(来自 HRESULT 的异常:0x8001010A (RPC_E_SERVERCALL_RETRYLATER))在 Microsoft.Office.Interop.Excel._Workbook.RefreshAll() 在 RefreshExcelFiles.Program.RefreshFile(String fileName)

这是我的代码。如何在开始处理循环中的新文件之前等待刷新操作完成?或者,等待 wb 对象上的封送释放操作完成,然后再开始新文件?

using System;
using System.Configuration;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.Office.Interop.Excel;

namespace RefreshExcelFiles
{
    internal class Program
    {
        private static string _fileDirectory;
        private static Application _excelApp;

        private static void Main(string[] args)
        {
            _fileDirectory = ConfigurationManager.AppSettings["FileDirectory"];
            _excelApp = new Application();
            _excelApp.DisplayAlerts = false;

            Console.WriteLine("starting to refresh files");
            int i = 0;
            int total = Directory.GetFiles(_fileDirectory).Length;

            foreach (string file in Directory.GetFiles(_fileDirectory))
            {
                i += 1;
                Console.WriteLine("File " + file + " " + i.ToString() + "/" + total.ToString());
                RefreshFile(file);
            }

            _excelApp.Quit();
            Marshal.FinalReleaseComObject(_excelApp);

            Console.WriteLine("press any key to exit");
            Console.ReadLine();
        }

        private static void RefreshFile(string fileName)
        {
            _Workbook wb = _excelApp.Workbooks.Open(fileName, false);
            wb.RefreshAll();

            wb.Save();
            wb.Close(Type.Missing, Type.Missing, Type.Missing);

            Marshal.FinalReleaseComObject(wb);
        }
    }
}
4

1 回答 1

8

我找到了我的问题的答案。我需要实现 IMessageFilter RetryRejectedCall。有关使用 IMessageFilter::RetryRejectedCall 的 C# 和 VB.NET 代码示例,请参阅此博客文章(回程机器存档链接)

如果您自己没有注册 MessageFilter(通过调用 CoRegisterMessageFilter),您将获得默认行为,如果调用被拒绝,则调用失败。.Net 将失败 HRESULT 转换为异常。为了处理尝试调用时服务器忙的可能性,您需要在客户端代码中实现 IMessageFilter::RetryRejectedCall 并注册消息过滤器。在大多数情况下,您只需要等待几秒钟,然后重试呼叫 - 通常这将有足够的时间让 Word 完成它正在执行的任何操作,以便它可以处理您的呼叫。

于 2013-01-23T14:52:02.433 回答