web-dev-qa-db-ja.com

Excelウィンドウを開くとC#からExcelへのデータの書き込みが中断されました

私のC#プログラムはExcelスプレッドシートにデータを継続的に書き込みますが、エンドユーザーが右上のメニューをクリックして[Excelオプション]ウィンドウを開くと、System.Runtime.InteropServices.COMException with HRESULT:0x800AC472が発生し、データの書き込みが中断されます。スプレッドシートに。

理想的には、ユーザーは例外を発生させずにこれを実行できるようにする必要があります。

このエラーコードに対して私が見つけた唯一の解決策は、ループして例外がなくなるまで待つことでした: HRESULTからの例外:0x800AC472 これはアプリを効果的にハングさせ、データはExcelに書き込まれず、ユーザーは問題についての暗闇。

書き込み中にExcelのメインメニューを無効にすることを考えましたが、その方法に関するリファレンスが見つかりません。

私のアプリはExcel2000から2013をサポートしています。

問題を再現する方法は次のとおりです。

Visual Studio Express 2013 for Windowsデスクトップ、.NET4.5.1をWindows764ビットでExcel2007とともに使用します。

新しいVisualC#コンソールアプリケーションプロジェクトを作成します。

「MicrosoftExcel12.0オブジェクトライブラリ」(Excelの場合)および「System.Windows.Forms」(メッセージボックスの場合)への参照を追加します。

完全なコードは次のとおりです。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading.Tasks;
using System.Threading; // for sleep
using System.IO;
using System.Runtime.InteropServices;
using System.Reflection;
using Microsoft.Win32;
using Excel = Microsoft.Office.Interop.Excel; 

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            int i = 3; // there is a split pane at row two
            Excel.Application xlApp;
            Excel.Workbook xlWorkBook;
            Excel.Worksheet xlWorkSheet;

            try 
            { 
                object misValue = System.Reflection.Missing.Value;

                xlApp = new Excel.Application();
                xlApp.Visible = false;
                xlWorkBook = xlApp.Workbooks.Add(misValue);

                xlApp.Visible = true;
                xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);
                // next 2 lines for split pane in Excel:
                xlWorkSheet.Application.ActiveWindow.SplitRow = 2; 
                xlWorkSheet.Application.ActiveWindow.FreezePanes = true;
                xlWorkSheet.Cells[1, 1] = "Now open the";
                xlWorkSheet.Cells[2, 1] = "Excel Options window";
            }
            catch (System.Runtime.InteropServices.COMException)
            {
                System.Windows.Forms.MessageBox.Show("Microsoft Excel does not seem to be installed on this computer any longer (although there are still registry entries for it). Please save to a .tem file. (1)");
                  return;
            }
            catch (Exception)
            {
                System.Windows.Forms.MessageBox.Show("Microsoft Excel does not seem to be installed on this computer any longer (although there are still registry entries for it). Please save to a .tem file. (2)");
                return;
            }

            while(i < 65000)
            {
                i++;

                try
                {
                    xlWorkSheet.Cells[i, 1] = i.ToString();
                    Thread.Sleep(1000);
                }
                catch (System.Runtime.InteropServices.COMException)
                {
                    System.Windows.Forms.MessageBox.Show("All right, what do I do here?");
                }
                catch (Exception) 
                {
                    System.Windows.Forms.MessageBox.Show("Something else happened.");    
                }
            }

            Console.ReadLine(); //Pause
        }
    }
}

アプリを起動すると、Excelが表示され、データが書き込まれます。メニューからExcelオプションダイアログウィンドウを開くと、次のエラーが表示されます。

タイプ 'System.Runtime.InteropServices.COMException'の例外がmscorlib.dllで発生し、マネージ/ネイティブ境界の前に処理されませんでした

追加情報:HRESULTからの例外:0x800AC472

[続行]をクリックして、メッセージボックス「わかりました。ここで何をしますか?」をクリックします。が表示されます。

お知らせ下さい?

よろしく、バートランド

9
Bertrand_Szoghy

私たちはついにこの問題でマイクロソフトサポートに行きました。彼らの最終的な反応は次のとおりです。

問題を再現することができます。これについてさらに調査したところ、この動作は予期されたものであり、設計によるものであることがわかりました。この例外0x800AC472– VBA_E_IGNOREは、Excelがビジーであり、オブジェクトモデル呼び出しを処理しないためにスローされます。これはこれについて話している議論の1つです。 http://social.msdn.Microsoft.com/Forums/vstudio/en-US/9168f9f2-e5bc-4535-8d7d-4e374ab8ff09/hresult-800ac472-from-set-operations-in-excel?forum= vsto 私が見ている回避策は、この例外を明示的にキャッチし、意図したアクションが完了するまでしばらくしてから再試行することです。

ソフトがログ記録を停止したことに気付かずにウィンドウを開いたりメモを取ったりする可能性のあるユーザーの心を読み取ることができないため(エラーをマスクした場合)、次を使用して回避することにしました。

 xlWorkSheet.EnableSelection = Microsoft.Office.Interop.Excel.XlEnableSelection.xlNoSelection;

excelウィンドウのUIをロックします。わかりやすい「ロック解除」ボタンを用意していますが、ユーザーがクリックすると、メッセージボックスに「続行しますか?」という警告が表示されます。

5
Bertrand

私が成功したのは、コードで開く前に、ターゲットのExcelファイルの一時コピーを作成することです。

そうすれば、ソースドキュメントが開いているかどうかに関係なく操作できます。

1

ExcelInteractiveを作成することは完璧なソリューションです。唯一の問題は、ユーザーが範囲の選択やセルの編集など、Excelで同時に何かをしている場合です。たとえば、コードが別のスレッドから戻ってきて、計算結果をExcelに書き込もうとしています。したがって、この問題を回避するための私の提案は次のとおりです。

private void x(string str)
{
    while (this.Application.Interactive == true)
    {
        // If Excel is currently busy, try until go thru
        SetAppInactive();
    }

    // now writing the data is protected from any user interaption
    try
    {
        for (int i = 1; i < 2000; i++)
        {
            sh.Cells[i, 1].Value2 = str;
        }
    }
    finally
    {
        // don't forget to turn it on again
        this.Application.Interactive = true;
    }
}
private void SetAppInactive()
{
    try
    {
        this.Application.Interactive = false;
    }
    catch
    {
    }
}
1
v31
xlApp = new Excel.Application();
xlApp.Interactive = false;
1
guest

Excelを自動化し、その特殊性に取り組む代わりに考えられる1つの方法は、OpenXmlWriterライター(DocumentFormat.OpenXml.OpenXmlWriter)を使用してファイルを書き出すことです。

少し注意が必要ですが、100万行を超えるシートを問題なく処理できます。

MSDNのOpenXmlドキュメント

0
j3r3m7