I currently have a macro which does data mining and saves the workbook in the end. I intend to disable to the save function of the workbook and force the user to use the macro everytime the workbook needs to be saved. This is what I have so far but it does not seem to work. When I do this, my macro and this sub described below are both running in a loop. every time my macro tries to save the workbook, this sub is not allowing it. I basically want to force the user to use the macro to save the workbook.
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Dim NoSave
NoSave = MsgBox("Changes have to be submitted before the workbook can be saved, Proceed and submit ?", vbYesNo, "Continue?")
If NoSave = vbNo Then
Cancel = True
Else
Main
End If
End Sub
Here is an Example. Paste this in ThisWorkbook. This will not let you use the Save or the SaveAs. You can however use the macro SaveThisFile to save the workbook. Please amend it to suit your needs.
Option Explicit
Dim SaveByCode As Boolean
Const msg As String = "Please use the macro to save the file"
Private Sub Workbook_BeforeClose(Cancel As Boolean)
If Me.Saved = False And SaveByCode = False Then
MsgBox msg, vbExclamation, "Unable to save"
Cancel = True
End If
End Sub
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Application.EnableEvents = False
If SaveByCode = True Then
SaveThisFile
Else
MsgBox msg, vbExclamation, "Unable to save"
Cancel = True
End If
Application.EnableEvents = True
End Sub
'~~> Your macro to save the file
Sub SaveThisFile()
SaveByCode = True
ThisWorkbook.Save
End Sub
NOTE: If your Save macro is in a module then remove this Dim SaveByCode As Boolean from ThisWorkbook and place Public SaveByCode As Boolean in a module.
Alternative, how about this (I misunderstood the question at first, but also wanted to give it a try since it's interesting):
Declare public boolean (exceptional) in the thisworkbook module:
Option Explicit
Public bSave As Boolean
In the event BeforeSave event:
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Dim sNoSave As String
If bSave = True Then
bSave = False
Exit Sub
End If
sNoSave = MsgBox("Changes have to be submitted before the workbook can be saved, Proceed and submit ?", vbYesNo, "Continue?")
If sNoSave = vbNo Then
bSave = False
Cancel = True
Exit Sub
Else
bSave = True
Call Main(bSave)
End If
End Sub
In Main:
Option Explicit
Sub Main(bSave)
If bSave = True Then
ThisWorkbook.SaveAs Filename:="U:\Book1.xlsm", FileFormat:=xlOpenXMLWorkbookMacroEnabled
MsgBox "Main method called"
End If
End Sub
Related
I have a workbook that I don't want anyone to perform a Save on, but they can perform a SaveAs. The problem I'm running into is that when they do a SaveAs (using a ActiveWorkbook.SaveAs statement rather than File > Save As), it is not using the standard SaveAsUI. So I can't do a If SaveAsUI = False Then method.
Here's what I had it place until I realized it doesn't do what I need.
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
If Not SaveAsUI Then
If Application.UserName <> "Robby" Then
MsgBox "You can't save this workbook!"
Cancel = True
End If
End If
End Sub
I am currently doing a VBA code that needs to hide some sheets when the Excel file is closed and almost everything is working fine expects when I do the following steps:
make some change/insert data in the sheets
click the save button
make another change (that I do not want to save)
click to close the file and click not to save it
The problem is that I hide the sheets but since I do not save the file (because i do not want to save the changes made at step 3) the sheets are not hidden when I reopen the file. I cannot do this with the Workbook_open method because it is not allowed (at my project).
To do this I am rewriting the beforeclose method, as follows:
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Dim Msg As String
Dim ireply As Integer
If Not Me.Saved Then
Msg = "Do you want to save the file?"
ireply = MsgBox(Msg, vbQuestion + vbYesNoCancel)
Select Case ireply
Case vbYes
Call hidesheets
Me.Save
Case vbNo
Me.Saved = True
Application.Quit
Case vbCancel
Cancel = True
Exit Sub
End Select
Else
Call hidesheets
Me.Save
End If
End Sub
Sub hidesheets()
ThisWorkbook.Sheets("Cars").Visible = xlVeryHidden
ThisWorkbook.Sheets("Brands").Visible = xlVeryHidden
ThisWorkbook.Sheets("Models").Visible = xlVeryHidden
ThisWorkbook.Sheets("Price").Visible = xlVeryHidden
End Sub
My questions is, it is possible just to save the hidden sheets configurations/settings without saving the information/data changed/inserted by the user?
PS: when I save the file and make any change the code works fine, i.e. hides the sheets.
Thank you all in advance
Regards
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
ThisWorkbook.Sheets("Cars").Visible = xlVeryHidden
ThisWorkbook.Sheets("Brands").Visible = xlVeryHidden
ThisWorkbook.Sheets("Models").Visible = xlVeryHidden
ThisWorkbook.Sheets("Price").Visible = xlVeryHidden
End Sub
You have to do the other way around
1) Set your workbook having those four sheets as very hidden per default
set them as such and then save your workbook to have it assume its default configuration
2) When you open it you make those sheets visible
Private Sub Workbook_Open()
ThisWorkbook.Sheets("Cars").Visible = True
ThisWorkbook.Sheets("Brands").Visible = True
ThisWorkbook.Sheets("Models").Visible = True
ThisWorkbook.Sheets("Price").Visible = True
End Sub
3) When you close it, you set those sheets back invisible
Private Sub Workbook_BeforeClose(Cancel As Boolean)
'Your code to be processed upon closing the sheet
'...
Call hidesheets '<--| hide your sheets
End Sub
I need to disable the save option in Excel but I still need the save as option to be working... So I know how to disable both of the option by this VBA:
Private Sub Workbook_BeforeSave(ByVal SaveUI As Boolean, Cancel As Boolean)
MsgBox "You can't save this workbook!"
Cancel = True
End Sub
But How is it possible to disable save but save us to be working still.
Thank you for helping me
Try:
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
If SaveAsUI = False Then
MsgBox "You can't save this workbook!"
Cancel = True
End If
End Sub
EDIT:
To delete the code from ThisWorkbook Class Module (delete every thing) we can use this code:
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
If SaveAsUI = False Then
MsgBox "You can't save this workbook!"
Cancel = True
Else
With ThisWorkbook.VBProject.VBComponents("ThisWorkbook").CodeModule
.DeleteLines 1, .CountOfLines
End With
End If
End Sub
NOTE:
This will delete everything in ThisWorkbook Class Module not only Workbook_BeforeSave
We must allow Trust access to the VBA project object model (File > Options > click Trust Center, click Trust Center Settings, and then click Macro Settings).
I've got a workbook which runs a macro to show the userform Open1 as it opens, using the (very basic) code:
Private Sub Workbook_Open()
Open1.Show
End Sub
This does its job fine - each time I open the workbook, the userform pops up and runs perfectly.
But, I want the userform to appear the first time the workbook is opened only. Is there a way to allow this to happen?
You could use a dummy module which gets deleted the first time you open the spreadsheet...
Something like:
If ModuleExists("DummyModule") Then
Open1.Show
DoCmd.DeleteObject acModule, "DummyModule"
End If
Function ModuleExists(strModuleName As String) As Boolean
Dim mdl As Object
For Each mdl In CurrentProject.AllModules
If mdl.Name = strModuleName Then
ModuleExists = True
Exit For
End If
Next
End Function
Update: as stated, DoCmd isn't used in excel vba. That will teach me to write code without testing it!
The following updated code will work, but in order to access the VB environment, excel needs to be trusted.
There is a setting in the Trust Center>Macro Settings that you can tick for this code to work under Developer Macro Settings
As such, this may not be the way to go as it opens up the possibility of security issues...
Sub RemoveModule()
If ModuleExists("DummyModule") Then
Open1.Show
Dim vbCom As Object: Set vbCom = Application.VBE.ActiveVBProject.VBComponents
vbCom.Remove VBComponent:=vbCom.Item("DummyModule")
End If
End Sub
Function ModuleExists(strModuleName As String) As Boolean
Dim mdl As Object
For Each mdl In Application.VBE.ActiveVBProject.VBComponents
If mdl.Name = strModuleName Then
ModuleExists = True
Exit For
End If
Next
End Function
Try this:
If Sheets("Hide").Cells(1,1) = "1" Then
Open1.Show
Sheets("Hide").Cells(1,1) = "0"
End if
You must create the sheet Hide, and give the cell A1 the value 1, in that case the form will be shown.
After you create the sheet, hide it with this
Sheets("Hide").Visible = xlVeryHidden
And show it with this
Sheets("Hide").Visible = True
Here's an alternative bit of code that will persist between saves and allow you to reset it. No need to create a hidden sheet.
Put this in a module (invoke the DisplayFormIfFirstTime from your Workbook_Open event handler....)
Option Explicit
Private Const cMoniker As String = "FormHasBeenDisplayed"
Private Sub DisplayFormIfFirstTime()
If HasBeenOpened = False Then DisplayForm
End Sub
Public Sub DisplayForm()
MsgBox "Ok, its not a form but a dialog box...", vbInformation
End Sub
Public Function HasBeenOpened() As Boolean
Dim oName As Name
On Error Resume Next
Set oName = Application.Names(cMoniker)
On Error GoTo 0
If Not oName Is Nothing Then
HasBeenOpened = True
Else
Call Application.Names.Add(cMoniker, True, False)
End If
End Function
'Call this to remove the flag...
Public Sub ResetOpenOnce()
On Error Resume Next
Application.Names(cMoniker).Delete
End Sub
Based on the idea supplied by PaulG, I have coded an upgrade that will check for the name and if not found run a function, add the name and save the workbook for a more seemless approach to this problem...
Placed in ThisWorkbook
Private Sub Workbook_Open()
Run "RunOnce"
End Sub
Placed in a module
Sub RunOnce()
Dim Flag As Boolean: Flag = False
For Each Item In Application.Names
If Item.Name = "FunctionHasRun" Then Flag = True
Next
If Flag = False Then
Call Application.Names.Add("FunctionHasRun", True, False)
Application.DisplayAlerts = False
ActiveWorkbook.Save
Application.DisplayAlerts = True
Call RunOnceFunction
End If
End Sub
Private Function RunOnceFunction()
Open1.Show
End Function
Sub ResetRunOnce()
For Each Item In Application.Names
If Item.Name = "FunctionHasRun" Then
Application.Names.Item("FunctionHasRun").Delete
Application.DisplayAlerts = False
ActiveWorkbook.Save
Application.DisplayAlerts = True
End If
Next
End Sub
I have an application that I've written in Excel 2003 and I have recently upgraded to Excel 2013. In the workbook_open event I set the workbook to read-only ActiveWorkbook.ChangeFileAccess xlReadOnly and have used the Toggle Read Only button to switch between read\write and read only. In Excel 2003 when switching file mode the workbook would toggle as expected. When I run it in 2013 as an .xlsm the Workbook_Open Event is called after switching the file status and it becomes read only again.
Private Sub Workbook_Open()
If ActiveWorkbook.ReadOnly = False Then
ActiveWorkbook.Saved = True
ActiveWorkbook.ChangeFileAccess xlReadOnly
End If
End Sub
It is possible achieve the results you are after without changing the FileAccess to read only. You can use the Workbook_BeforeSave and Workbook_Beforeclose events to control one's ability to save the workbook. I have provided a complete code example below that I believe would suit your needs. You could use a toggle button or any method you choose to run the subMakeItSaveable and subMakeItUnSaveable, or you could implement that functionality in a single routine.
The funUpdateCustomDocumentProperty function writes a Boolean value to the workbooks custom properties to toggle the ability to save the sheet. Please note that this custom property doesn't do anything except provide a place to store a value that isn't in either code or in the sheet. This provides a handy method of persisting data that our code needs when the code isn't running.
The code I used follows:
Private Sub Workbook_BeforeClose(Cancel As Boolean)
ThisWorkbook.Saved = True
End Sub
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
If ThisWorkbook.CustomDocumentProperties("SaveMyChanges").Value Then
SaveAsUI = True
Cancel = False
Else
SaveAsUI = False
Cancel = True
myTestValue = MsgBox("Read Only Workbook. Save Not Allowed.", vbInformation, "Operation Aborted")
End If
End Sub
Private Sub Workbook_Open()
myTestValue = funUpdateCustomDocumentProperty("SaveMyChanges", False, msoPropertyTypeBoolean)
End Sub
Public Function funUpdateCustomDocumentProperty(strPropertyName As String, _
varValue As Variant, docType As Office.MsoDocProperties) As Boolean
'Function returns true if custom property was added, false if it already exists
'Originally a sub built by Peter Albert
'http://stackoverflow.com/users/1867581/peter-albert
On Error Resume Next
funUpdateCustomDocumentProperty = False
ThisWorkbook.CustomDocumentProperties(strPropertyName).Value _
= varValue
If Err.Number > 0 Then
ThisWorkbook.CustomDocumentProperties.Add _
Name:=strPropertyName, _
LinkToContent:=False, _
Type:=docType, _
Value:=varValue
funUpdateCustomDocumentProperty = True
End If
End Function
Public Sub subMakeItSaveable()
myTestValue = funUpdateCustomDocumentProperty("SaveMyChanges", True, msoPropertyTypeBoolean)
End Sub
Public Sub subMakeItUnSaveable()
myTestValue = funUpdateCustomDocumentProperty("SaveMyChanges", False, msoPropertyTypeBoolean)
End Sub