I have inherited an excel project, which I’ve been tasked to automate and develop further.
Use case being
An order comes in
User opens the base (root) excel file
Types in the relevant info (customer, order, data, tasks, etc)
And saves the new task file in a folder with tasks in progress
Leaving the base (root) excel basic and ready for next order.
The new task file needs to have a certain file name structure, which has been sorted.
My problem comes in on ActiveWorkbook.SaveAs filename.
As I step through F5 the lines, it goes through all the steps, creates the filename, shows the Save As UI, correctly shows the right folder and suggested filename, and actually saves the file. As I come out of ErrHandler and the last Application.EnableEvents = yes - it crashes. It seems to either be closing the base file, opening the new, or transfer active workbook to the new save file.
Which is fine, if it could stop crashing.
If criticalInput then
Msgbox “U been bad, U Shall not PASS!”, vbCritical ‘Not actual text or box showing, just for demo.
Else
Dim fileSaveName As Variant
'### It Crashes after saving (possible at opening)
fileSaveName = Application.GetSaveAsFilename( _
InitialFileName:=tasksfolder & "\" & suggestFilename, _
fileFilter:="Excel-projectmappe med aktive makroer (*.xlsm), *.xlsm")
If fileSaveName <> False Then
'### here is where you would save your file
DoEvents ‘ Debugging research tells this should be here. Not that is changes anything.
ActiveWorkbook.SaveAs fileSaveName ‘ During dev this has been disabled.
End If ' SaveAs
End If ' criticalInput
ErrHandler:
'## Reset back to default
Application.DefaultFilePath = strDefault
Application.EnableEvents = True
End Sub
Debugging
I can save the file just nicely, if I disable SaveAs and work only on the base (root) excel file.
I can open the new task file and save it nicely. (Just being a bugger about overwriting, Y/N)
Debugging research said I needed a DoEvents prior to SaveAs
Debugging research also said only to have the most relevant references present (in my case unselect OLE Automation)
During debugging, I’ve also created, AfterSave() and Open(). They triggers normally during normal operation, but fails when SaveAs has crashed. Eg as I disable SaveAs or when I open the excel book normally.
Private Sub Workbook_AfterSave(ByVal Success As Boolean)
On Error GoTo ErrHandler
If Success Then
Application.EnableEvents = False
'MsgBox "Success save", vbInformation ' for debugging purposes.
End If
ErrHandler:
Application.EnableEvents = True
End Sub
Private Sub Workbook_Open()
'MsgBox "I haz been opened, yehawww", vbInformation ' debugging
End Sub
Related
Im working on building out a VBA-based app that will have around 150 users. They will all have their own data files, tables, custom views, etc. But I will need to regularly update the code behind the app. So Im using the two-workbook technique where their unique User Workbooks (call them the UWs) all pass control to a Code Workbook (call it CW) which contains all the code. That way, when I need to update, I update the CW, and everyone simply replaces the old CW in their folders with the new one and their UWs remain the same.
My problem is that I'd like the CW to essentially remain hidden and protected. But with macro security, when they open their UWs after the update and it immediately calls the startup subroutine in the new CW, it won't run. They have to first open the CW (which I don't want!) and make it a trusted document before opening their UWs will run the startup subroutine in the CW.
It shouldn't matter, but here is the only code in the UWs (note this is still in prototyping/early stages so everything is called 'Test'!):
Private Sub Workbook_BeforeClose(Cancel As Boolean)
On Error Resume Next
Workbooks("Test CW.xlsm").Close
End Sub
Private Sub Workbook_Open()
Application.ScreenUpdating = False
'Checks to see if TestCW is present next to Test UW
On Error Resume Next
X = Workbooks("Test CW.xlsm").Name 'Sets X to name of workbook; if its not there this will throw an error and Err <> 0
If Not (Err = 0) Then 'If there's no error
On Error GoTo CWFileError
Workbooks.Open Filename:=ThisWorkbook.Path & Application.PathSeparator & "Test CW.xlsm" 'Opens Test CW if in same folder
'Makes Test CW hidden
Workbooks("Test CW.xlsm").Windows(1).Visible = False
End If
On Error GoTo 0
'Runs test module in Test CW, then returns control to here
With Application
.ScreenUpdating = True
.Run "'Test CW.xlsm'!ThisWorkbook.TestStart" 'Uses ThisWorkbook.TestSTart as TestStart is a Workbook-level subroutine in the ThisWorkbook module
End With
ThisWorkbook.Activate
Exit Sub
CWFileError:
MsgBox "Your SVEDash application file named Test CW is not in this folder." _
& vbCrLf _
& "Please locate your current SVEDash application file and place it in this folder." _
& vbCrLf _
& "This file will close to prevent damage to your data."
On Error GoTo 0
ThisWorkbook.Close
End Sub
Any ideas on how I can bypass this security issue without the users having to change their security settings?
This seemed to only be an issue with the first 'Updte'. As I copied newer 'updated' CW into the folder, as long as I kept the name consistent the previous trusted status of the former file with that name was remembered. Hopefully thats an actual solution
So I have an excel document that will just randomly break on me when opening it. I do have Code 1 in the VBA ThisWorkbook section but it doesn't start until I enable macros after opening it.
The images attached are in the order that they appear to me. One note is that I do have hidden files revealed and I only see the "Ownership file" when I have it open. I am on a shared network but I do not have the privileges to view where it all is open.
My current work around is to save the file under a different name and then delete the old file and rename it.
After researching a bit, someone stated it might have had to do with sorting. But I added Code 2 and I am still having the issue.
Code 1
Dim Result
Result = MsgBox("The Data in this document might be outdated. Would you like to refresh the Data Queries? This process could take a few minutes...", vbYesNo, "Data Query OutDated")
If Result = vbNo Then
Exit Sub
End If
MsgBox "Queries Will Refresh Upon Closing this window. Please wait"
ActiveWorkbook.Worksheets("SQLData").EnableCalculation = False
ActiveWorkbook.Worksheets("FlowBreakDown").EnableCalculation = False
Application.ScreenUpdating = False
Change_Background_Refresh False
ActiveWorkbook.RefreshAll
Application.ScreenUpdating = True
ActiveWorkbook.Worksheets("SQLData").EnableCalculation = True
ActiveWorkbook.Worksheets("SQLData").EnableCalculation = False
ActiveWorkbook.Worksheets("FlowBreakDown").EnableCalculation = False
MsgBox "Refresh Complete"
Call ResizeData
End Sub
Code 2
Dim Sht As Worksheet
' Clear all Sort Fields prior to Save & Exit
For Each Sht In Application.Worksheets
Sht.Sort.SortFields.Clear
Next Sht
End Sub
I'm working on vba and I would like to know how to change the access mode of a workbook that is open in read-only mode in read/write mode and continue with other instructions afterwards.
I managed to change the access mode except that it does not execute the following as instructions.
Thank you.
Sub RW()
If ThisWorkbook.ReadOnly Then
ThisWorkbook.Saved = True
ActiveWorkbook.ChangeFileAccess Mode:=xlReadWrite
End If
MsgBox "ok"
End Sub
More Sophisticated Version of your Code:
Take a look at the info present at this link about the function .ChangeFileAccess.
Sub RW()
If ThisWorkbook.ReadOnly Then
MsgBox "Access Changed from Read Only to Read/Write"
ThisWorkbook.Saved = True
ThisWorkbook.ChangeFileAccess Mode:=xlReadWrite
Else: MsgBox "No Access Changed"
End If
End Sub
I think the issue should be with Activeworkbook & Thisworkbook
Another Suggestion ... Read About Personal MacroWorkbook, and try and save this code in that, so you can use it efficiently and by defining proper references.
Microsoft states in its "Workbook.ChangeFileAccess Method" when you switch from a workbook that is opened ReadOnly to ReadWrite, that Excel needs to retrieve a new copy of the same workbook from disk, thus opening a new version of the file.
Given that this is the case, you would need to implement the code in the On_Open procedure of your workbook. Because this is the case, you will need to inform the user prior to doing the procedure that the status will be changed.
Note: if someone openes the workbook after it is sent in an email (just as an example) or any other way in which the file is not yet saved on disk, this may cause an error.
Private Sub Workbook_Open()
If ActiveWorkbook.ReadOnly Then
MsgBox "Access will be changed from Read Only to Read/Write." & _
vbNewLine & "The file will reopen in ReadWrite mode."
ActiveWorkbook.Saved = True
ActiveWorkbook.ChangeFileAccess Mode:=xlReadWrite
Else: MsgBox "No Access Changed"
End If
End Sub
I have one excel file that opens other excel files using VBA. These other excel files all run code on open — currently when the main file opens a file, it waits for the on open code to run in the file it just opened, and then opens the next file. I would like it to just open the files then move on to opening the next file without waiting for the on open code to finish — (I plan on limiting the number of files it has open at a time using process IDs) — any tips?
First you disable the run of macros, open the workbooks as you need them and then you reenable the run of macros. (as proposed here: Getting a .xlsm file to not execute code when being opened with VBA)
Private Sub OpenWorkBookMacroDisabled(wbPath As String)
Application.AutomationSecurity = msoAutomationSecurityForceDisable
Workbooks.Open (wbPath)
Application.AutomationSecurity = msoAutomationSecurityByUI
'or
'Application.AutomationSecurity = msoAutomationSecurityLow
End Sub
But actually this does not solve your problem. To run the macros it would be necessary to reopen the workbooks which then would again autostart the individual macros.
Workaround 1
A possible solution is mentioned here: https://www.ozgrid.com/forum/forum/help-forums/excel-general/47477-enabling-macros-without-re-opening-worksheet:
CREATE AN ENABLE/DISABLE VALIDATION CELL
The only work around if it was a problem could be something like a validation cell on your home / front page that said " enabled" / "disabled".
Then when opening the workbook always enable the macro's, then on workbook open auto set this to disabled.
then you would have all macros look at this ref and if disabled not run, and you would need to dial up enabled to allow any macro to run.
May not be what you want but a thought.
Workaround 2
Another workaround could be:
(1) Open the workbook(s) with the code mentioned above.
(2) Change Sub Workbook_Open to Sub Workbook_Open_OLD programmatically
(3) Save the workbook(s)
(4) Change AutomationSecurity to the desired level
(5) reopen your workbook(s)
Quite a lot of work!
For details see: http://www.cpearson.com/excel/vbe.aspx
Workaround 3
A variation to the enable/disable validation cell is the use of a central property
e.g. Application.Username
**This Macro calls the 'other excel files':**
Sub Main0()
'TEST 1:
'Open workbook and DON'T run macros
'Call "YourCode" manually
Application.UserName = "NoMacroRun"
Debug.Print "Test 1:"
Debug.Print Application.UserName
Workbooks.Open ThisWorkbook.Path & "\macro_010.xlsb"
Debug.Print "Open finished"
Debug.Print "Call YourCode"
Run "macro_010.xlsb!YourCode"
Workbooks("macro_010.xlsb").Close SaveChanges:=False
Debug.Print "Test 1: FINISHED successfully"
Debug.Print ""
'TEST 2:
'Open workbook and run macros
Application.UserName = "SomeThingElse"
Debug.Print "Test 2:"
Debug.Print Application.UserName
Workbooks.Open ThisWorkbook.Path & "\macro_010.xlsb"
Debug.Print "Test 2: FINISHED successfully"
Debug.Print ""
Workbooks("macro_010.xlsb").Close SaveChanges:=False
Debug.Print ""
End Sub
The other files look like:
In 'the other files' you seperate "YourCode" from "Workbook_Open" and make it callable from the outside:
'doubleclick "ThisWorkbook" in the IDE and insert this code there
Public Sub Workbook_Open()
If Application.UserName <> "NoMacroRun" Then
Debug.Print "---> " & ThisWorkbook.Name & ": Workbook_Open is part of ThisWorkbook in the IDE"
'your code
Call YourCode
End If
End Sub
This code you insert into a module:
'doubleclick "module" in the IDE and insert this code there
'OR click in the menu --> Insert --> Module
Sub YourCode()
Debug.Print "---> " & ThisWorkbook.Name & ": ""Sub YourCode"" is part of a module in the IDE!"
End Sub
And finally, the Immediate Window proves that it works as intended:
Test 1:
NoMacroRun
Open finished
Call YourCode
---> macro_010.xlsb: "Sub YourCode" is part of a module in the IDE!
Test 1: finished successfully
Test 2:
SomeThingElse
---> macro_010.xlsb: Workbook_Open is part of ThisWorkbook in the IDE
---> macro_010.xlsb: "Sub YourCode" is part of a module in the IDE!
Test 2: finished successfully
Q.E.D. ;-)
My excel file contains a lot of formulas and I therefore want it to set calculation mode to manual as soon as it is opened. Otherwise calculation starts automatically and I have to wait for hours. I found this page:
http://excel.tips.net/T001988_Forcing_Manual_Calculation_For_a_Workbook.html
which should be able to do the trick. However it's not working for my excel-file. It states that in the VBA-code, in the section "ThisWorkbook", the following code should be entered:
Private Sub Workbook_Open()
Application.Calculation = xlManual
Application.CalculateBeforeSave = False
End Sub
As pointed it out, it doesn't work in my case. Does someone have an alternative solution?
The best way around this would be to create an Excel called 'launcher.xlsm' in the same folder as the file you wish to open. In the 'launcher' file put the following code in the 'Workbook' object, but set the constant TargetWBName to be the name of the file you wish to open.
Private Const TargetWBName As String = "myworkbook.xlsx"
'// First, a function to tell us if the workbook is already open...
Function WorkbookOpen(WorkBookName As String) As Boolean
' returns TRUE if the workbook is open
WorkbookOpen = False
On Error GoTo WorkBookNotOpen
If Len(Application.Workbooks(WorkBookName).Name) > 0 Then
WorkbookOpen = True
Exit Function
End If
WorkBookNotOpen:
End Function
Private Sub Workbook_Open()
'Check if our target workbook is open
If WorkbookOpen(TargetWBName) = False Then
'set calculation to manual
Application.Calculation = xlCalculationManual
Workbooks.Open ThisWorkbook.Path & "\" & TargetWBName
DoEvents
Me.Close False
End If
End Sub
Set the constant 'TargetWBName' to be the name of the workbook that you wish to open.
This code will simply switch calculation to manual, then open the file. The launcher file will then automatically close itself.
*NOTE: If you do not wish to be prompted to 'Enable Content' every time you open this file (depending on your security settings) you should temporarily remove the 'me.close' to prevent it from closing itself, save the file and set it to be trusted, and then re-enable the 'me.close' call before saving again. Alternatively, you could just set the False to True after Me.Close