Excel Interop in .Net - Catch VBA errors? - vb.net

Similar to Errors when calling certain Excel VBA macros from C#, I want to implement an error handler that will catch VBA errors and return gracefully.
Basically, I'm opening up an arbitrary macro workbook in Excel, and if the macro fails (i.e. you get a VBA error dialog with "end" and "debug" buttons), I want my application to handle it internally instead of using the VBA's dialogs. This is primarily so that a buggy book won't freeze processing (I'm using a queue of sorts to process multiple workbooks).
I already know about the DisplayAlerts=False property, and On Error Resume Next inserted into each routine, but I don't want to need to inject this into everything (especially since some of these workbooks may already modify the mentioned settings and reset them mid-routine!)
My best idea so far is to write up some sort of process watcher that looks for windows titled "Microsoft Visual Basic" and sendkey an "E" (to click the end button).
I've read in a few places that there's a property called Application.BreakOnVBAError that can be set to False, but it doesn't seem to exist in the interop assembly.

With the help of pinvoke.net and MWinAPI, I've been able to enumerate all of the windows created under Excel's process ID, which I can then drill down into to discover the elements of the dialog (if it's a dialog such as the Microsoft Visual Basic dialog).
Since it's an automated instance, the main window is hidden so the only thing that should show up are message boxes and the VBA error box, which I can then send keyboard input messages to to End the script when necessary.
Of course, this method never hits the "Debug" button so I should never see the VBE windows, but just in case I handle that too.
Source code available upon request?

Related

Word Add-in - find if dialog has focus?

I am writing a word add-in in VB .NET (using Add-in Express, but I don't think that's relevant).
I have created shortcuts, but I only want them to take effect if the document itself is in focus, not a dialog - for example, "Find and replace" or any other.
How do I determine if a dialog has focus?
The "Selection" property of the application points to the selection in the document, even if a dialog is currently selected. I can't find any "HasFocus"-equivalent property anywhere either. I'm running out of ideas :o)
Thanks!
This workaround worked for me:
My add-in keeps a reference to the handle of the most recently activated Word window, by using the GetActiveWindow API during the WindowActivate event of the Word application. This is necessary since, up until Office 2013, the Window object does not expose a handle property.
When a shortcut is triggered, I compare that to the handle of the currently active window, using the same API. If they don't match, I simply don't proceed :o)

Event when VBA code module is reset?

I am developing an excel sheet which has lots of ActiveX elements in it.
I am not using UserForm and all the data is loaded when an activeX button is pressed.
At this point a hidden excel app is created where various actions are performed.
This new app is then combined with other data etc etc.. based on what the user is doing on the front-end with the provided ActiveX controls.
My problem comes when the "project is reset", where all the objects are released from memory and everything.
If this was a user form I would have implemented "on terminate" event where I would close hidden all workbooks that I have used, basically clean after myself.
However this is not a userform and there is no way to detect when the "project is reset"(as far as I know) so the hidden excel app that I've created remain open but nothing points to it.
If I go to the task manager i see various "EXCEL.EXE" and the number of those is basically the number of times I have run the tool.
So, is there any way for me to detect when VBA is about to "stop the project" in the same was as there is "terminate" for user forms so I can delete unsused stuff and reset elements in the spreadsheet?
Thank you!
I have found that there is no corresponding event to catch this.
Best way to handle this is to create a hidden userform object which will "hold" all global variables and objects that I define. I can then implement a UserForm_Deactivate event to catch when the form is exiting and clean up after myself.

Outlook 2007 - VBA macro in NormalEmail.dotm

I have a Word 2007 template that I use as Normal.dotm, which has corporate theme, styles, etc., plus a tiny bit of macro code that overrides the default behaviour of the bullet & number buttons on the ribbon.
I'd now like to use this same template when creating emails in Outlook 2007. I've tried just copying my Normal.dotm to NormalEmail.dotm, and to an extent this works, but although my macro is correctly invoked when I press the bullet/number buttons in the email editor, it gives an error:
Run time error 429: ActiveX component can't create object
On further investigation, it seems that anything I do within my macro that references an object in the normal Word object model (Application, Selection, etc.) causes this error. So, even if my macro consists of the following, it still fails:
MsgBox TypeName(Application)
I have an inkling that this is because I'm running in the context of Outlook, not Word, and so perhaps there is no (Word) application, or any of the objects associated with it. I know that the email editor in Outlook is Word-but-not-as-we-know-it-Jim.
Having said that, I did discover that ThisDocument does return a valid Document object; unfortunately, it corresponds to the template itself, not the email being edited.
By trial and error, I've discovered that I can get at the Document corresponding to the email by the following circuitous route (this displays the text in the email):
MsgBox ThisDocument.MailEnvelope.Item.Application.ActiveInspector.WordEditor.Content.Text
However, this code also seems to cause Outlook to crash - not at the time, but later, when you close Outlook.
At this point, I'm just about ready to admit defeat. No doubt the "correct" way to create macros in Outlook is to create them in Outlook itself, but from my limited experience, that's just horrible. (You can create macros in VBA, but you can't deploy them; or, you can create them in VSTO, but then you need an installer rather than simply deploying a template).
So. Any ideas out there that would let me do all that I hoped to do?
Override the behaviour of the bullet/number buttons on the ribbon in the email editor.
Deploy the macros in the NormalEmail.dotm file, rather than having to "install" them.
Not crash Outlook.
Have you tried adding the reference in the VBA editor to the Microsoft Outlook Object Library?
In Outlook 2007 you might also have to add VBA references to "Microsoft Word 12.0 Object Library" and maybe "Microsoft Forms 2.0 Object Library". Different versions may apply for other version years.
In addition, in the macro/code you have to set the objects to get/use the correct methods and properties.
I'm not an OO programmer and usually copy code from elsewhere and modify for my need so I can't help much more than what I said above. (And one of my macros is also giving me the same 429 error you get.)

How to determine if 'SaveChanges:=wdDoNotSaveChanges' was passed to Interop.Word.Document.Close()

I have an issue with an Office addin I'm working on, which is implemented for Office 2003 & 2007. The addin is written in VB.NET 3.5 using VSTO.
The problem comes from some external code which automates a mail merge, opening the mail merge template, merging and then closing the template document. The close is done with this code:
objWord.Documents(sDoco).Close SaveChanges:=wdDoNotSaveChanges, OriginalFormat:=wdPromptUser
Because of some logic in my addin, instigated from the Interop.Word.Application.DocumentBeforeClose event, a message box is opened which prevents the Office document from closing, which breaks the automation.
Is there a way for me to determine the SaveChanges parameter (if any) on a Close within an Office.Interop.Word.Application event, such as DocumentBeforeClose? I'm trying to capture this parameter and determine if it's set to wdDoNotSaveChanges so that I can work around this problem.
I'm pretty sure you get the DocumentSave event BEFORE the DocumentBeforeClose, so set a flag in it, and if that flag is set at close, you know the doc has been saved, but if not, it was not. I've had to do similar things to know whether a Document was SAVED-AS vs just SAVED.
I'm not aware of any way to interrogate the state of that parameter from DocumentBeforeClose.

WatiN handler for vbscript Input Box

Do anyone have a solution for handling a vbscript inputbox with watin, and to be clear this is not the same a javascripts prompt or vbscript msgbox or etc....
I have and used handlers for those but cannot find a way to handle the input box and i do not have the pull to get the developers to change the code to use prompt and javascript like they have in some many other places in our old vb6 systems.
You should create a custom dialog handler that can handle the window. The trick to doing that is to get spy++ and match the right window style. Another method might be to call the document.eval method and close it using javascript.