code does only run correctly in break mode - excel

After hours and days of searching the web in order to find a hint how to fix a bug in my code, I am completely clueless about what might be going on, and am hoping to get some advise from this community.
The code is somewhat complicated, therefore I will not add any snippets, but rather try to explain as simple as I can get it.
I have created a tool (excel macro) that does a lot of analyses on certain data, collected at customer sites using our software (mostly multiple users)
This tool runs well since years, including e.g. filtering to only take into account users that match certain criteria
I want to expand that tool in a way so that it automatically runs multiple times - once for each user.
The way how this works is:
The tool processes data from the first user, and saves the result as a new excel spreadsheet (in which the code continues to run).
the tool processes data from the next user, and again saves the result as a new spreadsheet, and so on.
In the second run the weird behaviour happens: If run in regular mode, the code breaks due to an error; if the code is interrupted by a 'stop' right before the line producing the error and code completion is continued, everything works perfectly fine.
The problem occurs at assignment of a table as range:
Dim rr As Range
Set rr = Workbooks(actWBK).Worksheets(shtName).Range(tableName & "[[#All],[" & header & "]]")
From the second run onwards, the line starting with Set... produces an error (application-defined or object-defined error).
The fact that this assignment works perfectly in the first run made me believe that there is some kind of unspecified assignment to a workbook or the like, but I tested all options and could rule that out;
The really staggering thing is that, as mentioned, when I add a "stop" before, the code works perfectly fine.
I am really out of any ideas, so every answer is more than welcome!
Thank you in advance,
Alexander
I will try to add some code.
The problem occurs in the module sortTable (relevant part after "code here", I always use this kind of "template" to set some standard things):
Sub sortTable(sheetName As String, tableName As String, header As String, dir As XlSortOrder)
' here only logging and error handling settings
'---------------------------------------------------------------------------------------
' code here
'---------------------------------------------------------------------------------------
' deal with #-sign in header
Dim headerParts() As String
headerParts = Split(header, "#")
Dim cleanHeader As String
If UBound(headerParts) = -1 Then
successcode = 2
GoTo errorHandler
ElseIf UBound(headerParts) = 0 Then
cleanHeader = header
Else
cleanHeader = headerParts(0)
Dim i As Integer
For i = 1 To UBound(headerParts)
cleanHeader = cleanHeader & "'#" & headerParts(i)
Next i
End If
' sorting
Dim actWBK As String
actWBK = ActiveWorkbook.name
Dim rr As Range
Set rr = Workbooks(actWBK).Worksheets(sheetName).Range(tableName & "[[#All],[" & cleanHeader & "]]")
ActiveWorkbook.Worksheets(sheetName).ListObjects(tableName).Sort.SortFields _
.Clear
ActiveWorkbook.Worksheets(sheetName).ListObjects(tableName).Sort.SortFields _
.Add key:=Range(tableName & "[[#All],[" & cleanHeader & "]]"), SortOn:=xlSortOnValues, Order _
:=dir, DataOption:=xlSortNormal
With ActiveWorkbook.Worksheets(sheetName).ListObjects(tableName).Sort
.header = xlYes
.MatchCase = True
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
'---------------------------------------------------------------------------------------
' sub cleanup on exit; don't make changes below this line
'---------------------------------------------------------------------------------------
' here only logging and error handling
End Sub
The procedure is called from a different module called QuickSort which takes as argument an array:
Public Sub QuickSort(vArray As Variant)
' here only logging and error handling
Dim wsName As String
wsName = "tempSort"
Application.DisplayAlerts = False
On Error Resume Next
Sheets(wsName).Delete
On Error GoTo errorHandler
Application.DisplayAlerts = True
Worksheets.Add After:=Sheets(Sheets.count)
ActiveSheet.name = wsName
Cells(1, 1) = "Header"
Dim rr As Range
Set rr = Range(Cells(2, 1), Cells(UBound(vArray) + 2 - LBound(vArray), 1))
Set rr = rr.Resize(UBound(vArray) + 1 - LBound(vArray), 1)
rr.value = myTransposeArray(vArray)
Set rr = Nothing
ActiveSheet.ListObjects.Add( _
xlSrcRange, _
Range(Cells(1, 1), Cells(UBound(vArray) + 2 - LBound(vArray), 1)), _
, xlYes).name = "tempSortTable"
sortTable sheetName:=wsName, tableName:="tempSortTable", header:="Header", dir:=xlAscending
' more code hereafter

Try changing this
Dim actWBK As String
actWBK = ActiveWorkbook.name
Dim rr As Range
Set rr = Workbooks(actWBK).Worksheets(sheetName).Range(tableName & "[[#All],[" & cleanHeader & "]]")
To
Dim actWbk as workbook
Set actwbk = activeworkbook
dim ws as worksheet
set ws = actwbk.worksheets(sheetname)
dim s as string
s = tableName & "[[#All],[" & cleanHeader & "]]"
Dim rr as range
Set rr = ws.range(s)
Then when it breaks you can inspect each in turn to see if they point to what you think they should

A collegue of mine found a workaround to overcome the problem (all credits onto you, Thomas!):
instead of referencing the range as
Set rr = Workbooks(actWBK).Worksheets(sheetName).Range(tableName & "[[#All],[" & cleanHeader & "]]")
I changed the code to
Set rr = Workbooks(actWBK).Worksheets(sheetName).ListObjects(tableName).ListColumns(cleanHeader).Range
By that, everything works perfectly fine, no matter if in the first run or in subsequent runs.
There is also a suspicion what might cause the problem (which clearly is not resolved itself, this solution is just a workaround!), and it has to do with something going on during saving the workbook using SaveAs.
I am not clear at all what could be this reason, but for those who face a similar problem, I'd like to explain what I did in my code:
By opening a file containing the tool
AnalysisTool.xlsm
the macro starts running. In order to get data, the code opens an xml file as excel table; this table temporarily is called something like
Book1.xlsx
The code copies the data from Book1 to AnalysisTool; in order to remain the tool unchanged, the file is saved as something like
AnalysisResult_20180222_01.xlsm <- this is the file in which code is executed!
Book1 is closed without saving.
When the analysis is finished, the workbook is saved without close.
Upon re-run,
All result tabs in AnalysisResult_20180222_01.xlsm are deleted, a new xml data file is opened, data is copied, and the code-bearing file is saved as
AnalysisResult_20180222_02.xlsm <- this is the file in which code now is executed!
etc.
As I said, I am not sure what goes wrong, but by changing this one line as described makes everything work perfectly fine.
Hope this might be helpful to anybody!

Related

Excel VBA Workbook.Save Method taking >1 minute for changes on only 1 of 3 worksheets

I have a very odd duck problem with Excel VBA. I have a data file that is opened in VBA, written to and then closed. I have three separate worksheets within this same file that are similar but not the same, but none of them contain shapes, or other objects and relatively small amounts of data (usually less than 1000 rows by no more than 30 columns -- mostly numeric constant values) are being pasted into these worksheets. When two of the sheets are modified, it saves lickety split with no issues, but the third worksheet takes in excess of one minute to complete the save operation. The preceding code is almost exactly the same.
Set WBs = ThisWorkbook
Set WSs = WBs.Worksheets("SourceData")
LastRow = WSs.Range("B" & Rows.Count).End(xlUp).Row 'Finds row number of last row of data
Set WBd = OpenWorkbook(FileNam, FullPath:=True)
Set WSd = WBd.Worksheets("TroubledWorksheet")
''' CODE FOR COPYING DATA '''
Set Rng = WSs.Range("A20:AJ" & LastRow + 1)
WSd.Range("A2:AJ" & LastRowD).Clear
Rng.Copy WSd.Range("A2") 'copies all data from source to dest file
WSs.Columns("A:AI").Copy 'copy column width from source
WSd.Columns("A:AI").PasteSpecial Paste:=xlPasteColumnWidths 'paste column width to dest
ActiveWindow.DisplayZeros = False 'hides zeros in cells if formulas output is zero
WSd.Cells.FormatConditions.Delete 'clears Conditional Formatting for entire Sheet
WBd.Activate
WSd.Select
WSd.Range("A1").Select
Application.CalculateBeforeSave = False
' WBd.Save
WBd.Close SaveChanges:=True
Application.CalculateBeforeSave = True
I have uncommented the .Save in the above code with the same effect. I have also removed the .CalculateBeforeSave flags being set, also with no difference.
OpenWorkbook is a helper function that I use to open all of my workbooks.
''' ***************************************************************************
''' * OpenWorkbook()
''' * Preconditions: None
''' * Input: fname - File name
''' * show - boolean to show the workbook after opening
''' * FullPath - Boolean saying wheter it is partial or full path to wb
''' * Readonly - To open as Read Only or not
''' * Output: The Workbook Object
''' * This returns a workbook object of the specified file name. Checks to see
''' * if the Workbook is already open
''' ***************************************************************************
Public Function OpenWorkbook(fname As String, _
Optional show As Boolean = True, _
Optional FullPath As Boolean = False, _
Optional ReadOnly As Boolean = False, _
Optional UpdateLinks As Boolean = False, _
Optional AutoSave As Boolean = False) As Workbook
Dim wb As Workbook
Dim myFileName As String
Dim wbPath As String
Dim aPath() As String
On Error GoTo OpenWorkbookError
'If GEN_DEBUGGING Then Debug.Print "Enter OpenWorkbook #" & TimeInMS
Application.DisplayAlerts = False
Application.AskToUpdateLinks = False
wbPath = IIf(FullPath, fname, ReturnPath(fname))
If Right(wbPath, 4) Like "*xls*" Then
myFileName = wbPath
ElseIf Left(fname, 1) = "\" Or Left(fname, 1) = "/" Then
myFileName = wbPath & Mid(fname, 2) 'SelectFile(wbPath)
Else
myFileName = wbPath & fname
End If
On Error Resume Next
aPath = Split(myFileName, Delimeter)
Set wb = Workbooks(aPath(UBound(aPath)))
If wb Is Nothing Then Set wb = Workbooks.Open(myFileName, UpdateLinks:=UpdateLinks, ReadOnly:=ReadOnly)
On Error GoTo OpenWorkbookError
If wb Is Nothing Then
Err.Raise vbObjectError + 514, "Helper.OpenWorkbook", _
"Unable to Open " & myFileName & " Workbook"
Exit Function
Else
On Error Resume Next
wb.AutoSaveOn = AutoSave
On Error GoTo OpenWorkbookError
wb.Windows(1).Visible = show
End If
Set OpenWorkbook = wb
OpenWorkbookExit:
Application.DisplayAlerts = True
On Error GoTo 0
Exit Function
OpenWorkbookError:
MsgBox "Please ensure the workbook you are trying to open is at the specified location: " & _
vbCrLf & fname, vbCritical + vbOKOnly, "Error Opening Workbook"
HandleError "Helper.OpenWorkbook()"
Resume OpenWorkbookExit
End Function
This slow save for only one of the sheets has been observed by other members of my company. I have tried to pause the code before the save and save the workbook manually with the same result of a very prolonged save. Once I have saved it the first time it resumes normal behavior and saves quickly either in code or in the Excel application.
Any pointers or help would be greatly appreciated.
EDIT 1: I've updated the code for more completeness
EDIT 2: There was a similar post here: Too long saving time in Excel via VBA but it resolved itself. The problem I am experience is taking longer and longer. Today it took 11 minutes to save the file. The hangup is only on the .Save everything runs like clockwork right up until that point.
EDIT 3: It appears that some of the time it is now saving quickly and at other times it has continued to act slowly. There is no rhyme or reason behind these differences that I can pinpoint, they all occur when the data file was already created and previously saved, but other than that I am stumped.
EDIT 4: Resurrecting this post because this is becoming a rather serious slow-down in the operation. This behavior is only for Sheet(1) of the 3-sheet workbook, if I save to the other two sheets, this problem is non-existent. If I create a fresh workbook in code (a common occurrence) this problem does not happen, it is only when the data on Sheet(1) is replaced by the new data that we see this problem. Hopefully someone out there has seen something like this.
check your strategy for last row
LastRow = WSs.Range("B" & Rows.Count).End(xlUp).Row 'Finds row number of last row of data
can return ALL the worksheet, provoking lack of performance

VBA Find and Replace within a For loop not replacing as expected

I'm taking Excel worksheets and putting them into XML format, to then import to SQL. I have a worksheet of a list of file links, called "Files List". The code opens up the necessary sheet within the file links and puts the data into a sheet called "XML format", which is suitable to then import to SQL. The issue is that the Find and Replace within the loop of transferring the data does run, but not seem to get passed the first "Files List" reference.
Sub LinkFile()
Application.ScreenUpdating = False
ThisWorkbook.Sheets("Files List").Activate
oldfile = Sheets("Files List").Range("oldFile")
Debug.Print oldfile
strfnd = oldfile
Set db1 = connect_sql_server()
strfnd = Format_link(oldfile)
Debug.Print strfnd
For i = 3 To 50
Sheets("Files List").Range("FIleIndex").value = i
filelink = Sheets("Files List").Range("fileindex2")
curfile = ThisWorkbook.Sheets("Files List").Range("curfile")
Set wkbkNew = Workbooks.Open(filelink)
ThisWorkbook.Sheets("XML Format").Range("B3") = ActiveWorkbook.Name
Debug.Print (ThisWorkbook.Sheets("XML Format").Range("B3"))
Set wbsheet = wkbkNew.Sheets("Calculations")
filelink = ThisWorkbook.Sheets("Files List").Range("E3")
strRplc = filelink
Debug.Print (strRplc)
Set sht = ThisWorkbook.Sheets("XML Format")
Application.Volatile
ActiveWorkbook.Close SaveChanges:=False
Application.Volatile
sht.Cells.Replace What:=strfnd, Replacement:=strRplc, _
LookAt:=xlPart, SearchOrder:=xlByRows, MatchCase:=False, _
SearchFormat:=False, ReplaceFormat:=False
strfnd = strRplc
Debug.Print (strfnd)
ThisWorkbook.Sheets("XML Format").Activate
strxml = concatenate_xml()
Debug.Print (strxml)
'this imports data into sql server
WriteDB strxml, db1
strfnd = strRplc
continue:
Next i
db1.Close
End Sub
Say the loop is set as i=2 to 2. The expected result is that in the "XML Format" sheet, the data should be from the second files link in "Files List". The actual output is that the data is always from the first files link, the original "oldfile". The only thing that works as expected is the file name, "ActiveWorkbook.Name".
sorry if I cannot spend a lot of time answering your problem in detail. Trying to work though loads of cells in Excel in various workbooks generally gave me a lot of issues. Especially if you have macros running on worksheet events. The best advice I can give is that you get the full range from the old worksheet, process it with VBA, and then put it back into the new worksheet. It will also speed up your macro by orders of magnitude.
the process will then look a bit like this:
XML_table = thisWorkbook.range()
for i = 1 to nr_rows
for j = 1 to nr_columns
XML_table(i,j) = replace_str(XML_table(i,j))
next j
next i
thatWorkbook.range() = XML_table
good luck, hope the quick advice helped a bit
If I interpret this correctly (which is kind of tough since you use a lot of named ranges which I have no way of knowing where they link to) you do not account for iterations of your loop. You write away the iteration number on tab "Files list" and that's it. This means since you use absolute references for everything, it will repeat all steps exactly as you wrote them for the first iteration, never progressing. You need to feed i back into your loop as a row number to advance to the second row like so:
filelink = ThisWorkbook.Sheets("Files List").Range("E" & i)
Which from i = 3 to i = 50 actually loops through rows 3 to 50 in your "Files list" sheet, rather than taking "E3" every time.

Using function to open and update values in external workbooks, but returning source errors

I've been using a function from another StackOverflow question (I'm SO sorry I can't find the original answer!) to help go through a number of cells in Column L that contains a formula that spits our a hyperlinked filepath. It is meant to open each one (workbook), update the values, then save and close the workbook before opening the next one. See below.
Sub List_UpdateAndSave()
Dim lr As Long
Dim i As Integer
Dim WBSsource As Workbook
Dim FileNames As Variant
Dim msg As String
' Update the individual credit models
With ThisWorkbook.Sheets("List")
lr = .Cells(.Rows.Count, "L").End(xlUp).Row
FileNames = .Range("L2:L" & lr).Value
End With
For i = LBound(FileNames, 1) To UBound(FileNames, 1)
On Error Resume Next
If FileNames(i, 1) Like "*.xls*" Then
Set WBSsource = Workbooks.Open(FileNames(i, 1), _
ReadOnly:=False, _
Password:="", _
UpdateLinks:=3)
If Err = 0 Then
With WBSsource
'do stuff here
.Save
.Close True
End With
Else
msg = msg & FileNames(i, 1) & Chr(10)
On Error GoTo 0
End If
End If
Set WBSsource = Nothing
Next i
If Len(msg) > 0 Then
MsgBox "The Following Files Could Not Be Opened" & _
Chr(10) & msg, 48, "Error"
End If
End Sub
The problem now is I am using this to work on a Network drive, and as a result it cause pathing issues with the Connections/Edit Links part. Each of the files are stored on S:\... which as a result of using the Hyperlink formula, won't be able to find the source data. See below the example image of a file that as been opened through a hyperlink cell from my original workbook. When I go to update the Edit Links section of it, it shows these errors.
If I open that lettered drive in Windows Explorer and find the file, it works with no problems. Open, Update Values > Save > Close, it says unknown...
(but if I click Update values here they update correctly.)
If opened using a Hyperlink formula in a cell (Also directing to S:\..) it says it contains links that cannot be updated. I choose to edit links and they're all "Error: Source not found". The location on them also starts off with \\\corp\... and not S:\.
Anyway to fix this? Apologies for the long winded question.
I'm adding this as an answer as it contains code and is a bit long for a comment.
I'm not sure if it's what you're after though.
The code will take the mapped drive and return the network drive, or visa-versa for Excel files. DriveMap is the variable containing the final string - you may want to adapt into a function.
Sub UpdatePath()
Dim oFSO As Object
Dim oDrv As Object
Dim FileName As String
Dim DriveMap As String
Set oFSO = CreateObject("Scripting.FileSystemObject")
FileName = Range("A1")
If InStr(oFSO.GetExtensionName(FileName), "xls") > 0 Then
For Each oDrv In oFSO.drives
If oDrv.sharename <> "" Then
'Changes \\corp\.... to S:\
If InStr(FileName, oDrv.sharename) = 1 Then
DriveMap = Replace(FileName, oDrv.sharename, oDrv.Path)
End If
'Changes S:\ to \\corp\....
' If InStr(FileName, oDrv.Path) = 1 Then
' DriveMap = Replace(FileName, oDrv.Path, oDrv.sharename)
' End If
End If
Next oDrv
End If
End Sub

Error 1004 - item could not be found in OLAP cube after file copied/name changed

I have a workbook which connects to data models through PowerPivot, and the resulting pivot tables are filtered based on a given array collected through a difference process.
Sub AccrualPivot()
'Filter the data for the accrual entries that have been made.
Dim myArray() As Variant
Dim myR As Range
Sheets("Tables").Activate
Sheets("Tables").Range("JournalNum1").Select
Set myR = Sheets("Tables").Range("JournalNum1")
ReDim myArray(0 To myR.Cells.Count - 1)
Sheets("Data").Select
ActiveSheet.PivotTables("AccrualPivot").PivotFields( _
"[Query].[DataEntry].[DataEntry]").ClearAllFilters
ActiveSheet.PivotTables("AccrualPivot").PivotFields( _
"[Query].[JournalNum].[JournalNum]").ClearAllFilters
For i = 0 To myR.Cells.Count - 1
myArray(i) = "[Query].[JournalNum].&[" & myR.Cells(i + 1).Value & "]"
Next i
'ERROR THROWS HERE
ActiveSheet.PivotTables("AccrualPivot").PivotFields( _
"[Query].[JournalNum].[JournalNum]").VisibleItemsList = myArray
'This filters out the Data entries, which need to be included in a separate pivot.
ActiveSheet.PivotTables("AccrualPivot").PivotFields( _
"[Query].[DataEntry].[DataEntry]").CurrentPageName = _
"[Query].[DataEntry].&[0]"
End Sub
The error on the indicated line:
Run-time error '1004': The item could not be found in the OLAP cube.
When I put a watch on this line, both expressions are Variants and myArray has populated with the necessary information. The kicker (and I'm assuming the root) is that this works in my original file. But I need to be able to Save As the workbook to roll over for each month.
I need a file for 4.30, 5.31, etc. If I save the workbook as the following month, change the dates and run everything, it works. But if I close that file, reopen and try to run, I get the 1004 error.
Nowhere in the module do I reference the file name or file path. They're even saved in the same path, just as separate months, and all the sheets are named the same. I'm assuming it's embedded somewhere that I can't find.
I had the same problem, but fiddling with the variable UpdateStr made it work.
There is probably a cleaner way of doing this, but... it worked for me!
Sub FormatTables()
Dim i As Integer
Dim UpdateStr As String
Dim MySheet As Worksheet
Dim pt As PivotTable
Dim pf As PivotField
On Error Resume Next
For i = 1 To ActiveWorkbook.Worksheets.Count
Set MySheet = ActiveWorkbook.Worksheets(i)
If Left(MySheet.name, 7) = "looking for specific sheet names to modify the pivots" Then
For Each pt In MySheet.PivotTables
For Each pf In pt.PivotFields
' I am looping through all fields as I'm doing multiple pivot filtering, and setting different fields to other values... but in this example I only include one field.
If pf.Caption = "CoverageYear" Then
With pf
.ClearAllFilters
UpdateStr = Left(pf.Value, InStrRev(pf.Value, ".")) & "&[2019]"
.CurrentPageName = UpdateStr
End With
End If
Next
pt.RefreshTable
Next
End If
Next i
End Sub
I recently had this error and found Delora Bradish helpful: Rebuild the data model and run the code again.
The powerquery data model is fragile and there are unpredictable consequences when a table is renamed. Also, if you are scripting the model build, the order in which tables are added matters; though tables can be added simultaneously (multi-core processing), and it usually works just fine, sometimes the resulting model misses a table reference somewhere and you get this error. Change the load order to ensure good separation of the big files.
If you are using powerquery, you should have a plan for clean rebuilds of your data model from time to time.

Renaming named ranges

I have a workbook with many named ranges to rename. I have a spreadsheet with the old names and the new names.
This works:
Dim strOldName As String
Dim strNewName As String
strOldName = rngNamedRanges.Cells(1, 6).Value2
strNewName = strOldName & "_Renamed"
With ActiveWorkbook.Names(strOldName)
.Name = strNewName
End With
This does not:
Dim strOldName As String
Dim strNewName As String
strOldName = rngNamedRanges.Cells(1, 6).Value2
strNewName = CStr(rngNamedRanges.Cells(1, 8).Value2)
With ActiveWorkbook.Names(strOldName)
.Name = strNewName
End With
Clearly, I'm doing something wrong assigning strNewName.
I have also tried using .text, .value, and trimming the string, all with the same non-result.
The non-working code does not produce an error. It just fails to change the name.
rngNamedRanges.Cells(1,6) refers to a cell containing straight text.
rngNamedRanges.Cells(1,8) refers to a cell containing a CONCATENATE formula which creates the new range name based on several other pieces of info contained in other columns.
Renaming is always a pain. Try the following:
Sub Rename()
StrOld = "MyRange1"
StrNew = StrOld & "_Renamed"
Range(StrOld).Name = StrNew
With ThisWorkbook
.Names(StrOld).Delete
End With
End Sub
Looping is up to you. :) Let us know if this helps.
Thanks for the input, all! I still don't understand why the first example I gave worked and the second one did not. Nonetheless, the following code appears to be working. I apologize for poor formatting of the snippet.
Dim rngNamedRanges As Range
Dim strOldName As String
Dim strNewName As String
Dim strRefersTo As String
Set rngNamedRanges = ActiveWorkbook.Worksheets("Named Ranges").Range("A2:K909")
i = 1
Do Until [CONDITION] = ""
strOldName = CStr(Trim(rngNamedRanges.Cells(i, 6).Value2))
strNewName = CStr(Trim(rngNamedRanges.Cells(i, 8).Value2))
strRefersTo = ActiveWorkbook.Names(strOldName).RefersTo
'Update all the formulas to use the new name.
For Each ws In Worksheets
If ws.Name <> "Named Ranges" Then
ws.Cells.Replace What:=strOldName, Replacement:=strNewName, LookAt _
:=xlPart, SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False
End If
Next
'Delete old name and replace with the new one
ActiveWorkbook.Names(strOldName).Delete
ActiveWorkbook.Names.Add strNewName, strRefersTo
End If
strOldName = ""
strNewName = ""
i = i + 1
Loop
This is a really simple way to rename a range name. I got this from Paul Kelly at Excel Macro Mastery. Works great.
Sub rename_a_range_name()
Dim NewName As Variant
ThisWorkbook.Names("CurrentName").Name = "NewName"
End Sub
I modified the above code to rename some NAMES. With regards to the code immediately above, to loop through the worksheets and find/replace each NAME in formulas (etc)... I found that I needed to remove the Sheet Reference that is in the beginning of the string for each NAME's name.
'Update all the formulas to use the new name.
myStart = InStr(1, strOldName, "!", vbTextCompare) + 1
myLength = Len(strOldName) - myStart + 1
strOldNameSHORT = Mid(strOldName, myStart, myLength)
myStart = InStr(1, strNewName, "!", vbTextCompare) + 1
myLength = Len(strNewName) - myStart + 1
strNewNameSHORT = Mid(strNewName, myStart, myLength)
For Each ws In Worksheets
ws.Cells.Replace What:=strOldNameSHORT, Replacement:=strNewNameSHORT,
LookAt:=xlPart, SearchOrder:=xlByRows, MatchCase:=False,
SearchFormat:=False, ReplaceFormat:=False
Next
Long story short
Putting the update into e.g. the worksheet change event is likely to work.
Root Cause
Update: UDFs called from cells are not allowed to change things on the sheet. (That's what I did)
Old: I guess there are certain calculation processing phases, where updates to names are allowed or not allowed.
More explanation and findings
I wanted to rename a range and it was sometimes ignored and sometimes I got an error 1004 (application- or object-defined error - in German: Anwendungs- oder objektdefinierter Fehler).
Let's say one has a rename function like this:
Function rename( nold As String, nnew As String ) As Boolean
ThisWorkbook.Names(nold).Name = nnew
rename = True
End Function
I found out the following:
if the update is triggered by some UDF (user-defined cell function) on some cell update it will be ignored in some cases and in other cases the 1004 error is raised
e.g. putting some =rename("oldName", "newName") into A1 where oldName exists
why and when it is ignored or the error is raised is unknown to me
if the update is triggered by some event, e.g. the Private Sub Worksheet_Change(ByVal Target As Range) it will always be applied
Other side-effects
In finding out all this and debugging it, it may have caused that cells got locked automagically and thus also causing some 1004 error.

Resources