Variable scope

R

Rhino

I'm having some variable scope problems in VBA and would love to get an
explanation of how to avoid these problems.

I'm writing macros in Word 2002. At the moment, I'm polishing a series of
related procedures. I have a main macro that farms out much of its work to
other procedures. I also have some error handling which is centralized in
the main macro. I'd like to move some of the error handling into the lesser
procedures but this is causing me problems that look like variable scope
issues.

Specifically, the current version of the main macro opens a log file, writes
messages to that log file when it encounters errors, and then closes the log
file. I'd like to leave the open and close in the main macro but do the
writing of the error messages in a lesser procedure. For instance, I'd like
to be able to call a procedure like this from any of the other procedures:

public sub logError(message As String)
logTextStream.Write (message)
end sub

and then invoke it like this:

If ....
msg = "The warp pattern buffer is full."
logError (msg)
End If

However, when I change the code along these lines and then execute it, the
logTextStream.Write method crashes in the logError procedure with "Runtime
error '424': Object required." It appears that logTextStream is not visible
in the logError procedure. What do I need to do to make it visible in
logError? It is currently defined in the main macro as follows:

Set logFileObject = CreateObject("Scripting.FileSystemObject")
logFileObject.CreateTextFile (LOG_FILE_NAME)
Set logFile = logFileObject.GetFile(LOG_FILE_NAME)
Set logTextStream = logFile.OpenAsTextStream(WRITEONLY,
TRISTATE_USE_DEFAULT)

Clearly, logTextStream is a Variant since there is no 'Dim' statement for
it. I suspect that's my problem. I tried to write a 'Dim' statement for it
but VBA rejected my attempts:
- when I tried 'Dim logTextStream as TextStream', I found that there is no
TextStream type
- when I tried 'Dim logTextStream as Stream', I found that there is no
Stream type
- when I tried 'Dim logTextStream as Object', I got no compile error but I
got runtime error '424' when I wrote to logTextStream.
- when I tried 'Dim logTextStream as Object' and put that statement in the
Declarations area of Normal, I got no compile error but I got a runtime
error '91' when I wrote to logTextStream

So, what is the _right_ way to do this? I think I've found all the wrong
ways and can't think of anything else to try.
 
R

Rhino

Problem solved!

Just after posting this note, I discovered that I had _two_ occurrences of
'Dim logTextStream as Object', one in the main macro and one in the
Declarations area. As soon as I removed the one in the main macro, I found
that my lesser procedures could see the logTextStream and write to it just
fine. Now I have no compile or runtime errors and I'm a happy camper again!
 
J

Jay Freedman

Hi Rhino,

If you set a reference (Tools > References) to the Microsoft Scripting
Runtime, then you'll be able to declare LogFileObject As FileSystemObject,
and you can declare logTextStream As TextStream.

In fact, if you set the reference you can do early binding (see
http://word.mvps.org/FAQs/InterDev/EarlyvsLateBinding.htm) and replace the
CreateObject with a simple New statement. That's shown in the sample below.

Besides that, the use of a public variable (one defined in the Declarations
area) is usually not a good practice. It would be better to declare
logTextStream as a local variable in the main routine where the log file is
opened, and then pass logTextStream as a parameter to each called subroutine
or function.

Public Sub foo1()
Dim fs As FileSystemObject
Dim logFile As TextStream

Set fs = New FileSystemObject
Set logFile = fs.OpenTextFile("c:\temp\log.txt", _
ForAppending, True)

foo2 logFile, "This is a test."
Dim b As Boolean
b = foo3(logFile, "This is another test.")

logFile.Close
Set logFile = Nothing
Set fs = Nothing
End Sub

Private Sub foo2(f As TextStream, s As String)
f.WriteLine s
End Sub

Private Function foo3(f As TextStream, s As String) _
As Boolean
f.WriteLine s
foo3 = True
End Function

Finally, as Jezebel said in another thread, there's nothing here that you
can't do with VBA's native Open, Print # or Write #, and Close statements.
The FileSystemObject and TextStream objects are unnecessary distractions.

--
Regards,
Jay Freedman
Microsoft Word MVP
Email cannot be acknowledged; please post all follow-ups to the newsgroup so
all may benefit.
 
R

Rhino

Thanks, Jay! That fills in some of the gaps I had in understanding variable
scope.
 
J

Jezebel

Your example -- and the bug you created and fixed -- are a great example of
why variable names should show their scope. Always use a standard prefix to
show whether the variable is global, module-level, or function-level. (I use
g, m, and p respectively, but that's just me.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top