My macro should make a backup (in a specified path) of a file that is currently being saved, a procedure that is often discussed since it is a feature that Word lacks.
Private Sub Document_Close()
Dim blank As Range
For Each blank In ActiveDocument.StoryRanges
If Len(blank.Text) = 1 Then Exit Sub
Next
End Sub
Sub FileSave()
Dim BackupPath As String, objF As Object, retVal As Long, Rslt
BackupPath = "C:\Users\" & Environ("UserName") & "\Documents\BackupWord\"
With ActiveDocument
If .Path = "" Then: If Application.Dialogs(wdDialogFileSaveAs).Show <> -1 Then Exit Sub
If Len(Trim(.Range.Text)) = 1 Then Exit Sub
.Save
If Dir(BackupPath, vbDirectory) = "" Then
MkDir BackupPath
MsgBox "Backup folder has been created.", vbInformation
End If
If .Path & "\" = BackupPath Then
MsgBox "WARNING! Backup folder is the same as the source folder", vbExclamation
Exit Sub
End If
Set objF = CreateObject("Scripting.FileSystemObject")
retVal = -1
On Error Resume Next
retVal = objF.CopyFile(.FullName, BackupPath & .Name, True)
On Error GoTo 0
Set objF = Nothing
If retVal <> 0 Then MsgBox "Backup has not been copied to folder " BackupPath, vbExclamation
End With
End Sub
I will describe what the macro currently does.
FileSave procedure is intercepted.
The macro checks if an active document is saved. If it is, no extra action is required and the macro closes.
If an active document in not saved, the usual "Save As" dialogue appears. If the user chooses to not save the file then the macro closes.
If document is not saved, the macros saves it.
The macro looks for a backup folder. If it is not found, the macro creates it and shows a message box.
Then the macro checks if the source folder is the same as the backup folder. If they are the same, the macro shows a message and closes.
The active (current) document is copied to the backup folder. If it fails, a message box is displayed.
My macros fail to make a backup on two occasions.
When I open Word (no document opened, just blank page), modify it
and choose to close Word, a SaveAs dialog is shown. Then I choose to
save and the document is saved correctly but a backup copy is not
created.
When a document exists on, say, harddrive, pendrive etc.
and I will modify it and choose to close Word a SaveAs dialog is shown.
Then I choose to save and the document is saved correctly but a
backup copy is not created.
You would need a class, i believe at addin level to track all sheets, something like...
Option Explicit
Private WithEvents wd As Word.Application
Public Sub initialise(w As Word.Application)
Set wd = w
End Sub
Private Sub wd_DocumentBeforeSave(ByVal Doc As Document, SaveAsUI As Boolean, Cancel As Boolean)
' Your code here
End Sub
In your addin (.dotm) file you'd have the following
Option Explicit
Public c As clsCustomWord
Sub AutoExec()
Set c = New clsCustomWord
c.initialise Application
End Sub
Hope this helps
Related
I've ended up cleaning up someone's mess on a Word document that's used throughout my company. It is a macro-heavy document that needs to be saved as a .docm exclusively. I'm worried about it getting "save as"-d as something other than a .docm, but I can't seem to find a way to limit the save as file picker or swap out the extension on save as while still using VBA.
How can I achieve this?
Edit: Some of the things I've tried, to no avail:
This has the right idea, but doesn't actually limit the filetypes down on save https://answers.microsoft.com/en-us/msoffice/forum/msoffice_word-mso_other/how-to-set-path-for-wddialogfilesaveas-dialog/535b7f9c-9972-425c-8483-35387a97d61d
Towards the bottom, Microsoft says that SaveAs isn't compatible with filter.clear and filter.add https://msdn.microsoft.com/en-us/library/office/aa219834(v=office.11).aspx
In order to hijack the native "SaveAs" dialog in Word, you need to lever the Application-level event for DocumentBeforeSave, and then call the FileDialog manually, in order to validate the extension.
1. Create a standard code module and name it modEventHandler. Put the following code in it.
Option Explicit
Public TrapFlag As Boolean
Public cWordObject As New cEventClass
'You may not need these in a DOCM, but I needed to implement this in an ADD-IN
Sub TrapEvents()
If TrapFlag Then
Exit Sub
End If
Set cWordObject.DOCEvent = Application
TrapFlag = True
End Sub
Sub ReleaseTrap()
If TrapFlag Then
Set cWordObject.DOCEvent = Nothing
Set cWordObject = Nothing
TrapFlag = False
End If
End Sub
2. Create a Class Module called cEventClass and put this code in the module:
Option Explicit
Public WithEvents DOCEvent As Application
Private Sub DOCEvent_DocumentBeforeSave(ByVal Doc As Document, SaveAsUI As Boolean, Cancel As Boolean)
' Do not prevent SAVEAS for *other* documents
If ObjPtr(Doc) <> ObjPtr(ThisDocument) Then
Exit Sub
End If
If SaveAsUI Then
' The user has invoked SAVE AS command , so we will hijack this and use our own FileDialog
Call CustomSaveAs(Doc)
' Prevent duplicate appearance of the SAVEAS FileDialog
Cancel = True
End If
End Sub
Private Sub CustomSaveAs(ByRef Doc As Document)
Dim fd As FileDialog
Dim filename$
Set fd = Application.FileDialog(msoFileDialogSaveAs)
fd.Show
If fd.SelectedItems.Count = 0 Then Exit Sub
filename = fd.SelectedItems(1)
If Not Right(filename, 4) = "docm" Then
' ### DO NOT EXECUTE this dialog unless it matches our .DOCM file extension
MsgBox "This document should only be saved as a DOCM / Macro-Enabled Document", vbCritical, "NOT SAVED!"
Else
fd.Execute
End If
End Sub
3. In ThisDocument module, do the following code:
Private Sub Document_Close()
Call modEventHandler.ReleaseTrap
End Sub
Private Sub Document_Open()
Call modEventHandler.TrapEvents
End Sub
How Does This Work?
ThisDocument raises the Document_Open event which calls on the TrapEvents procedure.
TrapEvents procedure creates a WithEvents instance of Word.Application class, exposing additional events to automation. One of these is DocumentBeforeSave.
We use the DocumentBeforeSave event to trap the SaveAs operation. If the User has requested a SaveAs, then we force the dialog with logic as created in CustomSaveAs procedure. This uses simple logic to test the file extension provided, and prevents the document from being saved if it is not a DOCM extension. If the FileDialog does receive a valid DOCM extension, then we Execute the dialog which saves the file as the new name.
below is my code for the file to be saved to specific folder. my question is how can I make the folder of the location is open automatically after save complete. I google about "aftersave event" but nothing come out .
Private Sub savebr_Click()
Dim saveas As String
saveas = "C:\user\file"
Application.Dialogs(xlDialogSaveAs).Show saveas
End Sub
So you want to open the folder where the current workbook was saved automatically after saving. Paste this code in the ThisWorkbook code in the VB Editor
Private Sub Workbook_AfterSave(ByVal Success As Boolean)
Call Shell("explorer.exe" & " " & ThisWorkbook.Path, vbNormalFocus)
End Sub
Thisworkbook.path open every time same workbook path(i.e. your macro file path)
If your are adding many excel workbooks and save it on different path and want
to open this path so you should use below code.
Not necessary to use event for this, you can simply write code after saving workbook.
Private Sub Workbook_AfterSave(ByVal Success As Boolean)
Call Shell("explorer.exe" & " " & Activeworkbook.Path, vbNormalFocus)
End sub
When opening up a template a macro that is Auto_Open runs this code:
Sub Auto_Open()
UserForm.Show
End Sub
This then brings up a userform that says please save as and a Ok command button.
When Ok is clicked it has the this code.
Private Sub SaveAs_Click()
Dim bFileSaveAs As Boolean
bFileSaveAs = Application.Dialogs(xlDialogSaveAs).Show
If Not bFileSaveAs Then MsgBox "User cancelled", vbCritical
Unload Me
End Sub
Problem is after the Auto_Open is ran for the first SaveAs i want it to never run again. Because I want to be able to open it later with out the Userform popping up. So how do I disable the Auto_Open once its run and then save it disabled
I cant disable all macros because there are others in the workbook that still need to work.
Thanks
You have to use the Workbook.SaveAs method MSDN Found Here after you get the SaveAsFilename...
As for deleting a sub after it runs (I'd do this before saving) See here... You'll need your Auto Open Sub in a different module so you can delete the module before saving.
Private Sub SaveAs_Click()
Dim x As Object
Set x = Application.VBE.ActiveVBProject.VBComponents
x.Remove VBComponent:=x.Item("TestModule") 'Where TestModule is the module that holds the Auto Open script
Set NewBook = Workbooks.Add
Do
fName = Application.GetSaveAsFilename
Loop Until fName <> False
NewBook.SaveAs Filename:=fName
fName = False
Unload Me
End Sub
Exit auto_open if file name without specific wording.
For example: If file name is not starting from "N", auto_open will be exit.
Sub auto_open()
VBA_CODE = ActiveWorkbook.Name
If Left(VBA_CODE, 1) <> "N" Then Exit Sub
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Dim saveIt As Boolean
If ThisWorkbook.Name = "Test.xlsm" Then
Sheets("Sheet1").Select
If Not IsEmpty(A1.Value) Then
MsgBox "This workbook is 'read only' Please rename this workbook."
strName = "Please enter a new file name."
ThisPAth = Application.ActiveWorkbook.Path
ThisFile = Range("B1").Value
ActiveWorkbook.SaveAs Filename:=ThisPath & ThisFile & ".xlsm", FileFormat:=52, CreateBackup:=False
Else
MsgBox "Cancelled."
End If
End If
End Sub
I have a password protected workbook (Test.xlsm" that is strictly for data entry. When the user opens the workbook as read only, enters the data, and then exits the workbook/template, I want the SaveAs dialog box that automatically pops up to have the contents of A1 of Sheet1 to be the "Suggested" file name that is autofilled in the SaveAs box.
I thought if I snagged the BeforeSave function that I could declare this path/filename but alas, it does not work. The autofill box displays "Copy of Test.xlsm". I do not even think it sees the above code.
How can I accomplish autofilling this box with the desired name. Thanks.
------------Update------------------
Rewrote code to below but it still is not snagging the default dialog box on save. Maybe I am misunderstanding the Workbook_BeforeSave function. I thought it was automatically called whenever the file is getting saved. I never want the user to save the file with the name Test.xltm (I changed file to a template to see if that made a difference) but to suggest the user rename file to the value in B1 for standardization reasons. The code is not getting called automatically. I was able to get similar code to work if I call it by executing a macro from the quick access toolbar for example, but cannot seem to get it to execute automatically whenever the user selects "Close", "Save" or "Save As" from the "File" pull down menu.
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Dim saveDialog As FileDialog
Debug.Print "Hello"
Set saveDialog = Application.FileDialog(msoFileDialogSaveAs)
If ThisWorkbook.Name = "Test.xltm" Then
Application.EnableEvents = False
Debug.Print "Save as"
Set saveDialog = Application.FileDialog(msoFileDialogSaveAs)
With saveDialog
.InitialFileName = "foo.xlsm"
.Show
End With
Application.EnableEvents = True
Else
Debug.Print "Cancel"
End If
End Sub
The template is password protected and opened as read only by user so SaveAs dialog box should always open upon exit/save/save as. Correct? And shouldn't the Workbook_BeforeSave always get called under this circumstance?
Example:
Sub saveDialogTest()
Dim saveDialog As FileDialog
Set saveDialog = Application.FileDialog(msoFileDialogSaveAs)
With saveDialog
.InitialFileName = "Foo.xlsx"
.Show
End With
End Sub
If you use the FileDialog like this, it will allow you to change the suggested file name.
I have textbox and command button in the form1.
I will input path in the textbox
After the clicking the command button, workbook from the path location should open and need to the require macros code like copying , etc
when i tried using the . I getting error saying that file1.xlsx not found . plz help
Private Sub CommandButton1_Click()
Set wb1 = Workbooks.Open("file1")
End Sub
Private Sub TextBox1_Change()
Dim file1 As String
file1 = TextBox1.Value
End Sub
Private Sub UserForm_Click()
End Sub
The suggestions in the comments above will get you where you need to go, but if I may suggest... rather than using a textbox for the user to enter the name in, use the GetOpenFilename dialog. In this way you can ensure that the path is valid and the file actually exists. It also gives the user a nice GUI which is more like what they're used to for a File -> Open dialog. Something like this:
Private Sub CommandButton1_Click()
Dim vnt As Variant
On Error GoTo ErrorHandler
vnt = Application.GetOpenFilename("Excel Files (*.xlsx; *.xls; *.xlsm),*.xlsx;*.xls;*.xlsm", 1, "Please select the file to open")
If vnt = False Then Exit Sub
Application.Workbooks.Open (vnt)
ExitPoint:
Exit Sub
ErrorHandler:
MsgBox "Error " & Err.Number & vbCrLf & Err.Description
Resume ExitPoint
End Sub