【问题标题】:Thread was being aborted exception thrown when opening workbook in a new Interop Excel process在新的 Interop Excel 进程中打开工作簿时,线程被中止引发异常
【发布时间】:2021-10-15 17:18:09
【问题描述】:

我有一个 excel com 插件,它在 excel 工作簿上执行一些操作。这个想法是,当打开一个默认的 excel 文件时,com add in (OpenFile) 上的一个公开函数将从这个工作簿中的 vba 调用。此时,插件将打开一个新的 excel 进程并在那里打开用户工作簿。它大部分时间都在工作,但偶尔会在标记的行抛出以下异常:

INFO,05:31:12:消息:线程被中止。 信息,05:31:12:内部异常: 信息,05:31:12:来源:mscorlib 信息,05:31:12:HResult:-2146233040 信息,05:31:12:目标站点:Void ThrowExceptionForHRInternal(Int32, IntPtr) 信息,05:31:12:堆栈跟踪:在 System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo) 在 System.Dynamic.ComRuntimeHelpers.CheckThrowException(Int32 hresult,ExcepInfo& excepInfo,UInt32 argErr,字符串消息) 在 CallSite.Target(闭包,CallSite,ComObject,字符串,布尔值) 在 System.Dynamic.UpdateDelegates.UpdateAndExecute3[T0,T1,T2,Tret](CallSite 站点,T0 arg0,T1 arg1,T2 arg2) 在 System.Dynamic.UpdateDelegates.UpdateAndExecuteVoid3[T0,T1,T2](CallSite 站点,T0 arg0,T1 arg1,T2 arg2) 在 VbaApi.AddInApi.OpenFile(String path, Boolean fromVba)

当它失败时,新创建的进程崩溃并关闭。它似乎是在 RealOpen 函数中完全随机的位置抛出的,因此它不是函数中特定的失败。有时它根本没有抛出,工作簿在新进程中打开并且功能正常。

下面是产生异常的代码:

public void OpenFile(string path, bool fromVba)
        {
            if (fromVba)
            {
                // if called from vba, create a new application object and make visible
                Excel.Application singleApp = new Excel.Application();

                // show new application
                singleApp.Visible = true;
                     
                // Get process id
                int processId = ExcelFunctions.GetExcelProcessId(singleApp);

                // give new app focus
                ExcelFunctions.BringMainWindowToFront(processId);

                // get ComAddIn in new application instance
                COMAddIn addIn = singleApp.COMAddIns.Item(ExcelFunctions.GetVersion(singleApp.Version));
                
                // connect it
                addIn.Connect = true;
                
                // automation object
                dynamic automationObject = addIn.Object;

                try
                {
                    // call open file in new instance                                        
                    automationObject.OpenFile(path, false); // Exception is thrown here
                }
                catch (Exception e)
                {
                    LoggerFactory.Logger.Debug(e.StackTrace);
                }
                // close original application if no other workbooks open
                ExcelFunctions.CloseSession(application);              
            }
            else
            {
                RealOpen(path);                
            }
        }

        private void RealOpen(string path)
        {
            try
            {
                OnRealOpen?.Invoke(path);
                if (path.StartsWith("Cannot decode:"))
                {
                    string error = "Error during download.";
                    LoggerFactory.Logger.Error(error);
                    AlertUser();
                    return;
                }

                dynamic WinHttpReq = VBAFunctions.CreateObject("Microsoft.XMLHTTP");
                WinHttpReq.Open("GET", path, false);
                WinHttpReq.Send();

                string FileName = WinHttpReq.GetResponseHeader("Content-Disposition");
                if (FileName == null)
                {
                    AlertUser();
                    return;
                }
                FileName = FileName.Substring(10);
                FileName = FileName.Substring(0, FileName.Length - 1);

                // check if file is already open on this machine           
                if (ExcelFunctions.CheckIfWorkbookOpen(FileName))
                    return;

                SavePath = Path.GetTempPath() + FileName;
                byte[] caseTemplateWithoutData = WinHttpReq.ResponseBody;

                if (WinHttpReq.Status == 200)
                {
                    using (var fs = new FileStream(SavePath, FileMode.Create, FileAccess.Write))
                    {
                        fs.Write(caseTemplateWithoutData, 0, caseTemplateWithoutData.Length);
                    }
                    
                    GetMetaData("http://test.com", SavePath);
                }
                else
                {
                    string error = "Cannot open, download file error.";
                    LoggerFactory.Logger.Error(error + " http status: " + WinHttpReq.Status + " ResponseText: " + WinHttpReq.ResponseText);
                    AlertUser();
                    return;
                }
                SaveDisabled?.Invoke();

                // Closing current workbook, and opens case.
                ReOpenExcel?.Invoke(SavePath); // It never reaches this point when it fails

                // Set focus to ribbon tab.       
                ActivateTab();
            }
            catch (Exception ee)
            {
                LoggerFactory.Logger.Error($"RealOpen - Error: { ee.Message }.");
            }
        }

任何关于问题可能是什么的指导将不胜感激。

【问题讨论】:

  • 使用 Debug 配置而不是 Release 重新构建应用程序,以便在异常堆栈跟踪中具有行号。使用上面代码 sn-p 中的行号识别失败的调用(并告诉我们那行是哪一行)。
  • @cly 感谢您的回复。这是我的问题的一部分。我似乎无法在开发环境中重现该问题。仅使用已部署的应用程序。但是引发异常的行是:automationObject.OpenFile(path, false); // 在这里抛出异常至少这是它被捕获的地方,在 OpenFile 中,它总是在不同的位置,就像它是一个时间问题或竞争条件。
  • 查看执行机器的事件日志(eventvwr.exe、系统和应用程序日志)。也许那里隐藏了一些相关信息。

标签: c# vsto excel-interop


【解决方案1】:

不要创建Excel.Application 对象的新实例。另请记住,COM 对象具有线程关联性,因此如果您在辅助线程上创建新的 COM 对象,请使用 Marshal.ReleaseComObject() 释放它(及其所有子对象)。

【讨论】:

    猜你喜欢
    • 2019-01-27
    • 1970-01-01
    • 2011-08-01
    • 2020-11-09
    • 1970-01-01
    • 1970-01-01
    • 2013-05-05
    • 1970-01-01
    • 2015-09-10
    相关资源
    最近更新 更多