#c# #vsto #excel-interop
Вопрос:
У меня есть надстройка excel com, которая выполняет некоторые операции с книгой excel. Идея заключается в том, что при открытии файла excel по умолчанию в этой книге из vba будет вызвана открытая функция надстройки com (OpenFile). На этом этапе надстройка откроет новый процесс excel и откроет там пользовательскую книгу. Это работает большую часть времени, но иногда в отмеченной строке возникает следующее исключение:
ИНФОРМАЦИЯ , 05:31:12: Сообщение: Поток прерывается. ИНФОРМАЦИЯ , 05:31:12: Внутреннее исключение: ИНФОРМАЦИЯ , 05:31:12: Источник: ИНФОРМАЦИЯ mscorlib , 05:31:12: HResult: -2146233040 ИНФОРМАЦИЯ , 05:31:12: Целевой сайт: Пустое представление для внутренней(Int32, IntPtr) ИНФОРМАЦИИ , 05:31:12: Трассировка стека: в System.Runtime.Взаимодействия.Маршал.ThrowExceptionForHRInternal(код ошибки Int32, идентификатор ошибки IntPtr) в системе.Динамический.Комрантайм-помощники.Проверьте исключение(Int32 hresult, Except amp; except, UInt32 argErr, строковое сообщение) на сайте вызова.Цель(Закрытие , узел вызова , ComObject , строка , логическое значение ) в системе.Динамический.Обновленыелегаты.UpdateAndExecute3[T0,T1,T2,TRet](сайт сайта вызова, T0 arg0, T1 arg1, T2 arg2) в системе.Динамический.Обновленыелегаты.UpdateAndExecuteVoid3[T0,T1,T2](сайт узла вызова, T0 arg0, T1 arg1, T2 arg2) в VbaApi.Файл AddInApi.OpenFile(строковый путь, логическое значение 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 }.");
}
}
Мы были бы весьма признательны за любые указания относительно того, в чем может заключаться этот вопрос.
Комментарии:
1. Перестройте приложение с конфигурацией отладки вместо выпуска, чтобы иметь номера строк в трассировке стека исключений. Определите неудачный вызов, используя номер строки в приведенном выше фрагменте кода (и сообщите нам, какая это была строка).
2. @cly Спасибо за ответ. Это часть моей проблемы. Похоже, я не могу воспроизвести проблему в среде разработки. Только с развернутым приложением. Но строка, которая создает исключение, такова: automationObject. OpenFile(путь, ложь); // Исключение выбрасывается здесь, по крайней мере, именно здесь оно перехватывается, в OpenFile оно всегда находится в разных местах, например, это проблема со временем или состояние гонки.
3. Взгляните на журнал событий исполняющей машины (eventvwr.exe, журналы системы и приложений). Возможно, там скрыта какая-то связанная с этим информация.
Ответ №1:
Не создавайте новый экземпляр Excel.Application
объекта. Также имейте в виду, что COM-объекты имеют сходство с потоками, поэтому, если вы создаете новый COM-объект во вторичном потоке, освободите его (и все его дочерние объекты) с помощью Marshal.ReleaseComObject()
.