【问题标题】:writing data from C# to Excel interrupted by opening Excel Window通过打开 Excel 窗口将数据从 C# 写入 Excel 中断
【发布时间】:2021-06-10 17:43:07
【问题描述】:

虽然我的 C# 程序将数据连续写入 Excel 电子表格,但如果最终用户单击右上角的菜单并打开 Excel 选项 窗口,这会导致以下异常:

System.Runtime.InteropServices.COMException with HRESULT: 0x800AC472

这会中断数据写入电子表格。

理想情况下,应该允许用户执行此操作而不会导致异常。

我发现此错误代码的唯一解决方案是循环并等待异常消失: Exception from HRESULT: 0x800AC472 这有效地挂起应用程序,数据未写入 Excel,用户对问题一无所知。

我曾想过在写入时禁用 Excel 的主菜单,但找不到有关如何执行此操作的参考。

我的应用支持 Excel 20002013

这里是重现问题的方法:

  • 使用 Visual Studio Express 2013 for Windows Desktop、.NET 4.5.1 在 Windows 7 64 位和 Excel 2007 上创建一个新的 Visual C# 控制台应用程序项目。

  • 添加对“Microsoft ExceL 12.0 Object Library”(用于 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

  • 点击继续,我的消息框“好的,我在这里做什么?”出现。

请指教?

最好的问候, 伯特兰

【问题讨论】:

  • All right, what do I do here? - 如果您无法避免抛出异常,那么您需要一种方法来处理它。 The only solution I found to this error code was to loop and wait until the exception went awayI thought about disabling the main menu of Excel while writing to it, but cannot find a reference on how to do this. - 你不能在 Excel 中进入全屏模式或禁用功能区吗?
  • 听起来很深。如果您愿意禁用菜单,另一种方法是创建一个 99% 透明的喷嚏防护装置,它跟随 excel 窗口,但这仍然留下了键盘访问的问题。我想说最好的解决方案是抛出一个工具提示类型通知,让用户知道你在你的异常循环中。
  • 我怎么做:在没有功能区的旧版本 Excel 中打开“关于”窗口会出现同样的错误,因此这不是功能区问题。
  • Mark Robbins:禁用菜单是一种可行但不受欢迎的解决方案。我真的想解决这个异常。
  • excel 的问题是每个工作簿都是单线程的,所以它不能异步工作。正如其他人所提到的,您最好在工作时将用户锁定在电子表格中。或者发一条消息说请不要在我工作的时候这样做

标签: c# .net excel excel-interop


【解决方案1】:

我们终于找到了 Microsoft 支持来解决这个问题。他们的最终回应是:

我能够重现该问题。我对此进行了进一步研究 发现这种行为是预期的并且是设计使然。这个 异常,0x800AC472 – VBA_E_IGNORE,因为 Excel 正忙而被抛出 并且不会为任何对象模型调用提供服务。这是其中之一 讨论这个问题。 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。我们提供了一个明显的“解锁”按钮,但是当用户单击它时,他会在消息框中收到严厉警告以及“您要继续吗?”

【讨论】:

    【解决方案2】:

    Make Excel Interactive 是一个完美的解决方案。唯一的问题是用户是否同时在 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
        {
        }
    }
    

    【讨论】:

      【解决方案3】:
      xlApp = new Excel.Application();
      xlApp.Interactive = false;
      

      【讨论】:

      • 纯代码答案在这里被认为是低质量的。请为您的答案添加一些解释,而不仅仅是发布一个 sn-p。
      【解决方案4】:

      我成功做的是在代码中打开目标excel文件之前制作一个临时副本。

      这样我就可以独立于源文档是否打开来操作它。

      【讨论】:

        【解决方案5】:

        一种可能的替代 Excel 自动化的替代方法是使用 OpenXmlWriter 编写器 (DocumentFormat.OpenXml.OpenXmlWriter) 将文件写出。

        这有点棘手,但可以毫不费力地处理超过 100 万行的表格。

        OpenXml docs on MSDN

        【讨论】:

        【解决方案6】:

        由于 Interop 确实跨线程,它可能会导致多个线程访问同一个对象,从而导致此异常,下面的代码对我有用。

        bool failed = false;
        do
        {
            try
            {
                // Call goes here
                failed = false;
            }
            catch (System.Runtime.InteropServices.COMException e)
            {
                failed = true;
            }
            System.Threading.Thread.Sleep(10);
        } while (failed);
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-11-18
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多