tags:

views:

67

answers:

4

Hi StackOverflow, I've spent the past 3 hours trawling the web for answers to no avail, so I hope you can help me. I'm writing an application which automates Excel. The application has an option to "show/hide the excel sheet" so you can look at it, make any final changes and so forth.

Closing the application will naturally close the instance of Excel, however, there is a small chance that someone may exit out of Excel directly, without thinking. This breaks my application and I can't seem to find anyway of "checking if the same workbook is still open, and if not, re-opening it", before saving it

I've tried all sorts of things: checking if the Excel Application is null (when it's !=null it will save correctly, but when it "is" null (or at least, something other than !=null it won't even hit the breakpoint so I'm completely lost :(

Help please?

Edit: Thanks for all the replies so far, I'll reply to them in shortly.

AJ asked me to edit my question to provide a bit more information: I'm automating Excel using COM Interop from a C# application. The application allows the user to enter certain statistics which then get updated in Excel. There is a button which allows Excel to be shown/hidden, in case someone wants to check any other information in the sheet If someone exits Excel directly then it is still possible to use the show/hide button (it shows the Excel application with no workbook loaded) and the same Excel instance still shows up in Task Manager but when I click the "Save" button.

I added a try / catch in a slightly different place to last time (wasn't catching any errors last time, and now it catches two errors:

Exception from HRESULT: 0x800401A8

and

The object invoked has disconnected from its clients. (Exception from HRESULT: 0x80010108 (RPC_E_DISCONNECTED))

So basically it seems I need to "reconnect" the two again, although looking around on the web with the new error message doesn't seem's to suggest it could be a problem.

I'm wondering whether it would just be best to store all the values in strings (perhaps writing to a temp file sometimes in case of app failure) and then finally pushing them into Excel when the application is being closed?

A: 

How about using the FindWindow API to see whether the app is still visible?

AngryHacker
Not entirely sure but I think that this won't work if the actual application is hidden will it? I've never tried it on an app that's being used only as a COM server.
drachenstern
The window will be available as long as the app is loaded - but if the user has closed the application it should be out of memory entirely (thus unavailable).
AJ
Good to know, thanks.
drachenstern
A: 

I've tried all sorts of things: checking if the Excel Application is null (when it's !=null it will save correctly, but when it "is" null (or at least, something other than !=null it won't even hit the breakpoint so I'm completely lost :(

The test could be done like so:

if ( excelApp == null) {
  ; //set breakpoint here during execution to see if it IS null
}

EDIT:

Type wheresExcel = typeof(excelApp); //this is going to execute if the object has not been GC'd

/EDIT:

So your code looks like:

if ( excelApp != null ) {
  doSomething();
}

Then why not do this:

if ( excelApp == null ) {
  startExcel();
  addWorksheetToExcelInstance();
}
doSomething();
drachenstern
I attempted this already, the breakpoint is never hit as the workbook has already been "disconnected" from my app by the closing of Excel.
Charlie
You tried this on the excel workbook or on the application? I maintain a reference to both in my programs so I know if the instance is gone, not just the workbook. Also, if it doesn't hit that breakpoint, the object is not gone. You need a different test. Maybe define a new type set to the typeof that workbook. I'll edit and add a new test.
drachenstern
This seems to have worked, I used it in combination with a try / catch block as suggested by Jay below and it actually functions fine now, and reloads the Workbook if it was closed!Thanks all!
Charlie
A: 

There is no good way (read: reliable + robust), but someone has come up with a reasonable workaround here on the msdn social site which might do the trick for you.

The article talks about using subclassing to hook the window close. It also references an article on the microsoft support site which talks more generally about subclassing from C# and .Net.

The only other alternative which I have employed is a pretty tacky workaround - I would allow Excel to be visible, but I put my own stay-on-top form over the title bar + buttons (not recommended).

Edit:

Just in case it is not clear - I am not recommending you create an add-in, but that a similar approach with subclassing is potentially feasible to influence the behavior of Excel while being automated. I make the assumption you are using interop to 'automate excel'.

AJ
Doesn't that actually just prevent the user from exiting Excel EVERYTIME by showing said messagebox? That's not quite what @Charlie is trying to do is it?
drachenstern
if you adapt the code to just prevent closing until your app is ready, you can display a message to the user (if you choose) and prevent the closure - which is acceptable???
AJ
But if it's an Excel add-in, wouldn't it affect ALL Excel instances? Would the user need to use this program to always exit Excel? This sounds like a potential office virus waiting to happen. The "Never lets you quit office apps without a reboot" virus.
drachenstern
@drachenstern - the original question doesn't say it is an Excel add-in - just that it "automates" Excel - which is most commonly done via interop. The subclass code *should* only impact the instance associated with the main application. Regardless, the Excel instance can always be terminated by killing the process.
AJ
Fair enough. In that case I would concede, but in this case I have a feeling that he is not doing that. Hopefully we'll find out by Monday ;)
drachenstern
;-) I have asked Charlie to clarify
AJ
A: 

Why do you need to reopen the workbook "before saving it?"

Wrap the save in a try...catch block -- if it works, you're good, and if it doesn't, you can handle it any way you see fit in the catch block.

Jay