PDA

View Full Version : Call to UserForm Fails only when Global Template



Shred Dude
03-02-2011, 03:02 PM
I've developed a .dotm file that contains Ribbon buttons that launch user forms, etc.

When I have this file open, as when editing, it works flawlessly for me. When I move a copy of it to my Startup Folder and have it launched automatically as an Add-In (Global Template), everything works fine, except the launch of one user form. I"m stumped.

The code below is from the UserForm's Initialization sub, and it works fine when .dotm file is open, but not when installed as a global template. When using with the template open, the userform pops up and all six fields are accurately populated. When run from the template when installed as a Global Template, it fails if the last two lines are not commented out. That is, it will work with those lines commented out, populating the first four text boxes. If those two lines are not commented out, it throws a VBA error 5, Invalid Procedure Call or Argument. It doesn't get to my error handling code.

Private Sub UserForm_Initialize()
'fill Text boxes with Custom Document Properties
On Error GoTo errhandler
With ThisDocument

Me.txtConTemplate.Text = .CustomDocumentProperties("Bulletin Agreement Template").Value
Me.txtContractsFolder.Text = .CustomDocumentProperties("Contracts Folder").Value
Me.txtPanelData.Text = .CustomDocumentProperties("Panel Data").Value
Me.txtReportsFolder.Text = .CustomDocumentProperties("Reports Folder").Value

'When Global Template, if these lines active, code fails with VBA Erro 5
'Invalid Procedure Call or Argument. WHAT'S CAUSING THIS????
'if I comment out two lines below, fomr opens with first four fields populated

'if run when Template Open, code executes fine...populating all six fields

Me.txtConEmail.Text = .CustomDocumentProperties("Contract Email").Value
Me.txtSalesRep.Text = .CustomDocumentProperties("Sales Rep").Value


End With

Me.Caption = "Testing"

errExit:

Exit Sub

errhandler:

MsgBox "Set Up User Form Initializaton failed" & vbCr & _
Err.Number & " - " & Err.Description, vbCritical, "ERROR"
Err.Clear
Resume errExit

End Sub


Any ideas? I'm stumped. Have gone through line by line commenting out the calls to the custom document properties and concluded it works fine if the email and sales rep are commented out but not otherwise. Works fine when template is opened and then run though. ??????

Frosty
03-02-2011, 03:23 PM
Don't really have any ideas of what's actually wrong, since the way you've outlined it.... of course those two lines which are exactly like the 4 lines previous should work. Hehe.

A couple of suggestions, apart from the obvious: post your addin.

1) Create a function which tests whether the customdoc props actually exist, and if they don't, create them with " " as the initial value

2) You've got a lot going on in a single line of code (setting the text value of a user form control to the value of a custom document property).

Try separating out the single line of the offending code... debug.print or message box each individual value of:
1. the value of the custom document property before you set it
2. the value you want to set it to
3. the value after you try to set it

That will give you an idea of what's not working when you can't "see" the code.

My guess is you've got something else going on, in addition to the above code... otherwise, you're right-- makes no sense :)

mdmackillop
03-02-2011, 03:43 PM
Is there any code attached to the Textboxes?

Shred Dude
03-02-2011, 06:48 PM
Thank you for the fresh eyes on this. It was an issue with Change event code on those two text boxes. I had ActiveDocument in there instead of ThisDocument. The other four text boxes didn't use change events, as they are updated through a click event on an ellipsis label that launches file or folder pickers. Those sections also had ActiveDocument in them, and so would have failed once the user tried to use the form if it had gotten past the first two issues.

This was my first go at Word Add-In's as a Global Template. Good lesson learned on ActiveDocument vs. ThisDocument. Also reemphasizes the value of error handling code. I wasn't familiar with the inability to "see" the code once it's running as a global add-in. That makes debugging a challenge. Any suggestions on that front?

Thanks again,

Shred

Frosty
03-02-2011, 07:25 PM
The following is just my opinion :)

A good suggestion is to never write your routines to use Active/Selection anything, except at the very top level (obviously, if your routine is designed to work on the ActiveDocument or some text you've selected, you have to identify it somewhere). But any routines buried down should be using some sort of parameter (and there are a lot of styles to doing this).

But it will always (maybe not immediately) pay dividends, at least down the road, to encapsulate your routines and make them basically stand-alone procedures in some fashion.

It seems longer to write a function that does

Public Sub MySubProcedure (oDoc as Document)

'blah blah blah

End Sub
Than it would to simply use activedocument in the actual routine... but it makes it hell to debug. As you get into using more and more complex stuff, good consistent coding practice will help out a lot.

I can't tell you how few people realize the value of the Locals window... it's designed to help you debug real-time (and it's helped me solve some problems that other people have thrown their hands up at--simply because I was able to see what VBA was looking for and not getting).

The Locals window won't show you all of the global things like Selection and ActiveDocument... but it will show you any variables you're currently using in your routine, including any parameters you might have passed in.

ThisDocument is a pretty safe object to use, as it's always the project you have the code in... but even then, depending on how you structure it... you might want to be able to pass in the ThisDocument object, so that you can re-use that code elsewhere.

For example, if you wrote a routine which copied all of the styles from your addin to the activedocument... you could use ThisDocument and ActiveDocument in the routine. But I almost guarantee you that at some point you will want to use that routine two other documents... and then you have to rewrite it.

So much easier, at the minimum, to

Sub CopyStyles
Dim docFrom as Document
Dim docTo as Document

Set docFrom = ThisDocument
Set docTo = ActiveDocument

'do some stuff
End Sub
'or
Sub CopyStylesAlt(docFrom as Document, docTo as Document)
'do some stuff
End Sub

Just makes it simpler down the road, and not that much harder to set up.

As an additional bonus to having parameters in your routines (even Optional parameters, which allow you even more flexibility), those routines won't show up in a macro list...

Just my two cents... this is very much into opinion territory, so take my opinion as just that-- my opinion. Lots of different ways to write good code.

fumei
03-07-2011, 10:40 AM
Good suggestions. Other than quick and dirty stuff, I try to avoid using ThisDocument or ActiveDocument. I use set objects. It makes this explicit, and generally speaking explicit is good. Explicit makes things easier to debug.

Frosty's suggestion for encapsulating procedures is a best-practice, and if you are doing anything more than short procedures a definite best-practice.