当我的C#程序将数据连续写入Excel电子表格时,如果最终用户点击右上方菜单并打开 Excel选项窗口,这会导致带有HRESULT的System.Runtime.InteropServices.COMException:0x800AC472中断数据 从写入电子表格。
理想情况下,应允许用户执行此操作而不会导致异常。
我发现此错误代码的唯一解决方案是循环并等待异常消失: Exception from HRESULT: 0x800AC472 这有效地挂起了应用程序,数据没有写入Excel,用户对此问题一无所知。
我想在写入时禁用Excel的主菜单,但找不到如何执行此操作的参考。
我的应用支持Excel 2000到2013。
以下是重现此问题的方法:
在Windows 7 64位上使用Visual Studio Express 2013 for Windows Desktop,.NET 4.5.1和Excel 2007。
创建一个新的Visual C#控制台应用程序项目。
添加对“Microsoft ExceL 12.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
}
}
}
Lanch应用程序,Excel出现并写入数据。从菜单中打开Excel选项对话框窗口,然后弹出错误:
mscorlib.dll中出现“System.Runtime.InteropServices.COMException”类型的异常,并且在托管/本地边界之前未处理
附加信息:来自HRESULT的异常:0x800AC472
点击继续和我的消息框“好的,我该怎么办?”出现。
请指教?
祝你好运, 贝特朗
答案 0 :(得分:4)
我们终于通过此问题一直到微软支持部门。他们的最终回应是:
我能够重现这个问题。我进一步研究了这个问题 发现这种行为是预期的并且是设计的。这个 异常,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。我们提供了一个明显的解锁&#34;按钮,但是当用户点击它时,他会在消息框中严格警告,并且&#34;你想继续吗?&#34;
答案 1 :(得分:1)
xlApp = new Excel.Application();
xlApp.Interactive = false;
答案 2 :(得分:1)
我成功完成的工作是在打开代码之前制作目标excel文件的临时副本。
这样我可以独立于打开或未打开的源文档来操纵它。
答案 3 :(得分:1)
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
{
}
}
答案 4 :(得分:0)
自动化Excel的一种可能的替代方案,并与其“摔跤”进行摔跤。 perculiarities,是使用OpenXmlWriter编写器(DocumentFormat.OpenXml.OpenXmlWriter)写出文件。
这有点棘手,但确实处理了带有&gt;的表格。 100万行没有出汗。
答案 5 :(得分:0)
由于 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);