C# Excel Interop替代方案,避免等待处理0x800AC472错误

4
我有一个应用程序,会多次写入带有公式/宏的工作簿。它循环遍历一些数据3次,每次迭代都会创建、填充、保存,然后关闭Excel文件。当它是唯一的运行版本时,它可以正常工作,但如果有多个实例运行,就会出现问题。
具体来说,在向某些单元格写入数据时,我会遇到0x800AC472错误。每次出错时,它不是相同的单元格或值,但似乎每次都在第二次遍历时发生。这是相关代码:
public void SetCellValue(int row, int col, string val)
{
    if (_currWorkSheet != null)
    {
        string parms = string.Format("row={0}; col={1}; val={2}", row.ToString(), col.ToString(), val);
        for (short i = 0; i < _maxRetries; i++)
        {
            try { (_currWorkSheet.Cells[row, col] as Range).Value2 = val; return; }
            catch (Exception ex) { HandleError(ex, parms); }
        }
        Exception newExc = new Exception("Too many retries attempting to set cell value.");
        newExc.Data.Add("parms", parms);
        throw newExc;
    }
}


    private void HandleError(Exception exc, string parms)
    {
        if (exc != null && exc.Message != null)
        {
            // Excel error that just needs more time to complete. http://social.msdn.microsoft.com/forums/en-US/vsto/thread/9168f9f2-e5bc-4535-8d7d-4e374ab8ff09/
            if (exc.Message.Contains("0x800AC472"))
                Thread.Sleep(_threadSleepMs); // Give excel a chance to catch up, then keep processing.
            else
            {
                Exception newExc = new Exception("Unexpected Error", exc);
                newExc.Data.Add("parms", parms);
                throw newExc;
            }
        }
    }

我将_maxRetries设置为10,_threadSleepMs设置为500,但仍然出现错误,所以我认为再增加没有意义了。
我想知道是否有其他方法可以让线程有机会“解除卡顿”。
也许这可以算作第二个问题,但我不太担心,当它崩溃时,我仍然在finally块中执行Close()操作,但我仍然有它的实例挂起。这是我的关闭方式:
public void Dispose()
{
        if (!_disposed)
        {
            if (_currWorkBook != null)
                for (short i = 0; i < _maxRetries; i++)
                {
                    try { _currWorkBook.Close(false, _missing, _missing); break; }
                    catch (Exception ex) { HandleError(ex, ""); }
                }

            if (_app != null)
            {
                if (_app.Workbooks != null)
                    for (short i = 0; i < _maxRetries; i++)
                    {
                        try { _app.Workbooks.Close(); break; }
                        catch (Exception ex) { HandleError(ex, ""); }
                    }

                for (short i = 0; i < _maxRetries; i++)
                {
                    try { _app.Quit(); break; }
                    catch (Exception ex) { HandleError(ex, ""); }
                }

                if (_currWorkSheet != null)
                {
                    Marshal.ReleaseComObject(_currWorkSheet);
                    _currWorkSheet = null;
                }
                if (_currWorkBook != null)
                {
                    Marshal.ReleaseComObject(_currWorkBook);
                    _currWorkBook = null;
                }
                Marshal.ReleaseComObject(_app);
                _app = null;
            }

            GC.Collect();
            _disposed = true;
        }
}

它没有抛出错误,所以我只是想知道是否存在任何漏洞?

谢谢, 杰夫

3个回答

3

我能想到的唯一解决方案是在需要使用Excel功能的线程上创建一个锁。这只是确保我一次只有一个进程在使用Excel。这并不完美,特别是如果不相关的进程也尝试使用Excel,但这是我能想出的唯一解决方案。


0

你经常会遇到这个错误,因为你试图在同步文件夹上(例如公司桌面上的主文件夹)处理Office文档。

只需先将文件复制到本地磁盘文件夹(例如temp),一切都应该没问题了。

如果你正在更新Excel工作簿,或者等待数据表或数据透视表刷新,请使用一些人为延迟。

e.g

field.ClearAllFilters();
Thread.Sleep(500);
Application.DoEvents();
field.CurrentPageName = value;
Thread.Sleep(500);
Application.DoEvents();

0
根据我的经验,Excel无法通过COM Interop可靠地运行多个实例。我们有很多测试代码针对Excel运行,因此我们尝试让它正常工作。唯一的解决方案是将您的应用程序限制为一次只能运行一个实例 - 即使这样,我的经验是偶尔会出现无法解释的异常。 SpreadsheetGear for .NET 可能会解决您的问题。SpreadsheetGear具有“工作簿集”,大致类似于Excel应用程序,并支持从不同线程使用任意数量的工作簿集。
如果您想自己尝试,请查看实时ASP.NET示例here并下载免费试用版here
声明:我拥有SpreadsheetGear LLC。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接