I have created a template for registration of changes. These are the requests and further administration in the process. I have a code in this template to save the file as an excel macro enabled workbook, always. The problem with this code is that i can't define a specific folder to save the documents. In all cases the save as dialog box will pop up and the user must be able to define their own file name. I want to define the path for all the users. Does anyone know how to add a file location (path) in this macro in order to make it work?
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Dim FileNameVal As String
If SaveAsUI Then
FileNameVal = Application.GetSaveAsFilename(, "Excel Macro-Enabled Workbook (*.xlsm), *.xlsm")
Cancel = True
If FileNameVal = "False" Then 'User pressed cancel
Exit Sub
End If
Application.EnableEvents = False
If Right(ThisWorkbook.Name, 5) <> ".xlsm" Then
ThisWorkbook.SaveAs Filename:=FileNameVal, FileFormat:=xlOpenXMLWorkbookMacroEnabled
Else
ThisWorkbook.SaveAs Filename:=FileNameVal, FileFormat:=xlOpenXMLWorkbookMacroEnabled
End If
Application.EnableEvents = True
End If
End Sub
Thanks in advance.
Kind regards,
Remco H.
If you wish to generate a unique filename, you could use something like the following function:
Function NextFileName(basename As String) As String
Dim followup As Integer
Dim pathname As String
pathname = "C:\Temp\Temp\" ' Include the trailing path separator so that we don't have to do it later
followup = 1
Do
NextFileName = pathname & basename & "-" & followup & ".xlsm"
If Dir(NextFileName) = "" Then Exit Function
followup = followup + 1
Loop
End Function
You could then call it from your main code as
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Dim FileNameVal As String
If SaveAsUI Then ' <-- Exclude the IF statement if you want EVERY save to have a new follow up number
' rather than just "Save As" saves
Application.EnableEvents = False
'Generate the filename
FileNameVal = NextFileName(Format(Now, "yymmdd"))
ThisWorkbook.SaveAs Filename:=FileNameVal, FileFormat:=xlOpenXMLWorkbookMacroEnabled
'Maybe advise the user that the save has happened, and where it went to
MsgBox "Spreadsheet saved as " & FileNameVal
Cancel = True
Application.EnableEvents = True
End If
End Sub
Related
I have a previous topic about setting password for another workbook. The other workbook is named "Sample.xlsm"
Protect closed workbook with password
Now I need to make the user input the password from the Sample.xlsm itself and at the same time to prevent the user from changing the password
I used this
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Application.DisplayAlerts = False
If SaveAsUI Then MsgBox "SaveAs Feature Disabled", vbExclamation: Cancel = True
Application.DisplayAlerts = True
End Sub
But this seems not enough from preventing the user to save the workbook with another name.
To force only saving to a specific location:
This is the code that should stop most attempts at saving:
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Application.EnableEvents = False
Cancel = True
Call MySaveCode
BackToExcelSave:
Application.EnableEvents = True
End Sub
Then you have to add code for your save, and avoid triggering excels' default save routine:
Sub MySaveCode()
On Error GoTo ReEnable ' Use On Error in case they cannot save to specified location/filename
Application.EnableEvents = False ' turn off excel default action (Workbook_BeforeSave)
Dim Path As String
Dim FileName As String
Path = "C:\Users\SeanC\Documents\Excel\"
FileName = "MyFixedFilename.xlsm"
Application.DisplayAlerts = False 'Optional. Suppresses default excel messages
ThisWorkbook.SaveAs Filename:= _
Path & FileName, _
FileFormat:=xlOpenXMLWorkbookMacroEnabled, _
CreateBackup:=False, _
Password:="P#$$w0rd"
MsgBox "Saved as: " & ThisWorkbook.FullName 'Also Optional
ReEnable:
Application.DisplayAlerts = True 'Optional
Application.EnableEvents = True
End Sub
I have code, that only runs when a user chose "Save As". To do that and getting the new name of the file I'm using the Application.GetSaveAsFilename function.
The problem I came across was a type mismatch while checking if the user clicked on Cancel when he did not do that.
Line that threw the error when Cancel was not clicked: If saveName = False Then Exit Sub
My working code:
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
If Not SaveAsUI Then Exit Sub
Cancel = True
'other variables
Dim saveName As String
saveName = Application.GetSaveAsFilename(filefilter:="Microsoft Excel Files (*.xlsm), *.xlsm", Title:="Save as Microsoft Excel Macro-Enabled Worksheet")
On Error GoTo RunTime13
If saveName <> False Then
On Error GoTo 0
'other code
ThisWorkbook.SaveAs Filename:=saveName, FileFormat:=52
End If
Exit Sub
RunTime13:
If Err.Number = 13 Then Resume Next
End Sub
What am I doing wrong, that I have to work around the Cancel button like this?
Edit:
I chose Dim saveName As Variant to be able to use If saveName = False Then Exit Sub
As Vityata mentioned I am in Germany and thus could have run into problems with the language, fortunately for me Vityata reminded me of the problem because I am in fact using Excel in English, but not all of my colleagues are, so my accepted answer might not have worked when they were using the workbook.
As you've declared SaveName as a string, you need to check for "False", not False.
If saveName <> "False" Then
OP, I have some news for you - you are in Germany and thus I am about 99% sure you are using German Excel.
There the VBA is a bit translated, thus the saveName is translated to Falsch and not False as in the rest of the world. E.g. CStr(False) returns Falsch.
In your code write either of these three:
If saveName <> "Falsch"
If saveName <> False
If Len(saveName) <> 6
Here's another approach:
Dim vSaveName As Variant
vSaveName = Application.GetSaveAsFilename(filefilter:="Excel Files (*.xlsm), *.xlsm", _
Title:="Save as Macro-Enabled Worksheet")
If TypeName(vSaveName) = "Boolean" Then Exit Sub
'' otherwise continue with save...
The only time vSavename is a Boolean is when the user cancels, so this approach doesn't need to know how to say False in the user's language.
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Dim fname As Variant, DateTime As String, myInitialFilename As String
On Error GoTo ErrorHandler
SaveAsUI = True
If SaveAsUI Then
Cancel = True 'Cancel the original SaveAs
DateTime = "_" & Format(Now(), "yyyy_mm_dd_hhmmss") '= " [yyyy_mm_dd]"
'DateTime = " [" & Format(Now(), "yyyy_mm_dd hhmm_ss") & "]" '= " [yyyy_mm_dd hhmm_ss]" (use instead if you want time in the name)
myInitialFilename = "Quote" 'EDIT THIS
'Get filename (with path) for saving
fname = Application.GetSaveAsFilename(InitialFileName:=myInitialFilename & DateTime, fileFilter:="Excel Marcro-Enabled Workbook (*.xlsm),*.xlsm")
If fname = False Then Exit Sub 'Exit if user hit Cancel
Application.EnableEvents = False 'Prevent this event from firing
ThisWorkbook.SaveAs Filename:=fname, FileFormat:=52
'52 = xlOpenXMLWorkbookMacroEnabled = xlsm (with macro's in 2007-2010)
Application.EnableEvents = True 'Re-enable events
End If
Exit Sub
ErrorHandler:
Application.EnableEvents = True
MsgBox "An error occured during save." & Err.Number, vbCritical, "Error"
End Sub`
I have written a bit of VBA code to force a save or save-as to be the file type .xlsm, which works fine. However, I can't seem to save the template file with the VBA code in it because of the code itself forcing the .xlsm save.
I have a template saved without the code, but as soon as I add the code, obviously I can no longer save as xltm, since the code pushes to save as xslm. Looking for a best practice solution to save my template!
Thanks,
Kathy B.
Any changes within the file will either make it always save as xltm, or always as xlsm. So you want a flag stored in a different file, which defaults to false. This way, when you want to edit your template, you can turn it on and save your changes, but in normal usage, it will save as .xlsm.
If you do not overwrite the SaveAsUI-Flag with true
you can save the file as Template when you work on it.
If you create a new File form the Template the
SaveAsUI-Flag will be true and then your code forces
to keep the macros.
I have created a folder containing many .xls and .xlsm sheets, this folder will be distributed to many people in the company, in order not to alter the integrity of the sheets in the folder I want to disable saving any files in this folder, all filles saved will have to be "saved as" in a location different than the folder called project.Here is what have found so far.
Cheers
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
' Following line will prevent all saving
Cancel = True
' Following line displays the Save As Dialog box
If SaveAsUI Then SaveAsUI = True
' How do I forbid the folders path ???
End Sub
I've come up with one way of doing it. Maybe someone can give you a better answer.
It will save a file to your default location which is set to be C:\MyFiles and show a MessageBox after with the path to the file.
Only use this code if you do not want to ask the user where to save the file and save it in a static location then notify him/her of the location the file was saved to.
The below code goes in here (ThisWorkbook Object Module)
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
If SaveAsUI Then
Cancel = True
Else
Dim path As String
path = "C:\MyFiles\"
If Len(dir(path, vbDirectory)) = 0 Then
MkDir path
End If
Me.SaveAs Filename:=path & Me.Name, _
FileFormat:=xlOpenXMLWorkbookMacroEnabled, CreateBackup:=False
MsgBox "This file has been saved in " & path & Me.Name
Cancel = True
Exit Sub
End If
End Sub
update!
If all your users are on Windows 7 than you can change the path to
path = "C:\Users\" & Environ$("username") & "\Desktop\"
This will go to each user's desktop regardless of their username. The Environ$("username") function returns currently logged in username.
This version saves to the User Desktop regardless of the Windows O/S version
It also disables Events so that the code doesn't call itself recursively.
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Dim ws As Object
Set ws = CreateObject("WScript.Shell")
If ThisWorkbook.Saved Then
Application.EnableEvents = False
ThisWorkbook.SaveAs ws.specialfolders("Desktop") & "\" & ThisWorkbook.Name
MsgBox ThisWorkbook.Name & " saved to " & ws.specialfolders("Desktop")
Application.EnableEvents = True
Else
MsgBox "workbook has not been saved before", vbCritical
Cancel = True
End If
End Sub
So I am working with a XLTM file, and I want the user to make sure they save as XLSM. When they click "Save," this works fine, but I find when they click "Save As," the file is saved as "*.xlsm.xlsm". I am a little lost with how to make sure that the user saves as XLSM, while keeping the file name as "filename.xlsm" and not "filename.xlsm.xlsm".
'Action makes sure the user saves as XLSM file type.
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Dim FileNameVal As String
If SaveAsUI Then
FileNameVal = Application.GetSaveAsFilename(, "Excel Macro-Enabled Workbook (*.xlsm), *.xlsm")
Cancel = True
If FileNameVal = "False" Then 'User pressed cancel
Exit Sub
End If
Application.EnableEvents = False
ThisWorkbook.SaveAs Filename:=FileNameVal & ".xlsm", FileFormat:=ThisWorkbook.FileFormat
Application.EnableEvents = True
End If
End Sub
I thought the problem may have been writing ".xlsm" in:
ThisWorkbook.SaveAs Filename:=FileNameVal & ".xlsm", FileFormat:=ThisWorkbook.FileFormat
However, without ".xlsm" written there, I find the file instead saves as a bad file suffix. (E.g., if my XLTM file is called Template(File001).xltm, and the user opens a new template file, it will save as Template(File001)1 (believing that "1)1" is the file type).
It may be the structure of my code, so I need direction in how to revise it.
The problem appeared to have existed because the template would name the file "Template(1)1" prior to it actually being saved initially. This changes the way that Excel saves the file, so the easiest way to contrast between this initial save and further saves (that already contain a file extension) was to use an if-then statement to judge whether an extension exists already.
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Dim FileNameVal As String
If SaveAsUI Then
FileNameVal = Application.GetSaveAsFilename(, "Excel Macro-Enabled Workbook (*.xlsm), *.xlsm")
Cancel = True
If FileNameVal = CStr(False) Then 'User pressed cancel
Exit Sub
End If
Application.EnableEvents = False
If Right(ThisWorkbook.Name, 5) <> ".xlsm" Then
ThisWorkbook.SaveAs Filename:=FileNameVal & ".xlsm", FileFormat:=xlOpenXMLWorkbookMacroEnabled
Else
ThisWorkbook.SaveAs Filename:=FileNameVal, FileFormat:=xlOpenXMLWorkbookMacroEnabled
End If
Application.EnableEvents = True
End If
End Sub