Excel VBA: SaveAs, then killing old file has permission error - vba

I have Excel VBA code, which I have distributed, to produce some reports. The code has errors, and I have now fixed them. I want to update the end users.
Assume that the code is in a macro workbook "software.xlsm", as is any data that they have entered.
What I have done is to create "software v1.0.1.xlsm". It checks for the presence of "software.xlsm" and copies all the data and parameters from it to itself. It then renames "software.xlsm" as "software v1.0.0.xlsm.old", and saves itself as "software.xlsm". At this point, Excel is quite happy that this is the new name for the workbook.
All that remains is to delete the "updater". But this is where I run into permission errors - Excel won't let me kill it. It is not in use anywhere else, and it seems as if Excel isn't letting go of the original file name.
This is my code:
set newWb = ActiveWorkbook
thisName = newWb.FullName ' get full name of updater
newWb.SaveAs newWb.Path & "\software.xlsm" ' save updater as code file
Kill thisName ' delete updater <!! FAILS
I'm tearing my hair out here. I have checked here an online, and what I am doing should work - but it doesn't!
Thanks.
EDIT: I should mention that I have also tried SetAttr on the file, which also has no effect.
EDIT2: I am not sure I am being clear about what I want to do. I want to get rid of the updater once it has run, so as to not confuse the users. So I used "SaveAs" to save the updater with a new name, which left TWO files on the disk, and ONE file open in Excel. I am then trying to kill / delete the file that IS NO LONGER open in Excel (i.e. the updater before I saved it with a new name).

newWb.Close (you have to close it before you can delete it)
You can also try setting the variable to nothing.
Set newWb = Nothing

The error you are encountering is because you are trying to access the FullName of the workbook which has since changed after the SaveAs. For example. If I have a workbook with the FullName "SomeFilePath.foo" and I do a SaveAs with FullName & ".old" the FullName is now "SomeFilePath.foo.old".
This makes sense, but the part you are getting tripped up on is your thisname variable. For example:
Dim thisName as String
thisName = ActiveWorkbook.FullName
Debug.Print thisName ' E.G "SomeFilePath.Foo"
ActiveWorkbook.SaveAs ActiveWorkbook.FullName & ".old"
Debug.Print thisname ' Still "SomeFilePath.Foo"
The workbook by the old name simply doesn't exist anymore. It has been changed to the new name.
How do we fix this? You could find the new name and still Kill it, but you dont see Kill often for a reason, it is a bad practice.
The ideal would be to properly host, and reference, your workbook. For example:
thisName = thisWorkbook.FullName
thisWorkbook.SaveAs thisWorkbook.FullName & ".old"
thisWorkbook.Close(False)
We are almost there. We are saving the workbook and closing the current workbook, but this isnt actually what we want. What we need instead is:
thisWorkbook.SaveCopyAs thisWorkbook.FullName & ".old"
thisWorkbook.Close(False)
Instead of changing the FilePath of the updating workbook, just make a copy of it. Not only is it cleaner, but it allows us to not have to worry about the funky things that can happen when we mess with a file when it has code currently running.
Note though, you will want to chance the output file path to the path you actually intend. The ".old" is purely for example. Likewise, ThisWorkbook.Close(False) isn't ideal, but if you must close immediately after finishing then this will work best.
TLDR: The permission denied error is caused by referencing a workbook, by name, that no longer exists within the processes.

Related

How to open and activate another workbook in VBA?

I'm creating a macro where I will need to run it in 1 file (called "Masterfile"), it will open and execute the macro on another file ("SurveyReport") and then give me a message box saying "done!".
The code I have to execute on the SurveyReport file works fine when I open that file manually and execute it. The code I need to open SurveyReport from MasterFile is also working it seems, I ran the below with no issues:
Sub PivotTable()
'
' PivotTable Macro
Dim MasterFile As String
MasterFile = ActiveWorkbook.Name
Dim SurveyReport As String
SurveyReport = Application.GetOpenFilename("Excel files (*.xlsx), *xlsx", 1, "Please select the Survey Create Report file", , False)
Workbooks.Open (SurveyReport)
End Sub
But, when I try to activate the SurveyReport file so I can begin executing the macro in it, I get a "Subscript out of range" error. I've tried using the following code after the above block and before the code to execute in the SurveyReport file:
Windows(SurveyReport).Activate
This didn't work, not did:
ThisWorkbook.Activate
...which only had the effect of activating the MasterFile.
SurveyReport file is a .xlsx file. I tried saving it as a .xls file and amending the code, but no joy.
I also tried passing it the file name directly (i.e. Windows("filename.xlsx").Activate), same issue.
ActiveWorkbook is as it says on the tin - whichever workbook happens to be active when the code runs.
ThisWorkbook is always the workbook that the code is sitting in.
You can SET references to specific workbooks rather than just using their names each time. A name can change, or reference the wrong object.... imagine you have a friend called Darren. Each time you mention him you mention him by name. Someone that doesn't know Darren hasn't a clue which Darren out of all the ones available in the world you're talking about. Now imagine you have a little replica of Darren in your pocket... nah, that's a terrible anology - it wouldn't be a replica, it would be a reference to the real Darren... anyway, I digress.
This code sets a reference to the workbook, you can then use that reference any time you want to refer to the correct workbook:
Sub PivotTable()
Dim MasterFile As Workbook
Dim SurveyRptName As String
Dim SurveyReport As Workbook
Set MasterFile = ThisWorkbook '
SurveyRptName = Application.GetOpenFilename("Excel files (*.xlsx), *xlsx", 1, _
"Please select the Survey Create Report file", , False)
If SurveyRptName <> "False" Then
Set SurveyReport = Workbooks.Open(SurveyRptName)
End If
SurveyReport.Activate 'You don't need this line. It doesn't matter if
'the workbook is active, the code knows which one
'you're talking about in the next line.
MsgBox "This is " & SurveyReport.Name & _
" containing " & SurveyReport.Worksheets.Count & " sheets." & vbCr & _
"The value in cell A1 of the first sheet is " & _
SurveyReport.Worksheets(1).Range("A1")
End Sub
Edit: Of course, if you press Cancel when selecting a file then the lines following the IF...THEN code won't have a reference to work on and you'll get a Object Variable or With block variable not set - best not to run the bottom bit of code if you haven't successfully opened the Survey Report file.
The part of the answer that is missing - is that he tried to call a method of an object when his variable was STRING - the open command and subsequent commands will give you an OBJECT - which has properties and methods like .Activate. The STRING type has no such method or property (to be sure - it may have others).
the solution provided by Darren solves this by declaring his SurveyReport as type Workbook - an object of Excel.

How can I change the name of another Excel workbook I'm referencing in my code by entering the file name into a cell?

Here's what I'm trying to do.
My Excel workbook, InspectionFormTemplate3.4.xlsm, exists as a template to copy over data from various other workbooks that have a totally different format. The code works for copying the data over, but I have 1500 reports to convert and every time I have to manually go into my code and ctrl+f replace all instances it references the report to be converted. Instead, I enter data into a cell (S50) and tried replacing the referenced file name with a variable I named oldfilename. That is what gives me an error, and that's what I'm stuck on.
I've looked around for hours in order to find something that does what I'm trying to do, but I have no real experience with VBA at all. I think this is probably just a simple syntax error.
So, here's what I tried so far with my current code.
Private Sub ConvertButton_Click()
Dim oldfilename As String
oldfilename = Range("S50")
'Name of bldg and date
Workbooks("InspectionFormTemplate2018.3.4.xlsm").Worksheets("COVER PAGE").Range("C9").Value = Workbooks("ReporttoConvert.xls").Worksheets("Cover Page").Range("B5").Value
Obviously here, "ReporttoConvert" is a placeholder for an actual workbook name. It works when I manually insert file names, but I need it to look more like this instead:
Workbooks("oldfilename")
in order for it to change to whatever I input as the file name in cell S50. I'm sure this is probably pretty simple, but I have no clue what this would be called or how to do it.
Try this, your macro enabled workbook should be saved in the same folder as the other workbooks, else you will have to change 'ThisWorkbook.path...
Dim OpenWb As String
OpenWb = ThisWorkbook.Worksheets("COVER PAGE").Range("S50").Value
Workbooks.Open Filename:=ThisWorkbook.Path & "\" & OpenWb
ThisWorkbook.Worksheets("COVER PAGE").Range("C9").Value = Workbooks(OpenWb).Worksheets("Cover Page").Range("B5").Value

Connecting to Sharepoint File System using VBA

Can someone help explain why when trying to save or copy files over to a file structure that is part of a SharePoint site the code only seems to work if I use the SaveAs code once everytime I log on to my network
The code also works on other excel spreadsheets
If Dir("//teamspace.healthcare.siemens.com/content/90002613/Documents/" & Filename & "", vbDirectory) = "" Then
MkDir ("//teamspace.healthcare.siemens.com/content/90002613/Documents/" & Filename & "")
Else
The code I need to run once on logon is
With ActiveWorkbook
Application.ActiveWorkbook.SaveAs Filename:="https://teamspace.healthcare.siemens.com/content/90002613/Documents/Budget_Presentations/SavedFileName.xlsm"
Application.ActiveWorkbook.Close False
End With
I have tried multiple things, like using different directories, turning the slashes round, using variables. Nothing seems to work, even though exact same code has worked multiple times on a different spreadsheet
Thank You
If you are going to save it as a macro enabled workbook, then you need to explicitly tell the SaveAs command that. Like this:
Application.ActiveWorkbook.SaveAs Filename:="https://teamspace.healthcare.siemens.com/content/90002613/Documents/Budget_Presentations/SavedFileName.xlsm", XlFileFormat:=xlOpenXMLWorkbookMacroEnabled

Mystery Excel Worksheet Objects added by VBA

I have been creating a .xlsm Workbook that contains various bits of VBA. It simply copies data from two other workbooks into tables and then refreshes the PivotTables that are based on those tables to update the charts on the main workbook. All things I have done before in different workbooks without issue. Whilst working on the workbook I have naturally open, saved, and then closed the workbook several time over several different days.
Typically, now that I believe the workbook to be finished, it has developed a glitch whilst opening. Initially I was unable to open the file at all, as it would immediately crash. Only by saving the file to onedrive and downloading it back again, have I been able to keep the file open to see what is going on (for some reason this worked, I don't know why!).
I immediately suspected something in the VBA and so one press of Alt+F11 later I was confronted with this (image above).
All of the Blue Excel Objects in this picture were not created by me!
They contain no code and I do not seem to be able to open them as regular Excel Worksheets.
My Questions are,
does anyone have any idea what may be causing this?
Has anyone even seen this before?
Where do I start debugging this?
Attempting to run any of the VBA in the workbook causes it to instantly crash.
The VBA i suspect the most for the crashing is in these sections;
Public Function ThisWorkbookPath()
ThisWorkbookPath = ThisWorkbook.Path & Application.PathSeparator
End Function
which is passed to;
Public Function CheckPath(ByVal PathString As String) As Boolean
Application.Volatile (True)
If Strings.Right(PathString, 1) = "\" Then
CheckType = vbDirectory
Else
CheckType = vbNormal
End If
If Len(Dir(PathString, CheckType)) > 0 Then
CheckPath = True
Else
CheckPath = False
End If
End Function
These are both used in the workbook as user defined functions to check if the folder that contains the other 2 workbooks exists on the computer before trying to open them.
ThisWorkbook is now ThisWorkbook1 which might explain why, as the forumla in the workbook calculates, it can't find the correct path and just crashes.
But this doesn't explain where these extra objects came from in the first place.
Any help would be gratefully appreciated
I just had the same issue with Office365, made a code review and found out that I was using the same name for a public constant and a parameter to a function. After renaming the parameter and rerunning the macro, it did not happen again.

Excel VBA - Code to move or copy worksheets without warnings

I am trying to create a macro that would act the same as right clicking a workbook tab, selecting move or copy, checking the copy option, selecting another open workbook and clicking ok but without the warnings. I found the code to disable warning and I was able to record a macro that does what I want but I don't know how to make it request which open workbook to copy to.
In short how do I make the following code work where WorksheetIWantToCopy is the one the user currently has selected and OpenWorkbookIWantToCopyToo.xlsx is a workbook to be selected by the user out of a list of open workbooks.
Application.DisplayAlerts = False
Sheets("**WorksheetIWantToCopy**").Select
Sheets("**WorksheetIWantToCopy**").Copy Before:=Workbooks( _
"**OpenWorkbookIWantToCopyToo.xlsx**").Sheets(1)
I appreciate any information anyone can provide. My team greatly appreciates your support (we currently have to hit ok on 25 warnings due to conflicts we don't really care about). Thx!
If the worksheet you want to copy will always be the active sheet then you can use ActiveSheet.
As for letting the user select a workbook, it can be as simple as using the InputBox.
Public Function getWorkbookName() As String
Dim i As Integer, sListOfWbks As String, sRsp As String
' build list of workbooks
For i = 1 To Workbooks.Count
sListOfWbks = sWbkList & vbCrLf & i & " - " & Workbooks(i).Name
Next i
sRsp = InputBox("Select workbook." & vbCrLf & sListOfWbks)
If IsNumeric(sRsp) Then
getWorkbookName = Workbooks(CInt(sRsp)).Name
Else
' user pressed cancel or entered invalid text
getWorkbookName = ""
End If
End Function
This basic example will of course list all workbooks, including hidden add-ins and the workbook you are moving away from.
This needs to be said before anything else: always, always, ALWAYS make use of .Copy instead of .Move when automatically shuffling excel workbooks with VBA. Move has inherent risks because it is a modification of the other file, and if your code misbehaves then you could lose all of the data you're working with.
First of all, know which workbook is which, with no ambiguity:
Dim wkbkDestination, wkbkTemporary As Workbook
Set wkbkDestination = Workbooks("OpenWorkbookIWantToCopyTo.xlsx")
Set wkbkTemporary = Workbooks.Open("WorkbookIWantToCopy.xlsx")
Next, Copy your desired tab to your destination workbook, rename the new tab to prevent errors, and close the second workbook, without saving.
wkbkTemporary.Worksheets("WorksheetIWantToCopy").Copy Before:=wkbkDestination.Worksheets(1)
wkbkDestination.Worksheets(1).Name = "WorkbookIWantToCopy"
wkbkTemporary.Close SaveChanges = False
Naturally, depending on the exact controls you intend to use, there are lots of ways this code could be implemented. From your description it is somewhat unclear what exact problem you're trying to solve and whether this is a one-off event you're trying to accomplish for a given list of files, or whether this function is to be used on an ongoing basis.