Forum Discussion
"Method 'Calculation' of object '_Application' failed" error occurs on unpredictable attempts
The error "Method 'Calculation' of object '_Application' failed" is notoriously vague, but its intermittent nature is the biggest clue. It almost always points to a race condition or an unstable application state caused by how your code interacts with the Excel environment, especially when combined with userforms and screen updating.
I Think the error happens on this line: Application.Calculation = xlCalculationManual. You are trying to change a global application setting. The failure means Excel is in a state where it cannot process this request at that exact moment.
Here my solution approach with some Key Improvements (Replaced On Error Resume Next with a proper On Error GoTo ErrorHandler - The CleanExit block is now the only exit point, besides End Sub - The code now captures selectedRow = Selection.Row at the very beginning - The SetAppState helper sub makes the main code cleaner and less error-prone - The wait form is shown after the application state is set to "busy" - Using worksheet variables (wsProd, wsBkg) makes the code easier). Hope that Helps in your Projekt.
' Helper sub to manage application state
Private Sub SetAppState(ByVal isBusy As Boolean)
Static originalCalculation As XlCalculation
Static originalEvents As Boolean
Static originalScreenUpdating As Boolean
Static originalUpdateRemoteRefs As Boolean
Static originalDisplayStatusBar As Boolean
If isBusy Then
' Store original states first time
If originalCalculation = 0 Then
originalCalculation = Application.Calculation
originalEvents = Application.EnableEvents
originalScreenUpdating = Application.ScreenUpdating
originalUpdateRemoteRefs = ActiveWorkbook.UpdateRemoteReferences
originalDisplayStatusBar = Application.DisplayStatusBar
End If
' Turn everything OFF for speed/stability
On Error Resume Next ' Just in case calculation change fails
Application.Calculation = xlCalculationManual
Application.EnableEvents = False
Application.ScreenUpdating = False
ActiveWorkbook.UpdateRemoteReferences = False
Application.DisplayStatusBar = False
On Error GoTo 0
Else
' Restore original states
On Error Resume Next
If originalCalculation <> 0 Then
Application.Calculation = originalCalculation
Application.EnableEvents = originalEvents
Application.ScreenUpdating = originalScreenUpdating
ActiveWorkbook.UpdateRemoteReferences = originalUpdateRemoteRefs
Application.DisplayStatusBar = originalDisplayStatusBar
Else
' Fallback to defaults
Application.Calculation = xlCalculationAutomatic
Application.EnableEvents = True
Application.ScreenUpdating = True
ActiveWorkbook.UpdateRemoteReferences = True
Application.DisplayStatusBar = True
End If
On Error GoTo 0
' Reset stored states
originalCalculation = 0
End If
End Sub
Private Sub CommandButton2_Click() 'Save
' --- PREPARATION ---
' Declare all variables at the top
Dim wsProd As Worksheet, wsBkg As Worksheet
Dim rng As Range, cell As Range
Dim first_DB_avail_row As Range
Dim Highest_Version_Row As Long
Dim existingVersions() As String
Dim ver_find As Variant
Dim ver_list As Object: Set ver_list = CreateObject("System.Collections.ArrayList")
Dim padded_list As Object: Set padded_list = CreateObject("System.Collections.ArrayList")
Dim v As Variant, parts As Variant
Dim padded_v As String, leadChar As String, all_vers As String
Dim i As Long 'Use Long instead of Integer for row counts
Dim productID_To_Find As String
Dim newVersionString As String
Dim selectedRow As Long '*** CRITICAL: Store the selected row number explicitly ***
Dim destRow As Range
Dim srcDevRow As Range
' --- INITIAL SETUP & VALIDATION ---
On Error GoTo ErrorHandler 'Use a proper error handler
' Set worksheet objects to avoid repeated lookups
Set wsProd = ThisWorkbook.Sheets("Products")
Set wsBkg = ThisWorkbook.Sheets("Background Data")
' *** CRITICAL FIX: Capture the active row BEFORE any UI changes ***
If TypeName(Selection) <> "Range" Then
MsgBox "Please select a product row first.", vbExclamation, "Business Manager"
GoTo CleanExit
End If
selectedRow = Selection.Row
If selectedRow < 4 Then 'Basic validation - assuming data starts at row 4
MsgBox "Please select a valid product row (row 4 or greater).", vbExclamation, "Business Manager"
GoTo CleanExit
End If
productID_To_Find = wsProd.Range("E" & selectedRow).Value
If productID_To_Find = "" Then
MsgBox "The selected row does not have a Product ID.", vbExclamation, "Business Manager"
GoTo CleanExit
End If
newVersionString = stage_entry & Major & Minor & Patch
'Handle first version case
If Me.Caption = "First Version - Business Manager" Then
If Me.ComboBox1.Value = "" Or Me.TextBox1.Value = "" Or _
Me.TextBox2.Value = "" Or Me.TextBox3.Value = "" Then
MsgBox "You must complete all fields.", vbExclamation, "Business Manager"
GoTo CleanExit
End If
Insert_Product.ver_val = newVersionString
Unload Me
Insert_Product.new_product_ver_cancel = False
GoTo CleanExit
End If
' Validate entries for non-first version
If Me.ComboBox1.Value = "" Or Me.TextBox1.Value = "" Or _
Me.TextBox2.Value = "" Or Me.TextBox3.Value = "" Then
MsgBox "You must complete all version fields.", vbExclamation, "Business Manager"
GoTo CleanExit
End If
'Check for existing versions
Call Find_Latest_Ver 'Get the current latest version
If newVersionString = Highest_Version Then
MsgBox "This version already exists (as the newest version).", vbExclamation, "Business Manager"
GoTo CleanExit
End If
If Me.TextBox4.Value <> "" Then
existingVersions = Split(Replace(Me.TextBox4.Value, vbCrLf, ""), "• ")
For Each ver_find In existingVersions
If Trim(ver_find) = newVersionString Then
MsgBox "This version already exists.", vbExclamation, "Business Manager"
GoTo CleanExit
End If
Next ver_find
End If
' --- START LONG-RUNNING PROCESS ---
Me.Hide 'Hide the form
' Set application state for performance/stability
SetAppState True
' Show wait form modelessly
PLZ_WAIT.Show vbModeless
PLZ_WAIT.Label2.Caption = "Setting new version..."
DoEvents
' --- CORE LOGIC ---
' Unprotect sheet
wsProd.Unprotect Password:=wsBkg.Range("CY39").Value
' Pull data from the latest version
Dim foundLatest As Boolean
foundLatest = False
Set rng = wsBkg.Range("E4:E7503")
For Each cell In rng.Cells
If cell.Value = productID_To_Find Then
If cell.Offset(0, -2).Value = Highest_Version Then
' Copy values from the latest version's row to the selected row
With wsProd.Rows(selectedRow)
.Cells(1, "B").Value = cell.Offset(0, -3).Value 'Name
.Cells(1, "C").Value = newVersionString 'Product Version
.Cells(1, "D").Value = cell.Offset(0, -1).Value 'File
.Cells(1, "E").Value = cell.Value 'ID Number
.Cells(1, "F").Value = cell.Offset(0, 1).Value 'Category
.Cells(1, "G").Value = cell.Offset(0, 2).Value 'Details (Description)
.Cells(1, "K").Value = cell.Offset(0, 6).Value 'Release Date
.Cells(1, "L").Value = cell.Offset(0, 7).Value 'Copyright Y/N button
.Cells(1, "M").Value = cell.Offset(0, 8).Value 'Copyright Status
.Cells(1, "N").Value = cell.Offset(0, 9).Value 'Year
.Cells(1, "O").Value = cell.Offset(0, 10).Value 'Copyright Statement
.Cells(1, "P").Value = cell.Offset(0, 11).Value 'Published Y/N button
.Cells(1, "Q").Value = cell.Offset(0, 12).Value 'Publish Status (Date)
.Cells(1, "R").Value = cell.Offset(0, 13).Value 'Web Link
.Cells(1, "S").Value = cell.Offset(0, 14).Value 'Withdraw Date
End With
Highest_Version_Row = cell.Row
foundLatest = True
Exit For
End If
End If
Next cell
If Not foundLatest Then
MsgBox "Could not find the data for the latest version ('" & Highest_Version & "') to copy from.", vbCritical, "Error"
GoTo ErrorHandler
End If
' Save new version to version database
Set first_DB_avail_row = wsBkg.Range("C7506").End(xlUp).Offset(1, 0)
Set destRow = first_DB_avail_row.EntireRow
' Copy product data to database
destRow.Cells(1, "B").Value = wsProd.Cells(selectedRow, "B").Value 'Name
destRow.Cells(1, "C").Value = wsProd.Cells(selectedRow, "C").Value 'Product Version
destRow.Cells(1, "D").Value = wsProd.Cells(selectedRow, "D").Value 'File
destRow.Cells(1, "E").Value = wsProd.Cells(selectedRow, "E").Value 'ID Number
destRow.Cells(1, "F").Value = wsProd.Cells(selectedRow, "F").Value 'Category
destRow.Cells(1, "G").Value = wsProd.Cells(selectedRow, "G").Value 'Details (Description)
destRow.Cells(1, "K").Value = wsProd.Cells(selectedRow, "K").Value 'Release Date
destRow.Cells(1, "L").Value = wsProd.Cells(selectedRow, "L").Value 'Copyright Y/N button
destRow.Cells(1, "M").Value = wsProd.Cells(selectedRow, "M").Value 'Copyright Status
destRow.Cells(1, "N").Value = wsProd.Cells(selectedRow, "N").Value 'Year
destRow.Cells(1, "O").Value = wsProd.Cells(selectedRow, "O").Value 'Copyright Statement
destRow.Cells(1, "P").Value = wsProd.Cells(selectedRow, "P").Value 'Published Y/N button
destRow.Cells(1, "Q").Value = wsProd.Cells(selectedRow, "Q").Value 'Publish Status (Date)
destRow.Cells(1, "R").Value = wsProd.Cells(selectedRow, "R").Value 'Web Link
destRow.Cells(1, "S").Value = wsProd.Cells(selectedRow, "S").Value 'Withdraw Date
' Copy Development Status Data from latest version
Set srcDevRow = wsBkg.Rows(Highest_Version_Row)
' Use bulk copy for efficiency
destRow.Cells(1, "T").Resize(1, 7).Value = srcDevRow.Cells(1, "T").Resize(1, 7).Value 'Title through Dev Log (1)
destRow.Cells(1, "AA").Resize(1, 3).Value = srcDevRow.Cells(1, "AA").Resize(1, 3).Value 'Framework through Stage
destRow.Cells(1, "DA").Resize(1, 7).Value = srcDevRow.Cells(1, "DA").Resize(1, 7).Value 'Dev Logs (2-7)
destRow.Cells(1, "AD").Resize(1, 13).Value = srcDevRow.Cells(1, "AD").Resize(1, 13).Value 'Bugs through Customer Request
' --- VERSION LIST & VALIDATION ---
' Build version list
ver_list.Add newVersionString
For Each cell In rng.Cells
If cell.Value = productID_To_Find Then
ver_list.Add cell.Offset(0, -2).Value
End If
Next cell
' Sort versions with padding technique
For i = 0 To ver_list.Count - 1
v = ver_list(i)
If Len(v) > 0 And Left(v, 1) Like "[A-Z]" And InStr(v, ".") > 0 Then
leadChar = Left(v, 1)
parts = Split(Mid(v, 2), ".")
If UBound(parts) >= 2 Then
padded_v = leadChar
padded_v = padded_v & Right("000" & parts(0), 3)
padded_v = padded_v & Right("000" & parts(1), 3)
padded_v = padded_v & Right("000" & parts(2), 3)
ver_list(i) = padded_v & "|" & v
End If
End If
Next i
' Sort descending
ver_list.Sort
ver_list.Reverse
' Reconstruct version list
For i = 0 To ver_list.Count - 1
If InStr(ver_list(i), "|") > 0 Then
ver_list(i) = Split(ver_list(i), "|")(1)
End If
Next i
' Create validation list string
all_vers = "," & Join(ver_list.ToArray, ",")
' Apply validation to the version cell
With wsProd.Cells(selectedRow, "C").Validation
.Delete
.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, _
Operator:=xlBetween, Formula1:=all_vers
.IgnoreBlank = True
.InCellDropdown = True
.InputTitle = ""
.ErrorTitle = ""
.InputMessage = ""
.ErrorMessage = ""
.ShowInput = False
.ShowError = False
End With
' Re-protect sheet
wsProd.Protect Password:=wsBkg.Range("CY39").Value
' --- FINALIZATION ---
Sheet2.UPDATE_DB_FORCE = True
' Pass the specific cell that changed
Application.Run "Sheet2.Worksheet_Change", wsProd.Cells(selectedRow, "C")
Sheet2.UPDATE_DB_FORCE = False
MsgBox "New version '" & newVersionString & "' created successfully!", vbInformation, "Success"
Unload Me
CleanExit:
' This section runs whether there's an error or not
' Restore application state
SetAppState False
' Clean up UI
On Error Resume Next
Unload PLZ_WAIT
On Error GoTo 0
' Release all object variables
Set wsProd = Nothing
Set wsBkg = Nothing
Set rng = Nothing
Set cell = Nothing
Set first_DB_avail_row = Nothing
Set destRow = Nothing
Set srcDevRow = Nothing
If Not ver_list Is Nothing Then
ver_list.Clear
Set ver_list = Nothing
End If
Set padded_list = Nothing
Exit Sub 'Normal exit
ErrorHandler:
' This section only runs when an actual error occurs
MsgBox "An unexpected error occurred:" & vbCrLf & _
"Error #" & Err.Number & ": " & Err.Description & vbCrLf & _
"The operation has been cancelled. Please try again.", vbCritical, "Business Manager"
' Jump to cleanup section to restore state
Resume CleanExit
End SubThe code is not Tested, save your file as a backup before.
Hello again :) Thank you for the insight! I'm not too familiar with what a Static variable is but hasn't been tried in my work yet. With that said, across all my userforms, I pretty much do a variable declare, then validation, then set macro enhancement, then the code. This one just doesn't set any of the application states ("Macro Enhancement - Start:") sometimes, but then other times, does it with no issues at all. I would get the error 1 time then good for 3 times of save in a row, or: 2-to-4, 1-to-6, 3-to-1, or any random consecutive number of error-to-good times.
No issues in other userforms and would be good random times in this one so it doesn't make sense. Anyway, what I wanted to ask before trying that is if I can keep this in one sub and have my same "MEM_CLEAN:" structure, before moving on with your suggestions?