MS Office Forum / Word / Programming / July 2007
Wierd Word Macro Crash - HELP!!!!
|
|
Thread rating:  |
Ian Baxter - 12 Jul 2007 22:14 GMT I have a Word document, a form with various checkboxes and such, designed to be a pre-qualification form for Contractors. At first it started with a need to color the selected answer (of "Yes", "No" or "N/A") in blue. I designed a macro to do this when the formfield is exited, and with strict naming conventions for the formfields via bookmarks.
It was then decided that they would like the "form" to automatically "jump" to a supplementary question if the N/A answer was ticked. Once completed, an exit macro in the textfield is designed to take the user back to the field after the "N/A" checkbox.
The code works so long as the user only uses the tab key to move from field to field in the form. If the user decides to use a mouse and click on the field after the N/A checkbox instead of using the tab key, Word crashes as soon as the sub is exited. I am sure it is tied to the movement of the insertion point via a .SELECT, but have been unable (after several rewrites and various attempts at workarounds) to identify the cause and solution.
Code:
Public Sub Color_Check() ' This routine goes into the document and colors the checked value ' of either Yes, No, or NA as blue and the others as black ' if NA is chosen, a message is displayed and the user sent to ' the end of the document to fill out additional details ' ' All bookmarks are set as <main>_YES, <main>_NO, <main>_NA, <main>_Jump and <main>_Back ' ' Initialize our internal values ' Dim Name_Yes, Name_No, Name_NA As String Dim IsNA, testVal As Boolean Dim NameVal, TestName, SelectedNameVal, JumpBookMark, OldMacro As String Dim BookPos As Range Dim BookField As FormField ' ' So, only one form field will be selected, we get the value and name ' this way SelectedNameVal = Selection.FormFields(1).Name
' We need to calculate the <main> value and the other permutations of the ' bookmark ' NameVal = Left$(SelectedNameVal, InStr(SelectedNameVal, "_") - 1) Name_Yes = NameVal & "_Yes" Name_No = NameVal & "_No" Name_NA = NameVal & "_NA" ' ' Now we determine if there is an NA option for this ' because it appears that there isn't always. We also set the bookmark to ' jump to if there is an "NA" value ' IsNA = False JumpBookMark = "" If (ActiveDocument.Bookmarks.Exists(Name_NA)) Then IsNA = True JumpBookMark = NameVal & "_Jump" End If ' ' And now we know the control that was called, we need to determine its ' state - if checked or not. Unchecking should simply turn it black. ' ' First - is it a checkbox? If ActiveDocument.FormFields(SelectedNameVal).Type = wdFieldFormCheckBox Then testVal = ActiveDocument.FormFields(SelectedNameVal).CheckBox.Value ' ' If the document is protected, we need to unprotect it. ' ActiveDocument.Unprotect ' If it was checked, then we have to color all the other ones black and ' uncheck them If testVal = True Then ' Which ones we check depends on the one we just exited Select Case SelectedNameVal Case Is = Name_Yes ActiveDocument.Bookmarks(Name_No).Range.Font.Color = wdColorBlack ActiveDocument.FormFields(Name_No).CheckBox.Value = False If IsNA Then ActiveDocument.Bookmarks(Name_NA).Range.Font.Color = wdColorBlack ActiveDocument.FormFields(Name_NA).CheckBox.Value = False End If Case Is = Name_No ActiveDocument.Bookmarks(Name_Yes).Range.Font.Color = wdColorBlack ActiveDocument.FormFields(Name_Yes).CheckBox.Value = False If IsNA Then ActiveDocument.Bookmarks(Name_NA).Range.Font.Color = wdColorBlack ActiveDocument.FormFields(Name_NA).CheckBox.Value = False End If Case Is = Name_NA If ActiveDocument.Bookmarks.Exists(Name_Yes) Then ActiveDocument.Bookmarks(Name_Yes).Range.Font.Color = wdColorBlack ActiveDocument.FormFields(Name_Yes).CheckBox.Value = False End If If ActiveDocument.Bookmarks.Exists(Name_No) Then ActiveDocument.Bookmarks(Name_No).Range.Font.Color = wdColorBlack ActiveDocument.FormFields(Name_No).CheckBox.Value = False End If End Select ' ' Make sure we color the selected bookmark blue Selection.Font.Color = wdColorBlue Else ' Here we simply turn the checkbox black ActiveDocument.Bookmarks(SelectedNameVal).Range.Font.Color = wdColorBlack End If ActiveDocument.Protect Type:=wdAllowOnlyFormFields, NoReset:=True ' ' We are forced to process this after the SELECT because ' we will end up selecting another area of text after we're ' done. ' If (SelectedNameVal = Name_NA) And (testVal = True) Then If (ActiveDocument.Bookmarks.Exists(JumpBookMark)) Then MsgBox "Additional information is required. Jumping to that section of the document.", vbOKOnly ActiveDocument.Bookmarks(JumpBookMark).Select End If End If End If End Sub
Russ - 13 Jul 2007 01:59 GMT Have you put a breakpoint just before you think it crashes and then single step through the code to pinpoint which line in the code causes problems. Also what are the versions of Word you will be using this code with? Have you tried this code on a newer version of Word?
> I have a Word document, a form with various checkboxes and such, designed to > be a pre-qualification form for Contractors. At first it started with a need [quoted text clipped - 126 lines] > End If > End Sub
 Signature Russ
drsmN0SPAMikleAThotmailD0Tcom.INVALID
Ian Baxter - 13 Jul 2007 15:14 GMT > Have you put a breakpoint just before you think it crashes and then single > step through the code to pinpoint which line in the code causes problems. > Also what are the versions of Word you will be using this code with? > Have you tried this code on a newer version of Word? Of course. It crashes at the "Exit Sub"....
Word 2003.... And since this is a corporate environment, I am not allowed to have other versions of Word installed. We won't be using Office 2007 for another 6 months. Feedback from people who have received this form indicates that the behaviour is the same under Word 2007, but I cannot confirm that.
Ian Baxter - 13 Jul 2007 15:22 GMT Okay, I have determined the following:
1. The problem is with the Color_Check macro in the sense that it gets called "twice" 2. The first time it is called is when the selected "N/A" checkbox exitmacro is fired. 3. Strangely, the Checkbox the user has clicked on (in order to move forward in the form) seems to be also "selected" and it appears that the Exitmacro for that control fires when I execute the "ActiveDocument.Bookmarks(JumpBookMark).Select" command. This happens despite the fact that the Selection object is still pointing to the old "N/A" checkbox. 4. As a result, Word has a furry fit...
If I click on a checkbox which has had the Exitmacro disabled, Word continues to run just fine.
Ian Baxter - 13 Jul 2007 16:44 GMT As a further test, I created a public variable (InMacro) that I set as True when the macro starts running, False when it completes, and False when the document is opened.
I added a test to the Color_Check macro (right after the DIM statements) that would bypass the macro code if InMacro is True.
The macro still crashes Word.
Russ - 13 Jul 2007 21:04 GMT It's crashing because the Color_Check macro has been called again before it is done, right? So you need to test if it is still active BEFORE it is called again or temporarily hide objects on the form from user interaction that might call that macro again before it is finished.
In Doevents VBA help, it mentioned a similar situation that may occur while using that function: "Caution Any time you temporarily yield the processor within an event procedure, make sure the procedure is not executed again from a different part of your code before the first call returns; this could cause unpredictable results. In addition, do not use DoEvents if other applications could possibly interact with your procedure in unforeseen ways during the time you have yielded control."
> As a further test, I created a public variable (InMacro) that I set as True > when the macro starts running, False when it completes, and False when the [quoted text clipped - 4 lines] > > The macro still crashes Word.
 Signature Russ
drsmN0SPAMikleAThotmailD0Tcom.INVALID
Ian Baxter - 13 Jul 2007 21:46 GMT Yep, that would match my theory... In other words, VBA code within Word cannot be re-entrant... Thus, recursive routines would likely fail as well. So much for being able to write robust object-oriented code in VBA.... *SIGH*
Due to the nature of the document and the large number of formfields, I am going to have to get really creative.
Thanks for your assistance Russ.
Russ - 13 Jul 2007 22:09 GMT Recursive or multitask. I don't think you could also have another macro running at the same time doing the same thing to get around the recursive problem, unless maybe it was acting on a different object or application object or you could trigger another app.object to launch its macro?? Now the spaghetti is getting too jumbled. ;-) Good Luck.
> Yep, that would match my theory... In other words, VBA code within Word > cannot be re-entrant... Thus, recursive routines would likely fail as well. [quoted text clipped - 4 lines] > > Thanks for your assistance Russ.
 Signature Russ
drsmN0SPAMikleAThotmailD0Tcom.INVALID
Ian Baxter - 13 Jul 2007 22:04 GMT If I set the following macro as the Entry macro (after the modification I made to create and set a global variable called "InMacro" when Color_Check is running, the crashes stop.
Sub Check_Running() Dim SelectedNameVal As String SelectedNameVal = Selection.FormFields(1).Name If (InMacro = True) Then Selection.FormFields(1).ExitMacro = "" Else Selection.FormFields(1).ExitMacro = "Color_Check" End If End Sub
Russ - 13 Jul 2007 22:19 GMT Ian, Very nice. I'm glad you posted the code.
> If I set the following macro as the Entry macro (after the modification I > made to create and set a global variable called "InMacro" when Color_Check is [quoted text clipped - 9 lines] > End If > End Sub
 Signature Russ
drsmN0SPAMikleAThotmailD0Tcom.INVALID
Ian Baxter - 13 Jul 2007 22:34 GMT I didn't say it worked....
Further testing shows the original macro stops execution and the remaining code in Color_Check does not execute.
I am resigned to the fact that I can't make it work as the client wants and he is going to have to accept my "other" workaround.
Russ - 13 Jul 2007 22:54 GMT How about having Color_Check throw up a **Userform dialog** message like "Please Wait" that is modal (i.e. Not modeless) and there is no way for the user to dismiss the message until the macro is done and the macro takes the Userform message away. But that would be an irritant, if it popped up too often ( but then you might rethink when you do a color check ).
> I didn't say it worked.... > [quoted text clipped - 3 lines] > I am resigned to the fact that I can't make it work as the client wants and > he is going to have to accept my "other" workaround.
 Signature Russ
drsmN0SPAMikleAThotmailD0Tcom.INVALID
Russ - 13 Jul 2007 22:37 GMT Ian, You're not using SelectedNameVal? Did you want to send it as an argument to Check_Running to make Check_Running more universal?
Selection.FormFields(SelectedNameVal).ExitMacro
> Ian, > Very nice. I'm glad you posted the code. [quoted text clipped - 12 lines] >> End If >> End Sub
 Signature Russ
drsmN0SPAMikleAThotmailD0Tcom.INVALID
Ian Baxter - 13 Jul 2007 22:48 GMT It does not seem to matter. Honestly, I am going to create a small custom form, query the details, use it to set the value for the formfield requesting supplementary info and stop jumping around the document.
I am convinced that VBA works well for what it was intended to do - simple automation. More complex applications require a more robust programming language.
Russ - 13 Jul 2007 23:02 GMT Yes, I think must old timers here prefer to use a Userform dialog to gather information and then plug that data into a document. And I'm a firm believer in entering data only once to reuse elsewhere. http://gregmaxey.mvps.org/Repeating_Data.htm
> It does not seem to matter. Honestly, I am going to create a small custom > form, query the details, use it to set the value for the formfield requesting [quoted text clipped - 3 lines] > automation. More complex applications require a more robust programming > language.
 Signature Russ
drsmN0SPAMikleAThotmailD0Tcom.INVALID
Lene Fredborg - 13 Jul 2007 23:20 GMT I tested your code while setting your Color_Check macro as the _entry_ macro instead of the exit macro and that works.
When you turn on a form field check box, its value has become true already when the entry macro runs (which originally surprised me). The value remains true until after the exit macro has run, if any.
Correspondingly, when you turn off a form field check box, its value has become false already when the entry macro runs and it remains false until after the exit macro has run, if any.
To see this illustrated, you can try to insert the following code in the _start_ of your Color_Check macro after having applied it as the _entry_ macro to the three check boxes:
With ActiveDocument MsgBox "Entry " & vbCr & .FormFields("Name_Yes").CheckBox.Value & _ .FormFields("Name_No").CheckBox.Value & _ .FormFields("Name_NA").CheckBox.Value End With
Then create a macro, e.g. named "ExitTest", with the same message box code but with the word "Exit " instead of "Entry ". Assign that macro to the three check boxes as the _exit_ macro.
Now try turning on and off the check boxes and note the check box values shown by the message boxes. Remove the exit macro and the additional code in the Color_Check macro when done.
NOTE: If one of the check boxes is currently the first form field in the document, you could insert some other form field before it just to make sure that the check box is not automatically selected when the document opens since this will fire the entry macro - and nothing will happen if the user clicks the check box (because it is already selected).
If you insert the line Application.ScreenRefresh before the code that displays the message at the end of your macro, you will prevent the user form seeing 2 checked check boxes when the dialog box is displayed in case the user had previously checked the Yes or No check box.
 Signature Regards Lene Fredborg DocTools - Denmark www.thedoctools.com Document automation - add-ins, macros and templates for Microsoft Word
> I have a Word document, a form with various checkboxes and such, designed to > be a pre-qualification form for Contractors. At first it started with a need [quoted text clipped - 126 lines] > End If > End Sub Ian Baxter - 16 Jul 2007 21:38 GMT Wow,
It is going to take some re-writing, but I might be able to make that work. Thanks for the response... I'll keep you all posted.
> I tested your code while setting your Color_Check macro as the _entry_ macro > instead of the exit macro and that works. > > When you turn on a form field check box, its value has become true already > when the entry macro runs (which originally surprised me). The value remains > true until after the exit macro has run, if any. .......
|
|
|