question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

QueueAsMacro would not work - ever again!

See original GitHub issue

This is a little tricky explain and reproduce. But in some specific scenario we can ended up with QueueAsMacro not running ever again.

This is something pretty critical issue…

Description

If you run QueueAsMacro while the Excel dose not have any spread sheet open, it will be queued and run - we can argue if it should, as there is no file open, but it will. Next, we open some file. Obviously the code will run. Now we close the file (instance of the Excel is still open), and try to run QueueAsMacro. This will fail. But unfortunately any other invocation of QueueAsMacro (even from the opened spread sheet) will fail - we will never “dequeue” work.

Simple Repro-steps

  1. Open excel without any file
  2. Run something using QueueAsMacro.
  3. Open some file (could be ‘new empty file’) in Excel and try to use QueueAsMacro - this should work
  4. Close the file, leaving the Excel open
  5. Run something using QueueAsMacro - now this will fail (because this line)
  6. Open some file (could be ‘new empty file’)
  7. Try to use QueueAsMacro - this will fail - (because this line)

Explanation

For some reason, when you run ExcelDnaUtil.Application when there is no file for the first time (just after opening Excel) - will return proper object. This is whats allow us to run code and use QueueAsMacro even if no file is open. But when we run this second time (after closing some file) this will throw exception, because check in CheckExcelApiAvailable return XlReturnFailed. And I’m talking about running this from Main thread, because if we run this from some other thread, ExcelDnaUtil.Application will return null if there is no file open.

So, if we are in 5th step (from repro-steps), we will enqueue task and set the flag _syncPosted to true. Not this will be “picked” to run by ProcessRunSyncMacroMessage() and we will try to COMRunMacro. But in this case we will get exception when we try to get Application.

This exception is not caught anywhere, so we will not “schedule” this to run later (using timer). We will just exit - leaving the flag _syncPosted set, and not running PostRunSyncMacro ever again. Any other attempts to use QueueAsMacro will just add task to queue and wait (indefinitely) to be executed.

Possible solutions

I’m not that comfortable with the ExcelDNA code to create PR. (and I don’t want install Framework2.0 to be able to compile the project 😝 ) So this is my potential ideas how we can solve this problem.

  • use try/cache when we try to get Application (here) or just add additional cache to the “main try”. The downside of this, will be different behavior for the first “empty excel” and the rest, because at the beginning we will not get exception.
  • Add additional check if (IsInFormulaEditMode() || IsNoFileOpen()) return false;. We will have the same behavior in both cases - we will not run any macros until we open some file. Downside: we could ended with quite big queue and we will run (e.g. 50 tasks) all of them second after we open some file 🤔
  • Change the API and return bool from QueueAsMacro - if true, we enqueue task, if false, we was unable to do so, because no file was opened. So before we add something to the queue we would have to check if some file has been opened.
  • change where we clear the _syncPosted. Because right now we will clear only when we “clear” _isRunningMacros (which is redundant) - we should clear it just after we set runningMacros. And in addition use some new flag to indicate “something went wrong, try to run _syncWindow.PostRunSyncMacro() again”.

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:7 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
govertcommented, Mar 28, 2018

@Mad-Lynx Thank you for reporting this - I’ll have a look. Getting the Application object from Excel before the first workbook is opened is a huge problem, and the reason for a lot of the complicated code here. Excel has not internally created the COM objects and we need to get Excel to do so. Later, after all files are closed, I don’t think there is really a problem. This situation is just not handled well by Excel-DNA. I expect it to be easy to fix it I can recreate according to your steps. I’ll have a look over the weekend.

0reactions
govertcommented, Apr 26, 2018

@Mad-Lynx That makes sense.

You should pretty much never call Marshal.ReleaseComObject anywhere. The .NET GC properly keeps track of COM object references for you. Sometimes it makes sense to do a manual GC.Collect() to ensure COM objects that you are done with will be cleaned up and hence released by the GC immediately. Only case I can think of for using Marshal.ReleaseComObject is if you are using low-level COM calls where there is no RCW (Runtime-Callable Wrapper) and you are dealing with the IUnknown pointer directly through P/Invoke.

I’ve tried to write about the Marshal.ReleaseComObject anti-pattern on StackOverflow: https://stackoverflow.com/questions/37904483/as-of-today-what-is-the-right-way-to-work-with-com-objects

Read more comments on GitHub >

github_iconTop Results From Across the Web

QueueAsMacro multiple requests issue?
I'm guessing that this is all essentially single threaded, and that the QueueAsMacro call is eventually executed by some sort of call back...
Read more >
How to not hang Excel?
1 Answer 1 ... ExcelAsyncUtil.QueueAsMacro runs the code as soon as possible - in this case when the calculation completes. But the macro...
Read more >
Excel-dna Add-in opens Excel in the background after ...
What happens is that the Excel process is not terminating because there are outstanding COM references. From your Excel-DNA add-in, this can ...
Read more >
You're Not Imagining It—Job Hunting is Getting Worse
Even legitimate companies are posting “ghost jobs” that they don't actually ever fill, according to a survey by Clarify Capital.
Read more >
10 Ways To Recharge When You Don't Want To Work ...
Learn how to fight burnout and find career satisfaction by reading these tips on what to do when you don't want to work...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found