Reputation: 545
I've got two methods which I feel should tell if a file is open or not.
Method 1 (Error: Subscript out of range):
If Not Workbooks(filename) Is Nothing Then
Workbooks.Open (filename)
End If
Method 2:
If Not IsWorkbookOpen(filename) Then
Workbooks.Open (filename)
End If
Where IsWorkbookOpen()
is:
Private Function IsWorkbookOpen(wbname) As Boolean
Dim wBook As Workbook
Set wBook = Nothing
On Error Resume Next
Set wBook = Workbooks(wbname)
If wBook Is Nothing Then
IsWorkbookOpen = False
Else: IsWorkbookOpen = True
End If
End Function
Aside from On Error Resume Next
, Method 1 appears to be nearly the same as Method 2.
Could anyone please explain why Method 1 gives the error it does?
Thank you.
Upvotes: 2
Views: 6492
Reputation: 4544
VBA tries to evaluate all the parts before it evaluates the conditional statement. So if I have a variable myvar = "xyz"
and try to run the following lines...
If IsNumeric(myvar) And Round(myvar, 1) = 3 Then
'you will get an error before the IF is evaluated
End If
it will not work. VBA will evaluate IsNumeric(myvar)
fine, then try to evaluate Round(myvar, 1) = 3
and get an error before it checks the entire conditional. So VBA will let you know about the error before it performs the AND
operator. If VBA had short circuit evaluation, it would work fine since the first part would evaluate to false.
But the following will work
If IsNumeric(myvar) Then
If Round(myvar, 1) = 3 Then
'second IF statement is not touched since first IF statement evaluates to false
End If
End If
This works because IsNumeric(myvar)
evaluates to false and therefore skips the nested statement.
So the error it throws on the Workbooks(filename)
will just give the error unless you tell it to resume next. So the method I use is
On Error Resume Next
Set wb = Workbooks(file)
If wb Is Nothing Then
Set wb = Application.Workbooks.Open(dir & "\" & file, ReadOnly:=True)
End If
On Error GoTo 0
Edited to give more detail and correctly capture that the second example will not be evaluated as well as provide a useful solution for the question at hand.
Upvotes: 1
Reputation: 2823
Workbooks(filename)
tries to get the element with the identifier (or 'index') filename
from the collection Workbooks
. If the collection does not contain such an element, you'll get the "Subscript out of range" error. (So in a nutshell: This code will fail whenever the file is not open. You probably don't want this.)
However, the knowledge that such an access will fail if the file is not open, i.e. an error is raised, is being made use of in the second method. The code tries to get the element with the identifier filename
from the Workbooks
collection and to assign it to the variable wBook
. If it fails, the value of the variable wBook
will stay Nothing
. If it succeeds, the variable wBook
will contain a reference to the respective Workbook object.
Upvotes: 0
Reputation: 33145
They both give a subscript out of range error. But in Method 2 you suppress that error with On Error Resume Next
.
Sub SeeError()
On Error Resume Next
Debug.Print Workbooks("DoesNotExist").Name
Debug.Print Err.Description
End Sub
This prints "Subscript Out of Range" in the Immediate Window. The On Error statement doesn't stop the error from occurring, it just handles it. Method 1 doesn't handle errors so the default error handling (stop execution and report the error) is in effect.
Upvotes: 5