Developer FAQs - MacrosWelcome to Baarns Publishing's Word Developers FAQ section. If you develop in Microsoft Word using Word Basic, these tips are for you. Feel free to copy any of the code you find here and use in your development projects. |
When my macro runs, it sometimes gets "out of memory" messages, why? |
|
| |
|
How do I make a variable stay persistent for another macro?
Keywords: WordBasic Variable
Re-Posted July 21, 1997
WordBasic only has a module and procedure level variable scoping. To save variable across instances of a macro the variable must be saved to another location such as the registry, ini file, text file or document variable. When the macro is executed it should read the values stored into memory.
Storing values in the registry or INI file is a good solutions for information that needs to be maintained across instances of Word too.
Note: This is only true for WordBasic. In WordVBA all module and global variables are persistent while a template is loaded. For more details read the white paper on Migrating to VBA from WordBasic. This method is still useful for storing values across different sessions or instances of Word.
Sub MAIN 'retrieve counter setting in the registry. HKEY_COUNTER$ = "HKEY_CURRENT_USER\software\Microsoft\Word\7.0\Options" 'Convert return value into a numeric value. iCount = Val(GetPrivateProfileString$(HKEY_COUNTER$, "MyCounter", "")) + 1 MsgBox "This macro has been run" + Str$(iCount) + " number of times." ' 'Store update value in registry. SetPrivateProfileString HKEY_COUNTER$, "MyCounter", Str$(iCount), "" End Sub
Sub PrivateProfileStringExample()
'retrieve counter setting in the registry.
Const HKEY_COUNTER As String = "HKEY_CURRENT_USER\software\Microsoft\Office\8.0\Word\Options"
Dim iCount As Long
'Convert return value into a numeric value.
iCount = Val(Application.System.PrivateProfileString("", HKEY_COUNTER, "MyCounter")) + 1
MsgBox "This macro has been run " & iCount & " times.", vbOKOnly + vbInformation
'
'Store update value in registry.
Application.System.PrivateProfileString("", HKEY_COUNTER, "MyCounter") = iCount
End Sub
For solutions that are more document centric, for example calculating how many times a user has opened a document. If the following example were added to as an AutoOpen macro it would track how many times a user has opened the document. Of course this would require read/write access to the document.
Sub MAIN On Error Goto Exit_Main 'Get User information from logon screen. HKEY_LOGON$ = "HKEY_LOCAL_MACHINE\Network\Logon" szUser$ = GetPrivateProfileString$(HKEY_LOGON$, "UserName", "") 'Get number of time user has opened the document. iCount = Val(GetDocumentVar$(szUser$)) + 1 SetDocumentVar szUser$, Str$(iCount) 'Display the message. MsgBox szUser$ + " has opened this document" + Str$(iCount) + " times." Exit_Main: If Err Then MsgBox "Cannot run inside of Macro window." End Sub
Sub AutoOpen()
On Error GoTo ErrorHandler
'Get User information from logon screen.
'''This does not work on NT4. Need to test on Win95.
Const HKEY_LOGON As String = "HKEY_LOCAL_MACHINE\Network\Logon"
Dim szUser As String
Dim iCount As Long
Dim wrdVariable As Word.Variable
szUser = Application.System.PrivateProfileString("", HKEY_LOGON, "UserName")
If szUser = "" Then
szUser = "unknown"
End If
'Get number of time user has opened the document.
Set wrdVariable = ActiveDocument.Variables(szUser)
iCount = Val(wrdVariable.Value) + 1
wrdVariable.Value = iCount
'Display the message.
MsgBox szUser$ + " has opened this document" + Str$(iCount) + " times."
Exit Sub
ErrorHandler:
Select Case Err.Number
Case 5825
'''Document variable doesn't exist, so create it.
Err.Clear
iCount = 1
Set wrdVariable = ActiveDocument.Variables.Add(szUser, (iCount))
Resume Next
Case Else
MsgBox Err.Number & ", " & Err.Description
Err.Clear
End Select
End Sub
The administrator would also want to review who has opened the document and how many times.
Sub MAIN
On Error Goto Exit_Main
fReset = 0 'Set this to 1 to set all counters back to 0.
uBound = CountDocumentVars()
'Because list might be cleared work from the bottom to the top.
'Word compresses the number of document variable entries every time
'an entry is removed.
For iLoop = uBound To 1 Step - 1
szUser$ = GetDocumentVarName$(iLoop)
msg$ = msg$ + szUser$ + ":=" + GetDocumentVar$(szUser$) + Chr$(13) + Chr$(10)
If fReSet Then
SetDocumentVar szUser$, ""
End If
Next
If msg$ <> "" Then
MsgBox msg$
Else
MsgBox "List is empty."
End If
Exit_Main:
If Err Then MsgBox "Cannot run inside of Macro window."
End Sub
Sub GetUsageTally()
Dim wrdVariable As Word.Variable
Dim wrdDocSource As Word.Document
Dim wrdDocTemp As Word.Document
On Error GoTo ErrorHandler
'''Store a pointer to the current active document, later the
'''temporary document will become the active document.
Set wrdDocSource = ActiveDocument
'''If no variables exist raise an error.
If wrdDocSource.Variables.Count = 0 Then
Err.Raise vbObjectError + 1, "GetUsageTally", "List is empty."
End If
'''Walk the variables collection.
For Each wrdVariable In wrdDocSource.Variables
'''Store results in a new document. Test to see if the temporary
'''document exist. If not create it, i.e. the first time through
'''the loop.
If wrdDocTemp Is Nothing Then Set wrdDocTemp = Word.Documents.Add()
With wrdDocTemp.Content
.InsertAfter wrdVariable.Name & " := " & wrdVariable.Value & vbCr
End With
Next
'''Now Delete all of the entries.
For Each wrdVariable In wrdDocSource.Variables
wrdVariable.Delete
Next
Exit Sub
ErrorHandler:
Select Case Err.Number
Case Else
MsgBox Err.Number & ", " & Err.Description
Err.Clear
End Select
End Sub
When my macro runs, it sometimes gets "out of memory" messages, why?
Keywords: Memory Message
Re-Posted July 21, 1997
Frequently this message occurs with macros that do a lot of text manipulate: copy and paste, inserting of AutoText, searching and replacing of text. The common cause here is the Undo buffer gets filled up. This has nothing to do with the amount of memory the system has. Therefore the simplest solution is to clear the undo buffer. There are 2 methods to clearing the undo buffer. None of this is straight forward because we are using side-effects of other features of Word. When ever you go into Tools Revisions you clear the undo buffer. Also when ever you Protect then un-protect a document you clear the undo buffer. Many solution providers use one of these 2 methods to clear the undo buffer.
Function ClearUndo1
ToolsProtectDocument .DocumentPassword = "", .NoReset = 0, .Type = 0
ToolsUnprotectDocument
End Function
Function ClearUndo2
Dim dlgTR as ToolsRevisions
Getcurvalues dlgTR
ToolsRevisions .MarkRevisions = ABS(dlgTR.MarkRevisions - 1)
ToolsRevisions .MarkRevisions = dlgTR.MarkRevisions
End Function
ClearUndo2 is the recommended as a utility function. ClearUndo1 will cause form fields to clear, where as toggling revisions doesn't effect revision marks.
Clearing the undo buffer frequently resolves many issues. However if you are making a tremendous amount of changes to a document, save frequently. Many times the performance of the macro will actually increase if the active document is saved from time to time. This is because Word handles all of the changes that are made to a document in a temporary file(s). Saving clears up these files reducing the size of them, therefore increasing access speed.
Word 97 still exhibits this same behavior and the solution is still similar. Word 97 provides a method off of the document object to clear the Undo Buffer. Microsoft help suggest to include the UndoClear method at the end of a macro to keep Visual Basic actions from appearing in the Undo box.
ActiveDocument.UndoClear
Back to the FAQ Table of Contents
It's starting to smoke...Should I turn it off? |
Copyright© 1996-1999, Baarns Consulting Group, Inc. - All rights reserved. |