So far the template will work well; except if the user clicks on the cross in the top corner of the dialog box. One of the options is to change the properties of the user form so that this control isn't displayed. But, this looks ugly and we are all used to seeing this little cross to close things down.
As it stands if the user clicked on the cross she would see the following displayed:
So what is causing this problem? Well, the user has destroyed the oForm object herself.
However, the pointer, oForm, still exists and it's now pointing to what is now the software equivilent to a smoking hole in the computer's memory and when the code tries to determine the value of oForm.Tag there is nothing there to resolve. Word then, quite rightly, gets upset and stops working.
So, what we have to do is to resolve this problem. We can do this with error handling. In the code add the highlighted lines:
Private Sub Document_New() Dim oForm As frmMemo
On Error Goto Error_DocumentNew
Set oForm = New frmMemo oForm.Tag = "Cancel" oForm.txtDate.Text = Format$(Date, "d mmmm yyyy") oForm.Show If oForm.Tag = "OK" Then ActiveDocument.Bookmarks("bmkTo").Range.Text = oForm.txtTo.Text ActiveDocument.Bookmarks("bmkFrom").Range.Text = oForm.txtFrom.Text ActiveDocument.Bookmarks("bmkSubject").Range.Text = oForm.txtSubject.Text ActiveDocument.Bookmarks("bmkDate").Range.Text = oForm.txtDate.Text ActiveDocument.Bookmarks("bmkStartHere").Range.Select Unload oForm Set oForm = Nothing Else Unload oForm Set oForm = Nothing ActiveDocument.Close wdDoNotSaveChanges End If
Exit_DocumentNew: Exit Sub Error_DocumentNew: On Error Resume Next Unload oForm Set oForm = Nothing ActiveDocument.Close wdDoNotSaveChanges Resume Exit_DocumentNew
End Sub
Whilst this is not the time nor the place to discuss Error Handling a quick overview of what has been added follows.
The first line tells VBA that whenever there is an error then the error handler which the developer has written will be invoked. This error handler (currently until Word XP) takes this format. If there isn't an error handler in this routine then the calling procedure is checked for an error handler, and if that one doesn't have one then...
If VBA goes 'all the way to the top' without finding an error handler then it will throw up an error message like the one shown here. Our task, as developers, is to write solid enough code so that these things don't happen.
So, back to the error handling. What happens is that if there is an error the the program control jumps straight to the line past the label 'Error_DocumentNew:' . The next line tells VBA that if there are any more errors to ignore them and to continue working through the code. In an error handling routine this is usually a good idea because at this moment we could have come in from anywhere and we don't know which objects still exist, what pointers are still pointing and so on and we have a duty to try to close things down.
So what we do is to try to unload the form. Now, if we have got into this section because the user has already destroyed it for us (thanks user!) then this will cause an error but because we have told Word that we ignore all errors from now on nothing will go wrong.
In this section we destroy the form and remove it from memory, we reset the pointer and then we close down the document. Then we come to the last line, the Resume statement.
The Resume statement clears the Error flag (actually today it's an error object, called 'Err') and then sends control to a certain point. We send the control back to the Exit_DocumentNew: label where the next instruction exits the routine.
Now, note that we could have written some code to clear the Err object ourselves and then let the control run out of the bottom of the routine. This means that then we have a routine with two exit points; one through the error handler and one before the error handler. It is not good programming practice to have more than one entry point into a routine (thankfully with high level languages this is rarely possible) and it is not good programming practice to have more than one exit point. The developer and those who follow him need to know where the exit of the code is and then see what has been closed.
No doubt some people will complain and say that this will take a few extra lines of code. We don't care. The job of the developer is to make life easier for himself and of those that follow and we do that by writing good code. Writing good code isn't just for personal satisfaction but well written code lends itself to strong code which can be maintained easily in the future.
Anyway, at this point the template is complete and is ready for testing before distribution.
This code can be downloaded from here.
<< Back |
If there are any suggestions for updates or comments then please drop us a mail at malcolm.smith@dragondrop.com.