Search code examples
c#excelexcel-automationexcel-exception

How to fix this Exception in Excel automation?


As I mentioned elsewhere, I'm writing a program to extract and reconstitute Excel files.

Until a few days ago, everything was fine, but suddenly Excel started throwing exceptions when it never did.

What's baffling is that the exception thrown

Sorry, we couldn't find <file>. Is it possible it was moved, renamed or deleted?

does not make any sense, because it is thrown just after a check to see if the file exists.

There's nothing on the code that would warrant such exception. The StackTrace is of no use whatsoever (it's listed at the end of the question, if you're interested).

I've searched for this error, and while I could find references to this exception, none of the proposed solutions I found are for opening the file iteratively, not through automation.

Weirder still is that Excel opens the file normally.

Can anyone shed some light on this problem?


Stack Trace

This is the stack trace as it is shown in the application when it explodes. During debug only the first part is shown, with no inner exception.

Unhandled exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Runtime.InteropServices.COMException: Sorry, we couldn't find SolutionTreePro2.xlam. Is it possible it was moved, renamed or deleted?
   at Microsoft.Office.Interop.Excel.Workbooks.Open(String Filename, Object UpdateLinks, Object ReadOnly, Object Format, Object Password, Object WriteResPassword, Object IgnoreReadOnlyRecommended, Object Origin, Object Delimiter, Object Editable, Object Notify, Object Converter, Object AddToMru, Object Local, Object CorruptLoad)
   at ExcelFusion.VbaExtractor.ExtractVbaSourceCode(ExtractOptions options) in C:\Users\pauls\source\repos\Stricklen Pro\StricklenSolutions\ExcelFusion\VbaExtractor.cs:line 33
   at ExcelFusion.Program.<>c.<ConfigureExtractHandler>b__2_0(ExtractOptions options) in C:\Users\pauls\source\repos\Stricklen Pro\StricklenSolutions\ExcelFusion\Program.cs:line 102
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
   at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
   at System.Delegate.DynamicInvokeImpl(Object[] args)
   at System.CommandLine.NamingConventionBinder.ModelBindingCommandHandler.<InvokeAsync>d__11.MoveNext() in /_/src/System.CommandLine.NamingConventionBinder/ModelBindingCommandHandler.cs:line 87
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.CommandLine.NamingConventionBinder.ModelBindingCommandHandler.Invoke(InvocationContext context) in /_/src/System.CommandLine.NamingConventionBinder/ModelBindingCommandHandler.cs:line 133
   at System.CommandLine.Invocation.InvocationPipeline.<>c__DisplayClass4_0.<<BuildInvocationChain>b__0>d.MoveNext() in /_/src/System.CommandLine/Invocation/InvocationPipeline.cs:line 80
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass17_0.<<UseParseErrorReporting>b__0>d.MoveNext() in /_/src/System.CommandLine/Builder/CommandLineBuilderExtensions.cs:line 501
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass12_0.<<UseHelp>b__0>d.MoveNext() in /_/src/System.CommandLine/Builder/CommandLineBuilderExtensions.cs:line 393
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass22_0.<<UseVersionOption>b__0>d.MoveNext() in /_/src/System.CommandLine/Builder/CommandLineBuilderExtensions.cs:line 630
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass19_0.<<UseTypoCorrections>b__0>d.MoveNext() in /_/src/System.CommandLine/Builder/CommandLineBuilderExtensions.cs:line 562
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c.<<UseSuggestDirective>b__18_0>d.MoveNext() in /_/src/System.CommandLine/Builder/CommandLineBuilderExtensions.cs:line 536
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass16_0.<<UseParseDirective>b__0>d.MoveNext() in /_/src/System.CommandLine/Builder/CommandLineBuilderExtensions.cs:line 476
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c.<<RegisterWithDotnetSuggest>b__5_0>d.MoveNext() in /_/src/System.CommandLine/Builder/CommandLineBuilderExtensions.cs:line 207
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass8_0.<<UseExceptionHandler>b__0>d.MoveNext() in /_/src/System.CommandLine/Builder/CommandLineBuilderExtensions.cs:line 297

Image depicting the Exception being thrown by Microsoft Excel


Solution

  • The origin of this problem is a misunderstanding between what you expect the computer to do and what it really does.

    When testing the existence of the file, the program uses its current path. All relative paths are in reference to this one.

    So, as the path name (or options.ExcelFile in the example above) was a relative path, the test for the existence of the file passed.

    Then when, after opening Excel, Excel went to open the file (that ‘you’ had just tested) Excel used its own ‘current path’ and, therefore obviously, could not find the file, as it was a relative path.

    Everything went away when I forced the usage of a full path.

    I changed from

    var wb = xl.Workbooks.Open(options.ExcelFile);
    

    to

    var xlFilePath = (new FileInfo(options.ExcelFile)).FullName;
    var wb = xl.Workbooks.Open(xlFilePath);