5

私はいくつかの数百のExcelファイルのディレクトリをループしていて、一度に1つずつExcelファイルを更新しようとしています。たとえば、ファイルAで更新操作がまだ実行中であり、FileBが更新操作を開始しようとしていることを示すこのエラーが発生し続けます。ループは高速であり、どういうわけか、ファイルAの前回の更新操作が完了するのを待ってから、ファイルBの更新を開始する必要があります。

未処理の例外:System.Runtime.InteropServices.COMException:メッセージフィルターは、アプリケーションがビジーであることを示しました。(HRESULTからの例外:0x8001010A(RPC_E_SERVERCALL_RETRYLATER))Microsoft.Office.Interop.Excel._Workbook.RefreshAll()at 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

私は自分の問題に対する答えを見つけました。IMessageFilterRetryRejectedCallを実装する必要がありました。IMessageFilter :: RetryRejectedCallを使用したC#およびVB.NETコードサンプルについては、このブログ投稿(ウェイバックマシンのアーカイブリンク)を参照してください

(CoRegisterMessageFilterを呼び出して)自分でMessageFilterを登録しない場合、デフォルトの動作が得られ、拒否された場合は呼び出しが失敗します。.Netは、失敗したHRESULTを例外に変換します。呼び出しようとしたときにサーバーがビジーになる可能性に対処するには、クライアントコードにIMessageFilter :: RetryRejectedCallを実装し、メッセージフィルターを登録する必要があります。ほとんどの場合、数秒待ってから通話を再試行する必要があります。通常は、Wordが通話を処理できるように、Wordが実行中の処理をすべて終了できるようにするのに十分な時間です。

于 2013-01-23T14:52:02.433 に答える