Handling erros for Application.Workbooks without using Error handlers - vba

I am trying to assign an opened workbook to an workbook object. If that workbook is not already opened, then it throws an error. I am handling the errors using an Error Handler.
This works for me:
On Error GoTo OpenWorkbookError
Set Uwk = Application.Workbooks(WbkName)
OpenWorkbookError:
If Err <> 0 Then
Err.Clear
MsgBox ("Please Open the Required Workbook")
Exit Sub
End If
But is there a way to avoid using the error handlers in this situation.

One way to do it is check each workbook name, but what's wrong with the functions in the link that #SJR gave?
In your provided code you've kept the error handler within the main body of code - it should appear between the Exit Sub and End Sub at the end of the procedure.
Something like this would work without an error handler, but it's slower as it needs to check each workbook:
Sub Test()
Dim Uwk As Workbook
Dim WbkName As String
WbkName = "PERSONAL.XLSB"
For Each Uwk In Workbooks
If Uwk.Name = WbkName Then
Exit For
End If
Next Uwk
If Not Uwk Is Nothing Then
MsgBox Uwk.Name & " found!"
Else
MsgBox "Not found."
End If
End Sub
Your version of the code should have the error handler outside the main body:
Sub Test1()
Dim WbkName As String
Dim UWk As Workbook
WbkName = "PERSONAL1.XLSB"
On Error GoTo OpenWorkbookError
Set UWk = Workbooks(WbkName)
TidyExit:
'Close anything that needs closing and Exit.
Exit Sub '<< End of main body of procedure.
OpenWorkbookError:
Select Case Err.Number
Case 9 'Subscript out of range.
MsgBox "Please open the required workbook."
Resume TidyExit
Case Else
MsgBox "Error " & Err.Number & vbCr & _
Err.Description, vbOKOnly + vbCritical
Resume TidyExit
End Select
End Sub '<< End of procedure.

Related

Update excel file when opened if a new version is available

I have an Excel file which checks its local version with the current version from a database. The code to check the version isn't important to the question.
If there's a new version I want to download it, close the old file (because I can't change/modify it while opened), replace it with the new downloaded version and open the downloaded version.
What I have is something like this:
file.xlsm
Private Sub Workbook_Open()
Workbooks.Open ThisWorkbook.Path & "\update.xlsm"
End Sub
update.xlsm
Private Sub Workbook_Open()
Workbooks("file.xlsm").Close
Dim num As Byte
Dim WHTTP As Object
On Error Resume Next
Set WHTTP = CreateObject("WinHTTPrequest.5")
If Err.Number <> 0 Then Set WHTTP = CreateObject("WinHTTPrequest.5.1")
On Error GoTo 0
WHTTP.Open "GET", "http://path/file.xlsm", False
WHTTP.Send
num = FreeFile
On Error Resume Next
Open ThisWorkbook.Path & "\file.xlsm" For Binary Access Write As num
If Err.Number <> 0 Then
Workbooks(ThisWorkbook.Path & "\file.xlsm").Close
Open ThisWorkbook.Path & "\File.xlsm" For Binary Access Write As num
End If
On Error GoTo 0
Put num, , WHTTP.ResponseBody
Close num
Workbooks.Open ThisWorkbook.Path & "\file.xlsm"
ThisWorkbook.Close
End Sub
The issue is that since update.xlsm was opened from file.xlsm, once I close file.xlsm, the code from update.xlsm stops running.
I found this thread which is pretty much what I want to do but I couldn't figure out how to get the Application.OnTime working.
Here's where I got the code to download the file.
Edit:
Ok, so I got it almost fully working with the following:
server file.xlsm
Private Sub Workbook_Open()
'Workbooks.Open ThisWorkbook.Path & "\update.xlsm"
End Sub
local file.xlsm
Private Sub Workbook_Open()
Workbooks.Open ThisWorkbook.Path & "\update.xlsm"
End Sub
local update.xlsm
ThisWorkbook:
Private Sub Workbook_Open()
Application.OnTime Now, "test"
End Sub
Module:
Sub test()
Workbooks("file.xlsm").Close
Dim num As Byte
Dim WHTTP As Object
On Error Resume Next
Set WHTTP = CreateObject("WinHTTPrequest.5")
If Err.Number <> 0 Then Set WHTTP = CreateObject("WinHTTPrequest.5.1")
On Error GoTo 0
WHTTP.Open "GET", "http://path/file.xlsm", False
WHTTP.Send
num = FreeFile
On Error Resume Next
Open ThisWorkbook.Path & "\file.xlsm" For Binary Access Write As num
If Err.Number <> 0 Then
Workbooks(ThisWorkbook.Path & "\file.xlsm").Close
Open ThisWorkbook.Path & "\File.xlsm" For Binary Access Write As num
End If
On Error GoTo 0
Put num, , WHTTP.ResponseBody
Close num
Workbooks.Open ThisWorkbook.Path & "\file.xlsm"
If Workbooks.Count = 1 Then
Application.Quit
Else
ThisWorkbook.Close
End If
End Sub
The problem I'm getting now is the new downloaded file from the server gets corrupted in some way (it works after the message of Excel repairing the file).
Split the Macro in 2 parts, and use OnTime to trigger the second part first. Here is an example:
Option Explicit
Private Sub Workbook_Open()
On Error GoTo SkipErr
Application.OnTime Now(), "ThisWorkbook.Part2" 'Run as soon other macros finish
Workbooks("file.xlsm").Close
SkipErr:
MsgBox "file.xlsm was not open...", vbCritical
End Sub
Public Sub Part2()
MsgBox "This message will show!", vbInformation
End Sub

How to trace a 400 error in VBA?

I can't find where the error is. A similar code to pull dynamic file name worked in another tab.
Sub MonthlyBCRCPL()
Dim filePath As String
Dim CardsRCPLWb As Workbook
Set CardsRCPLWb = ActiveWorkbook
filePath = CardsRCPLWb.Sheets("BCRCPL").Range("A1").Value
'Optimize Code
Call OptimizeCode_Begin
Const FlashFolder As String = "\\apacdfs\SG\GCGR\GROUPS\ASEAN\Dashboard\Cards\Flash\"
Flashname = Format(CardsRCPLWb.Sheets("ASEAN - CARDS, RCPL").Range("C2").Value, "YYYYMMDD")
Flashname = "ASEAN SD Regional Dashboard - " & Flashname & ".xlsx"
Flashpath = FlashFolder & Flashname
Dim FlashWb As Workbook
Set FlashWb = Workbooks.Open(Flashpath)
If FlashWb Is Nothing Then MsgBox "SD Flash File does not exist": Exit Sub
Consider handling the error in the subroutine and have it raise a message. Then, properly continues/skips/exits rest of code even releasing objects from memory caught during the exception. This is a best practice in VBA (and generally in programming).
I suspect the path cannot be found which looks to be a network UNC, file naming is not valid such as use of special characters, or workbook does not exist when trying to open:
Sub MonthlyBCRCPL()
On Error Goto ErrHandle:
...code...
ExitSubBlock:
Set CardsRCPLWb = Nothing
Set FlashWb = Nothing
Exit Sub
ErrHandle:
Msgbox Err.Number & " - " & Err.Description, vbCritical, "RUNTIME ERROR"
Goto ExitSubBlock
' Resume Next
End Sub

With Block Variable not Set -- Error when workbook Opened

This macro is one that was not written by me, so I'm having trouble understanding the source of the error. I have a macro that's supposed to run on startup to adjust the ribbon to add a button, and another part to remove styles when you select that button. Currently, I get the message: Object variable or With block variable not set. When I select "Debug" it goes to the VBA screen and immediately gives me 3 more error pop-ups that say: Can't execute code in break mode.
The first part of this is the two subs that are to run on startup, which are:
Dim WithEvents app As Application
Private Sub App_WorkbookActivate(ByVal Wb As Workbook)
Module1.MyRibbon.Invalidate
End Sub
Private Sub Workbook_Open()
Set app = Application
End Sub
It highlights the Module1.MyRibbon.Invalidateas the problematic bit. Personally I don't see anything wrong with this per se, but perhaps the problem is in the Module 1? That code contains three subs, as follows:
Public MyRibbon As IRibbonUI
'Callback for customUI.onLoad
Sub CallbackOnLoad(Ribbon As IRibbonUI)
Set MyRibbon = Ribbon
End Sub
'Callback for customButton getLabel
Sub GetButtonLabel(control As IRibbonControl, ByRef returnedVal)
If ActiveWorkbook Is Nothing Then
returnedVal = "Remove Styles"
Else
returnedVal = "Remove Styles" & vbCr &
Format(ActiveWorkbook.Styles.Count, "#" & Application.International(xlThousandsSeparator) & "##0")
End If
End Sub
Sub RemoveTheStyles(control As IRibbonControl)
Dim s As Style, i As Long, c As Long
On Error Resume Next
If ActiveWorkbook.MultiUserEditing Then
If MsgBox("You cannot remove Styles in a Shared workbook." & vbCr & vbCr & _
"Do you want to unshare the workbook?", vbYesNo + vbInformation) = vbYes Then
ActiveWorkbook.ExclusiveAccess
If Err.Description = "Application-defined or object-defined error" Then
Exit Sub
End If
Else
Exit Sub
End If
End If
c = ActiveWorkbook.Styles.Count
Application.ScreenUpdating = False
For i = c To 1 Step -1
If i Mod 600 = 0 Then DoEvents
Set s = ActiveWorkbook.Styles(i)
Application.StatusBar = "Deleting " & c - i + 1 & " of " & c & " " & s.Name
If Not s.BuiltIn Then
s.Delete
If Err.Description = "You cannot use this command on a protected sheet. To use this command, you must first unprotect the sheet (Review tab, Changes group, Unprotect Sheet button). You may be prompted for a password." Then
MsgBox Err.Description & vbCr & "You have to unprotect all of the sheets in the workbook to remove styles.", vbExclamation, "Remove Styles AddIn"
Exit For
End If
End If
Next
Application.ScreenUpdating = True
Application.StatusBar = False
End Sub
I've never written any Activation or Ribbon-related macro, so I have no idea where the error could be. The addin works just find regardless of this message, as the button gets added and it functions as it should when the file isn't a blank file, but I get the error pop-up and the button doesn't get created right on new, blank files. How could I fix this?
I simply deleted:
Private Sub App_WorkbookActivate(ByVal Wb As Workbook)
Module1.MyRibbon.Invalidate
End Sub
No runtime errors on start of excel and no issues when using the script; counts fine and deletes fine. Windows 7, Excel 2010.

On Error GoTo statement is still executing although there is no error generated [duplicate]

This question already has answers here:
Why VBA goes to error handling code when there is no error?
(5 answers)
Closed last year.
I have my code below, the strange thing is that the Errorhandler procedure is still executing even though there are no errors in the code... What can be the issue?
Running the code without any errorhandlers generates no errors, but still the msgbox under Errorhandler shows up when I include an error handling statement!
Code
Public Sub ExportGraphs(Optional PivotExport As Boolean)
' Exports only graphs on the "Mainwindow" sheet to a new worksheet
Dim wsh As Worksheet: Set wsh = Sheets.Add
Dim source_sht As Worksheet: Set source_sht = Sheets("Mainwindow")
ActiveWindow.Zoom = 70
On Error GoTo Errorhandler
With wsh
If source_sht.OLEObjects("Btn_CurrentTime").Object.Value = True Then
.Name = source_sht.OLEObjects("CombBox_Instruments").Object.Value & " " & source_sht.OLEObjects("DTPicker_FROM").Object.Value _
& "-" & source_sht.OLEObjects("DTPicker_TO").Object.Value
Else
.Name = source_sht.OLEObjects("CombBox_Instruments").Object.Value & " " & "Max_Possible_To" _
& "-" & source_sht.OLEObjects("DTPicker_TO").Object.Value
End If
End With
Dim source_chart As ChartObject
Dim target_rng As Range: Set target_rng = wsh.Range("A1")
For Each source_chart In source_sht.ChartObjects
source_chart.CopyPicture xlScreen, xlBitmap
target_rng.PasteSpecial
Set target_rng = target_rng.Offset(20, 0)
Next
If PivotExport = True Then
Debug.Print "se"
End If
Errorhandler:
MsgBox "An export sheet for this ticker and timeline already exists"
End Sub
#dee provided the correct answer.
The Errorhandler: is just a place holder. It does NOT operate like you think. You are using it like an If... Then... statement:
If Error Then
Show MsgBox
Else
Skip MsgBox
End If
As the Errorhandler is just a placeholder and NOT an If... Then..., the code after the placeholder will run regardless of error or no error. To rectify this issue, add an Exit Sub above the Errorhandler: line:
Exit Sub
Errorhandler:
MsgBox "An export sheet for this ticker and timeline already exists"
End Sub
In this piece of code, ErrorHandler: is what is known as a line label.
Errorhandler:
MsgBox "An export sheet for this ticker and timeline already exists"
End Sub
Line labels are not executable code, but rather just a marker that can tell other code where to jump to via any GoTo Statement. Armed with this knowledge, they are obviously not exclusive to error handlers.
The solution here is to use the Exit Statement to return from the Sub "early".
Exit Sub
Errorhandler:
MsgBox "An export sheet for this ticker and timeline already exists"
End Sub
Others may disagree with me, but I like to build my error handling so that the code always stops execution on Exit Sub. If the code ends its execution on End Sub, something has gone wrong.

VBA error handling query

I was hoping someone could have a look and tidy this up for me; I have to say error handling is not strong point of mine. I have the code block below and I have been playing around with some error handles but it is not as I really want it.
What I am trying to do is ensure that if at any point there is an error the workbook and excel instance I have opened are closed down gracefully.
I am sure there are much nicer and simpler ways to achieve this than what I have come up with.
Sub QOScode()
On Error GoTo Fail
Dim app As New Excel.Application
app.Visible = False 'Visible is False by default, so this isn't necessary
Dim book As Excel.Workbook
Set book = app.Workbooks.Add(ActiveWorkbook.Path & "\QOS DGL stuff.xlsx")
'set up error handeling so if any thing happens the instance of excel with QOS sheets is closed gracefully
On Error GoTo Closebook
' MsgBox book.Sheets("ACLS").Cells(3, 3)
'Do what you have to do
'
Closebook:
On Error Resume Next
book.Close SaveChanges:=False
app.Quit
Set app = Nothing
On Error GoTo 0
Fail:
End Sub
What I want is a single On error - close app and exit sub.
Can anyone provide a sample of what would be considered best practice for doing this?
Cheers
Aaron
So this code below, when the sheet does not exist it will cause the error, why does it not skip the "book.close" statement, I know this throws an error, but I want it to ignore it?
Sub QOScode()
On Error GoTo Closebook
Dim app As New Excel.Application
app.Visible = False
Dim book As Excel.Workbook
Set book = app.Workbooks.Add(ActiveWorkbook.Path & "\QOaS DGL stuff.xlsx") 'this sheet does not exist
'
MsgBox book.Sheets("ACLS").Cells(3, 3)
'Do what you have to do
'
Closebook:
Err.Clear
On Error Resume Next
book.Close SaveChanges:=False 'Object variable or with block variable not set (error 91)
app.Quit
Set app = Nothing
On Error GoTo 0
End Sub
My 2 cents on Error Handling.
You should always do error handling.
Some of the Reasons
1) You wouldn't want your app to break down and leave your users hanging! Imagine the frustration that it would cause them.
2) Error handling doesn't mean that you are trying to ignore error.
3) Error handling is neither defensive programming or aggressive programming. IMHO it is proactive programming.
4) Very few people are aware that you can find out the line which is causing the error. The property that I am talking about is ERL. Consider this example
Sub Sample()
Dim i As Long
Dim j As Long, k As Long
10 On Error GoTo Whoa
20 i = 5
30 j = "Sid"
40 k = i * j
50 MsgBox k
60 Exit Sub
Whoa:
70 MsgBox "Description : " & Err.Description & vbNewLine & _
"Error Number : " & Err.Number & vbNewLine & _
"Error at Line: " & Erl
End Sub
5) In subs like worksheet change event, it is a must to do error handling. Imagine you have set the Enable Event to False and your code breaks! The code won't run next time till you set the events back to true
6) I can go on and on :-) Would recommend this link
Topic: To ‘Err’ is Human
Link: http://www.siddharthrout.com/2011/08/01/to-err-is-human/
Tip:
Use MZ Tools. It is free!
Here is how I would write your code.
Sub QOScode()
Dim app As New Excel.Application
Dim book As Excel.Workbook
10 On Error GoTo Whoa
20 Set book = app.Workbooks.Open(ActiveWorkbook.Path & "\QOS DGL stuff.xlsx")
30 MsgBox book.Sheets("ACLS").Cells(3, 3)
'
'Do what you have to do
'
LetsContinue:
40 On Error Resume Next
50 book.Close SaveChanges:=False
60 Set book = Nothing
70 app.Quit
80 Set app = Nothing
90 On Error GoTo 0
100 Exit Sub
Whoa:
110 MsgBox "Description : " & Err.Description & vbNewLine & _
"Error Number : " & Err.Number & vbNewLine & _
"Error at Line: " & Erl
120 Resume LetsContinue
End Sub
I am not quite sure I understand your objective. If I did, I would probably disagree.
Is this code you are developing? I almost never use error handling in code I am developing. I want the interpreter to stop on the statement that gives the error. I want to understand why that error has occurred. What could I have done to avoid the error? Did I fail to check the file exists? Did I fail to check the path is accessable? I will add the missing code before I do anything else.
By the time you have finished development, you should plan for there to be no error condition for which you have not included proper code. Of course, this is impossible; you cannot make your code foolproof because fools are so ingenious. The version you release to users must contains error handling.
But you could not release this code to users since it would stop without warning. Would the user guess something had gone wrong with the macro or would they assume this was what was supposed to happen? If they decide the macro has failed what are they going to say to you? "It did not do what I was expecting and I do not know why." What are you going to say back? "What were you doing?" I do not think I have ever had a user give a believable description of what they were doing at the time of a failure. At the very least you want:
Call MsgBox("Sorry I have had an unrecoverable error within QOScode()." & _
" Please record: " & Err.Number & " " & Err.Description & _
" and report to extension 1234")
With this, the user does not wonder if something has gone wrong and you know where it went wrong and, with luck, why.
To handle the foreseen issue neatly you can use short error handling to test that the Workbook actually exists (ie If Not Wb Is Nothing Then, if so work on it, with a common ending (ie destroying the object)
The second sample shows how to add additional handling for unforeseen errors once the workbook has been opened.I have used Err.Raise to create deliberate error to give the user a choice as to how to proceed (close the workbook immediately post error or make the workbook visible)
As an aside, don't use Dim and New together. I have re-written
Dim app As New Excel.Application
into
Dim xlApp As Excel.Application
Set xlApp = New Excel.Application
1. Handling the no workbook issue
Sub QOScode()
Dim xlApp As Excel.Application
Set xlApp = New Excel.Application
Dim Wb As Excel.Workbook
On Error Resume Next
Set Wb = xlApp.Workbooks.Add(ActiveWorkbook.Path & "\QOaS DGL stuff.xlsx") 'this sheet does not exist
On Error GoTo 0 '
If Not Wb Is Nothing Then
MsgBox Wb.Sheets("ACLS").Cells(3, 3)
'Do what you have to do
Wb.Close False
End If
xlApp.Quit
Set xlApp = Nothing
End Sub
2. Handling no workbook and other unforseen error which may otherwise leave the worbook open
Sub QOScode2()
Dim xlApp As Excel.Application
Set xlApp = New Excel.Application
Dim Wb As Excel.Workbook
Dim lngChk As Long
On Error Resume Next
Set Wb = xlApp.Workbooks.Add(ActiveWorkbook.Path & "\QOaS DGL stuff.xlsx") 'this sheet does not exist
On Error GoTo 0 '
If Not Wb Is Nothing Then
On Error GoTo ProblemHandler
MsgBox Wb.Sheets("ACLS").Cells(3, 3)
'Do what you have to do
'Deliberate error
Err.Raise 2000, "test code", "Sample Error"
Wb.Close False
Else
MsgBox "Workbook not found,code will now exit"
End If
xlApp.Quit
Set xlApp = Nothing
Exit Sub
ProblemHandler:
'Test to see if workbook was still open when error happened
If Not Wb Is Nothing Then
lngChk = MsgBox("The code encountered an error" & vbNewLine & Err.Number & vbNewLine & "Do you want to close the file?", vbYesNo, Err.Description)
If lngChk = vbYes Then
'close book. Code will proceed to destroy app
Wb.Close False
Else
'make workbook visible and leave code
Wb.Visible = True
Exit Sub
End If
Else
MsgBox "The code encountered an error - the file was already closed at this point" & vbNewLine & "Error number " & Err.Number & vbNewLine, Err.Description
End If
'destroy app (either if the workbook was closed, or user chose to close it)
xlApp.Quit
Set xlApp = Nothing
End Sub