PDA

View Full Version : Solved: Searched and searched... writing to a variable stored in a global template?



rgmatthes
05-25-2010, 02:18 PM
I have two templates stored as global templates through the use of Word's startup folder. They both load correctly.

The first global template contains revision macros. Users can run them to clean up tables, delete obsolete styles, etc. The macros work well.

The second global template is what I'm designing now. It's supposed to contain a macro that uses Dir() to iterate through a folder full of documents and run the revision macros from the first global template on each one. The goal is to be able to clean up whole batches of files by letting the Dir() macro run overnight.

Since they both run essentially the same scripts, it makes sense to have the second global template access the first global template's macros. To do this, though, it seems I need to be able to write to the variables stored in the first global template.

For example, the first global template makes use of an AuthorName variable. While running the Dir() macro from the second global template, it may make sense to clear the AuthorName variable over the whole batch of files, essentially removing that info from all the documents being processed.

So here's my problem: how do I write AuthorName = vbNullString when AuthorName is being stored in a global template (in a module)? Or AuthorName = "Joe Schmuck"? (That's my real name, so please don't make fun of me.)

Finally, since I would assume my project is common, does anyone have any advice?

fumei
05-25-2010, 02:21 PM
You are storing a variable in a global template? Are you sure? Normally globals - except for Normal - do not store variables. HOW are you doing this?

rgmatthes
05-25-2010, 02:33 PM
Thanks for your response, fumei.

I may be wrong on the terminology - good catch. Unfortunately, I'm not sure I understand your question. I'll just explain everything.

Both templates are .dotm's stored in Word's startup folder. When I click Developer -> Document Template, they're both listed under "Global templates and add-ins", with checks next to each. So I know they're loaded.

Both templates contain forms and modules. Most of my variables are stored in the modules in the form of "Public TemplatePath As String".


Anything else I should add, fumei? Again, thanks for your response - I've been doing this all day. :(

fumei
05-25-2010, 03:06 PM
"Public TemplatePath As String".

is not stored. TemplatePath is a value. When the global is loaded your declared variable goes and gets that value. It is NOT stored. It is returned every time the global is loaded.

That being said, you could easily get the same value in your other global.

So, technically, yes, your variables ARE stored in the globals....but the values you want to use, are not.

For example, the first global template makes use of an AuthorName variable. While running the Dir() macro from the second global template, it may make sense to clear the AuthorName variable over the whole batch of files, essentially removing that info from all the documents being processed.
the first may make use of a variable like AuthorName, but this should have no effect on what you are doing in the second global.

If the files you are processing in the second global (using the Dir function it seems) have a value - say BuiltInProperty Author -then this has nothing at all to do with the variable used in the first global processing.

Perhaps if you spell out in a bit more detail what you are trying to?

If you wish to clear the value of Author in the files processed by the Dir, this can be done. Easily. But it has nothing to do with the variable used by the first global.

rgmatthes
05-25-2010, 04:28 PM
Thanks for your insight. I'll provide some more detail. Prepare for a long read, hopefully not a long response!

As I mentioned, both templates are loaded as global templates through Word's startup folder so the macros they contain are always accessible.

The first global template, the template that holds the document revision macros, can be utilized in two ways: either the user can click Developer -> Macros and run the subroutines one by one (for specific cleanup procedures), or the user can click an icon in the Quick Access toolbar to run a utility that calls all the subroutines. If the user calls the subroutines one by one, they're prompted to supply any missing info through InputBoxes so the subroutines can run correctly. If the user clicks the icon to run all the subroutines, a utility opens to collect data and provide info about what Word is doing while the subroutines run. I'll detail all this now.

The utility is made up of three forms total. The first two forms collect information about the document and the user's client and gives the user a chance to modify any of the data if necessary. All the variables (not their values! ;)) are stored within their own module. When the user clicks "OK" on the second form, a third form activates. That activation triggers 16 subroutines, which run one at a time using the information supplied by the user. While the subroutines run, the third form provides updates about what is happening by updating a label. The user effectively loses control of Word while these subroutines run, so the third form is modular. When the subroutines are all finished, the user can click an "OK" button and the utility ends. The result is a much cleaner document - typically takes about 3-5 minutes.

As I mentioned, all the variables the first global templates uses are stored in their own module. All the "revision" subroutines are stored to another. The various forms all have their own subroutines as well (for specifying that clicking the cmdExit button should close the form, etc.).

Now onto the SECOND global template... I just started on this. Right now it can only be accessed through an icon in the Quick Access Toolbar. When the icon is clicked, a userform appears asking for some info - the path of a source folder containing the documentation the user wants to process, the path to a destination folder for all the finished work, and the path to the Word template that all the documents' content should be dumped into. There are also two checkmarks for the user to indicate whether the author info and version info should be updated while processing the batch of files. And there are two related text boxes for the user to supply the updated author and version information if the respective checkmarks have "true" values.

When the user has finished filling out this info and clicks OK, a second form activates. Just like with the first global template, that activation triggers the subroutines stored in the first global template... only now some variables may need updating.

Like I mentioned, the AuthorName variable is effectively stored in "GlobalTemplate1.modVariables.AuthorName" (you follow?). But the second global template is running, and the user may wish to update the AuthorName variable to "Joe Schmuck", as indicated in the form. To me, it makes sense to say


If chkUpdateAuthor.Value = True Then
GlobalTemplate1.modVariables.AuthorName = txtUpdatedAuthorName.Value ' "Joe Schmuck"
End If

but I can't seem to reference the "AuthorName" variable to update it.

Any ideas? :)

Yours,
--Schmuck

TonyJollans
05-26-2010, 04:30 AM
Do you have a Reference set to GlobalTemplate1 in GlobalTemplate2?

rgmatthes
05-26-2010, 05:49 AM
I think I tried that already... but I just got an error saying something about how the components were already loaded. I assumed that since both global templates were already installed and I could call each macro already, I wouldn't have to set references.

Can you direct me to some sample code? I'll try that out today.

rgmatthes
05-26-2010, 07:30 AM
Hmmm... this could turn into a pretty good discussion of best practices.

Here's a recap:

Startup folder:
- GlobalTemplate1.dotm (contains revision macros)
- GlobalTemplate2.dotm (contains macro for batch application of revision macros)

GlobalTemplate1.dotm:
- modVariables (contains variables necessary for revision macros)
- modMacros (contains the actual revision macros)
- Form1 (collects document data)
- Form2 (collects user and client data)
- Form3 (upon activation, triggers revision macros in modMacros and updates user on processes)

GlobalTemplate2.dotm:
- modVariables (contains variables necessary for batch processing)
- modMacros (contains the batch processing macros)
- Form1 (collects add'l document/user data for batch processing)
- Form2 (upon activation, triggers macros to run batch application and updates user on processs)


GlobalTemplate1 works just fine. Like I said, Form1 and Form2 load to collect info, then Form3 triggers to activate the revision scripts, which run based on the info collected.

I'm having a problem with GlobalTemplate2. To put it as succintly as possible, from a script stored in GlobalTemplate2.modMacros, I need to be able to change the value stored in a variable stored in GlobalTemplate1.modVariables. I can't figure out how to do this!


If you wish to clear the value of Author in the files processed by the Dir, this can be done. Easily.

That's exactly what I'm trying to do!!!!


More info:

Both GlobalTemplates seem to be loading correctly through the startup folder. I haven't coded anything about adding specific references. I'm choosing not to do this because:

Both GlobalTemplates appear to be loading correctly as is.
I'm using "Application.Run" to call the macros stored in GlobalTemplate1.modMacros, which doesn't seem to require adding any references.
Adding references seems to require I know/code the specific path to the globaltemplate(s) (as in "C:\Startup Folder"), and that path could change.Now that your eyes are bleeding from all that text (:giggle), can anyone offer any advice? Pretty desperate here...

THANK YOU THANK YOU THANK YOU!!!!

fumei
05-26-2010, 08:27 AM
You really need to read up on Scope!

Variables declared, even as Public, in one template are NOT in Scope for another template.

Yes, you can call a procedure in one template from another. When you do, focus is shifted to THAT template, and any variables become in Scope.

Let me repeat that. From Global2, you can access a procedure in Global1, but you can NOT access a variable. Variable have Scope, the area in which they are viable. A Public variable has scope within any module/procedure in THAT project.

To put it as succintly as possible, from a script stored in GlobalTemplate2.modMacros, I need to be able to change the value stored in a variable stored in GlobalTemplate1.modVariables. I can't figure out how to do this!
and to put it succintly...you can not. They are not in Scope to GlobalTemplate2.

"If you wish to clear the value of Author in the files processed by the Dir, this can be done. Easily."

And since that is: "exactly what I'm trying to do!!!!"
Sub ClearAllAuthor()
Dim file
Dim path As String
path = "c:\zzz\Test\test2\"
file = Dir(path & "*.doc")
Do While file <> ""
Documents.Open FileName:=path & file
ActiveDocument.BuiltInDocumentProperties("Author") = ""
ActiveDocument.Save
ActiveDocument.Close
file = Dir()
Loop
End Sub
All *.doc (I refuse to use 2007...) files in c:\zzz\Test\Test2 have the Author builtin doc property set to "" (blank).

Done.

Have to ask why you want to do this though.

rgmatthes
05-26-2010, 09:15 AM
You really need to read up on Scope!

Variables declared, even as Public, in one template are NOT in Scope for another template.

Yes, you can call a procedure in one template from another. When you do, focus is shifted to THAT template, and any variables become in Scope.

Let me repeat that. From Global2, you can access a procedure in Global1, but you can NOT access a variable. Variable have Scope, the area in which they are viable. A Public variable has scope within any module/procedure in THAT project.

Thank you for briefly explaining this aspect of scope to me. I've learned a lot of VBA on my own (who hasn't?), and programming context like this is pretty easy to skip over. I think your explanation will help me a lot in the future.


and to put it succintly...you can not. They are not in Scope to GlobalTemplate2.

Drat it all. There are still ways to go about what I want to do, but they're a lot less elegant. Oh well... I already have my secondary solution figured out, and it works, I just would have preferred to not use it.


And since that is: "exactly what I'm trying to do!!!!"
Sub ClearAllAuthor()
Dim file
Dim path As String
path = "c:\zzz\Test\test2\"
file = Dir(path & "*.doc")
Do While file <> ""
Documents.Open FileName:=path & file
ActiveDocument.BuiltInDocumentProperties("Author") = ""
ActiveDocument.Save
ActiveDocument.Close
file = Dir()
Loop
End Sub


All *.doc (I refuse to use 2007...) files in c:\zzz\Test\Test2 have the Author builtin doc property set to "" (blank).

Done.

I may end up using that bit in the future, but right now I use AuthorName in the static words (the content) of the doc as well, so this doesn't present a whole solution for me. Still that's a great way to clear out built-in doc properties... eagerly bookmarked. Can I ask why you set Author = "" instead of vbNullString? I once read vbNullString is slightly faster and a good habit to get into... your thoughts?

By the way, 2007 ain't bad. Neither is 2010 (which I'm using now).

:yes :yes :yes :yes :yes :yes :yes :yes :yes :yes :yes :yes :yes
:yes :yes :yes Convert...Convert... :yes :yes :yes
:yes :yes Newest is always better... :yes :yes
:yes :yes :yes :yes :yes :yes :yes :yes :yes :yes :yes :yes :yes


Have to ask why you want to do this though.

My company has hundreds of crappy templates that need serious updating. Right now, authors take the crappy templates, add their info, and send them to me for revision. I use GlobalTemplate1 to apply mass revision to their work and save me time, but it'd make a lot more sense to fix up all the templates the authors start with. They'll still send their work to me for revision, but if the templates are fixed up from the start, it'll be easier for the authors to do their work, plus it will cut down on the work that comes my way. No one has taken on the challenge of fixing up the templates because it's such a huge undertaking. I want to come up with a utility to help with this. If successful, I can reuse the code to update other templates, too. The goal is to run the macro in GlobalTemplate2 overnight so it doesn't take up worktime. My bosses would be extremely happy about that!

Now with some templates, it might make sense to clear out the AuthorName (in the doc's file properties and the content) or replace it with a new name. IMO, given that it's a *template*, it should be just a document's shell, so why should an authorname be stored to the doc? But I want to be able to programmatically change the name to my own (or rather, GlobalTemplate2's operator) if my managers ask. Hence my problem.

fumei
05-26-2010, 09:41 AM
By the way, 2007 ain't bad. I respectfully disagree.


Convert...Convert...
Newest is always better... This is not proved, and in fact may be more mythology than reality. I rest my case.

I feel the same way about Windows 7. There is not a single reason spouted for switching that is honestly applicable to me. Not a one. More eye-candy.

What do you mean by: "right now I use AuthorName in the static words (the content)"

I doubt this very much. You may have the text value of what was AuthorName (the variable) but I seriously doubt you have the variable in any document. That is unless you are using a DOCVARIABLE field....are you? However, if you are, then - again - scope scope scope. That DOCVARIABLE must have been written to the file...it is still NOT the variable declared as Public in GlobalTemplate1. Sorry but it simply is not.

As for "" vs. vbNullString

Yes, you are technically correct, although I am unsure of the speed factor. However, setting a string variable to NullString dumps the memory previously allocated, which in priciple is a good thing.

For a decent article on optimizing string functions, see:

http://www.aivosto.com/vbtips/stringopt.html

It was written for VB, but it applicable for the most part to VBA as well.

rgmatthes
05-26-2010, 10:30 AM
I respectfully disagree.

This is not proved, and in fact may be more mythology than reality. I rest my case.

I feel the same way about Windows 7. There is not a single reason spouted for switching that is honestly applicable to me. Not a one. More eye-candy.

Haha, I knew I'd get you. :)

In all honesty, I like the content controls Office 2007 introduced, and themes are very helpful for my job. The smaller file sizes (from ZIP technology, dontcha know!) are also a plus. And I really like how I can change the file extension of any Office 2007+ file to .ZIP to unzip the file and check out all its contents. Seeing docs as layers of code, nothing else, is strangely appealing to me.

Windows 7 though... I like it a lot. The big features it touts are all pretty pointless, I agree. Yet, it contains a wealth of *little* improvements that won me over. For example, I use a QuickLaunch bar, and in it is a shortcut to the Recycle Bin. I frequently drag files to the Recycle Bin shortcut to delete them. It's a tiny icon, so if I miss it, all the files get dumped to the QuickLaunch bar as shortcuts... not cool. Windows 7 put in a tooltip that reads "Recycle Bin" when I'm hovering over it, so I never miss the icon anymore. It's just "smarter" than WinXP... and I suppose AeroSnap is sometimes pretty helpful, too.

But to each his own. :)


What do you mean by: "right now I use AuthorName in the static words (the content)"

I doubt this very much. You may have the text value of what was AuthorName (the variable) but I seriously doubt you have the variable in any document. That is unless you are using a DOCVARIABLE field....are you? However, if you are, then - again - scope scope scope. That DOCVARIABLE must have been written to the file...it is still NOT the variable declared as Public in GlobalTemplate1. Sorry but it simply is not.

Ah, I confused you. I should I have said "I use *the value stored to* AuthorName in static words (the content)". Sorry about that.

I use that value quite a bit. Say AuthorName = "Joe Schmuck":

I update an Author content control to that name (content controls are similar to fields). The content control is bound to the doc's file properties, so updating the control updates the Author property to "Joe Schmuck".
I update a Revision History table to include the author's name as the author. So a cell's contents are replaced with the static words "Joe Schmuck".
I actually perform a Document Comparison and mark all the changes from the original template to the revised doc as performed by "Joe Schmuck". I can pre-accept all deletion changes (NOT insertion changes) performed by "Joe Schmuck" to de-clutter the doc for my own revision.etc. I suppose I could work around having to set a variable by setting the built-in Author file property to "Joe Schmuck" early on, and then I could reference that file property for AuthorName info as the subroutines run, but my method of having a dedicated AuthorName variable gives users more control. For example, when a user runs the "UpdateRevisionHistory" macro and the AuthorName variable = vbNullString (;)), the user is given an InputBox and can supply an author name. Maybe they want that name to be "Joe Schmuck, Schmuck Extraordinaire". The doc's built-in file properties could simultaneously have an author property that reads simply "Joe Schmuck" if that was set earlier; the two author names don't have to be equal. Also, this way, running the "UpdateRevisionHistory" macro doesn't update the doc's file properties, which the user didn't ask for! But I digress.


As for "" vs. vbNullString

Yes, you are technically correct, although I am unsure of the speed factor. However, setting a string variable to NullString dumps the memory previously allocated, which in priciple is a good thing.

For a decent article on optimizing string functions, see:

http://www.aivosto.com/vbtips/stringopt.html

It was written for VB, but it applicable for the most part to VBA as well.

Thanks for clearing that up and passing that article my way.

And again, thanks so much for your help, fumei!!

Paul_Hossler
05-31-2010, 06:45 AM
gerry



For a decent article on optimizing string functions, see:

http://www.aivosto.com/vbtips/stringopt.html

It was written for VB, but it applicable for the most part to VBA as well.



That was VERY interesting -- for VBA, do you know of any differences to be aware of?

Paul