【发布时间】: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