Calling .SaveAs Crashes Excel - vba

I have created an xlam (Excel 2007 Add-In) file to handle manipulation of various files. I am trying to write a procedure in that xlam file that removes some worksheets from an opened xlsm file, and saves it as an xlsx (i.e. without macros).
So far the only thing I can do reliably is to crash Excel whenever I reach the .SaveAs call. The crash comes as a Windows Dialog stating:
Microsoft Office Excel has stopped working, Windows can try to recover your information and restart the program. [Restart the program] [Debug the Program]
In the folder that I am saving to, after every crash I am left with a temp file (ex. filename: 7A275000 with size: 0) in the folder it tried to save to.
For posterity here some things I have tried, and all have resulted in the same crash:
Hard coded filename value ("C:\Users\myUserName\Desktop\temp.xlsx")
Prompted filename from User (shown in code below)
filename without path ("temp.xlsx")
filename without extension ("C:\Users\myUserName\Desktop\temp")
filename as existing filename without extension
filename as existing filename with .xlsx extension
instead of using wb.SaveAs, I used wb.Activate followed by ActiveWorkbook.SaveAs
I have tried FileFormat:=xlOpenXMLWorkbook and FileFormat:=xlWorkbookNormal
Saved to several different directories of varying length
Added an Error trapping statement around the .SaveAs call (it does not trap any errors, and crashes Excel just the same)
The last weird bit is when I try to do a manual Save-As on the file (i.e. navigating to the Save-As menu myself) after the ws.delete calls, Excel crashes the same way. If I manually delete the Worksheets myself, then do a manual Save-As, it saves just fine.
Here is the offending code:
Public Sub ConvertToStagingFile(ByRef wb As Workbook)
Dim reWS As Object, reFILE As Object
Dim ws As Worksheet
Set reWS = CreateObject("VBScript.regexp")
reWS.IgnoreCase = True: reWS.Global = False: reWS.MultiLine = False
Set reFILE = CreateObject("VBScript.regexp")
reFILE.IgnoreCase = True: reFILE.Global = False: reFILE.MultiLine = False
reWS.Pattern = "^(home|location settings|date reference|[\w\s]{1,8} (rating|inquire) data|pkl data - \w{1,8}|verbs - \w{1,8})"
reFILE.Pattern = "\.xlsm$"
For Each ws In wb.Worksheets
If (ws.Visible = xlSheetHidden) Or (ws.Visible = xlSheetVeryHidden) Then
ws.Visible = xlSheetVisible
End If
Select Case True
Case reWS.test(ws.name)
'// Do Nothing
Case Else
Application.DisplayAlerts = False
ws.Delete
Application.DisplayAlerts = True
End Select
Next ws
ActiveWindow.TabRatio = 0.75
If (reFILE.test(Cached.getAdhocReportFull)) Then
Dim newName As Variant
newName = Application.GetSaveAsFilename(reFILE.Replace(Cached.getAdhocReportFull, ""), "*.xlsx")
If newName = False Then Exit Sub
wb.Activate
Application.EnableEvents = False
'// CODE RELIABLY CRASHES HERE
wb.SaveAs _
FileName:=newName, _
FileFormat:=xlOpenXMLWorkbook, _
CreateBackup:=False
Application.EnableEvents = True
End If
End Sub
Any help on this issue would be greatly appreciated.

I had what seems like exactly the same issue:
Excel 2013
Macro to delete worksheet in xlsm file
Subsequent calls to .Save, or manually saving file crashes Excel (same dialog as Hari)
The issue only appeared for us when we updated from .xls to the 'new' office file format
For info, our files are not that large (only 300kB)
As our intention is to replace the sheet the following works for us: rename old worksheet, create new worksheet (same name as old worksheet), delete the old worksheet. Seems to work for us. Why does it work? No idea.

Related

Excel -Run Time Error 1004 'Application Defined or Object Defined Error'

I have an Excel 2003 spreadsheet ("Tune.xls") with some VBA. It always fails with error:
Run Time Error 1004 'Application Defined or Object Defined Error'
When I click debug it brings me to the following line in the code :
DataImport.Range("J10").Value = FileName 'Copy path and filename to worksheet "Import Data"
and also please look into whole code as follows:
'Ensure that all global (public) flags are initialized properly; they might have been
'changed before the user requested a data import.
Sub_Error = False
Changed_Model_1 = False
Changed_Model_2 = False
Plot_Model_1 = False
Plot_Model_2 = False
Updated_Model_1 = False
Updated_Model_2 = False
'Disable screen updating to avoid flicker when graph data is modified. Puting the focus away
'from the graph to worksheet "Data Import" speeds up the execution by a factor of about 4. This trick
'is ad hoc and I cannot explain why it works, but it does...
Application.ScreenUpdating = False
DataImport.Select
'Open window to select data file. If no file is opened, then the variable FileName will be false.
FileName = Application.GetOpenFilename("Text Files (*.txt; *.dat),*.txt;*.dat, Excel Files (*.xls),*.xls", , "Open Process Data File")
If FileName = False Then Exit Sub 'exit if no file was opened or cancel button selected
******DataImport.Range("J10").Value = FileName 'Copy path and filename to worksheet "Import Data"******
'Open data file as a workbook and use shortcut name "DataSheet" for worksheet containing data.
Workbooks.Open FileName:=FileName, updateLinks:=0 'does not update linked cells
Set DataSheet = ActiveWorkbook.ActiveSheet
Set DataBook = ActiveWorkbook 'use shortcut for Data workbook
'The data workbook might contain cells referencing a DDE link. This makes it hard to manipulate
'the cells. Therefore, the entire worksheet is copied and only the values are pasted back. This
'will essentially remove all the DDE references.
DataSheet.Cells.Select 'This selects all cells
Selection.Copy
Selection.PasteSpecial Paste:=xlValues
Please can somebody help me to get this working again?
1004 is an error which can come because of various reasons. In general, it may be because:
some of the objects are not defined correctly;
the worksheet is locked;
Thus, to check the first option write these two lines before the error:
MsgBox Filename
MsgBox DataImport.Name
and see what you get. You should get something for Filename (not an error) and the DataImport.Name should be the name of the sheet.
Concerning the second option - check whether the cells in DataImport are not locked.

VBA: compile error after .copy

If have a large Workbook with a sub, that copies a specific worksheet to a new workbook and then saves this worksheet as FileFormat51 (xlsx without macro) to get rid of the contained code:
Public Sub savefile()
Dim WB As Workbook, WBtemp As Workbook
Dim path As String, antw As String, ext As String
Dim filetobesaved
path = ThisWorkbook.path
With Application.FileDialog(msoFileDialogSaveAs)
.InitialFileName = path & "\" & "standard name"
Application.ScreenUpdating = True
antw = .Show
Application.ScreenUpdating = False
If antw = -1 Then
filetobesaved = .SelectedItems(1)
ext = Right(filetobesaved, Len(filetobesaved) - InStrRev(filetobesaved, ".")) 'InStrRev() finds the first dot from the right and gives its position to Right() to write the file extension into ext
If ext <> "xlsx" Then
MsgBox "You chose ." & ext & " as filename extension. As this might cause problems during the current procedure I will change it to .xlsx."
filetobesaved = Left(filetobesaved, InStrRev(filetobesaved, ".")) & "xlsx"
End If
Else
Exit Sub
End If
End With
Set WB = ActiveWorkbook
TKontur.Copy
Set WBtemp = ActiveWorkbook
WBtemp.SaveAs Filename:=filetobesaved, FileFormat:=51 '51 = .xlsx without macros
WBtemp.Close
End Sub
This worked well for years until Excel started compiling the code right after the Worksheet got copied.
The code of the workbook compiles well before the copy-task (debug->Compile VBAProject works fine) but after the copy-statement the code fails to compile for many reasons that all include that the worksheet got copied into a new workbook without all the other worksheets and modules it references.
Currently if I restart the PC and then open the workbook and only execute the given sub, then I get said error.
The weird thing is at first I thought it was a data corruption error and rebuilt the whole thing (and rebuilt it again multiple times until now) and after every rebuild everything works fine for at least one time but eventually the same bug reappears and I have no clue what causes it to reappear.
I also found out that deleting any module (no matter which one), saving the Workbook and then reopening the workbook causes the error to not occur at least one time (-> all fine) no matter which module I delete.
So I thought it might be a problem with memory overflow.
But then when I rewrote the program with the most basic functions but half the code and half the modules this worked fine for two weeks and then the error reappeared.
It gets weirder: I wrote a more basic version with version number say 2.0
In those two weeks I changed some things to version 2.5
Most versions were in use at some time and worked.
But when the error occured in version 2.5 once all versions back to 2.0 started to have the same error right away when they did not have it before.
Also if the error occured at least one time, then no matter what I change it will occure every time except if I remove every single one of the many references to things in other modules and worksheets than the copied one.
There's also a very similar error that happens to be kind of unrelated (either error can happen without the other error and sometimes they happen both and sometimes neither happens) but has very similar properties:
When closing the workbook sometimes excel closes the excel-objects first and then compiles the modules and fails with that.
When that happens, then
ThisWorkbook.Saved = True
ActiveWorkbook.Close
usually helps to ignore that error for a while, but then (usually after a year or so) it reappears even with those two lines. Edit: Also this workaround seems to have a 20% chance to crash Excel including all other open workbooks.
Last thing: As soon as the error occurs once
most of the time it then occurs on all PCs and Notebooks including different update status, Operating System and Office version.
I disabled events (Application.EnableEvents = False) before saving the workbook as a workaround. It worked for me!
Also, as I prefer to use the Excel constants name for better readability instead of Excel constant values. For eg. below are the main formats, I use xlOpenXMLWorkbook for xlsx instead of just 51. Though this has nothing to do with the error you or I was getting.
51 = xlOpenXMLWorkbook (without macro's in 2007-2016, xlsx)
52 = xlOpenXMLWorkbookMacroEnabled (with or without macro's in 2007-2016, xlsm)
50 = xlExcel12 (Excel Binary Workbook in 2007-2016 with or without macro's, xlsb)
56 = xlExcel8 (97-2003 format in Excel 2007-2016, xls)
Here is the modified code for reference:
Public Sub savefile()
Dim WB As Workbook, WBtemp As Workbook
Dim path As String, antw As String, ext As String
Dim filetobesaved
path = ThisWorkbook.path
With Application.FileDialog(msoFileDialogSaveAs)
.InitialFileName = path & "\" & "standard name"
Application.ScreenUpdating = True
antw = .Show
Application.ScreenUpdating = False
If antw = -1 Then
filetobesaved = .SelectedItems(1)
ext = Right(filetobesaved, Len(filetobesaved) - InStrRev(filetobesaved, ".")) 'InStrRev() finds the first dot from the right and gives its position to Right() to write the file extension into ext
If ext <> "xlsx" Then
MsgBox "You chose ." & ext & " as filename extension. As this might cause problems during the current procedure I will change it to .xlsx."
filetobesaved = Left(filetobesaved, InStrRev(filetobesaved, ".")) & "xlsx"
End If
Else
Exit Sub
End If
End With
Set WB = ActiveWorkbook
TKontur.Copy
Set WBtemp = ActiveWorkbook
Application.EnableEvents = False
WBtemp.SaveAs Filename:=filetobesaved, FileFormat:=xlOpenXMLWorkbook ' = xlsx
WBtemp.Close
Application.EnableEvents = True
End Sub

Save dialog box freezes during loop

I have a VBA program that pulls data from a network location, processes the data, and then saves it as a single CSV file. This loop will create over a 1000 separate CSV files.
The error that I get is that seemingly at random, the saving dialog box will just get stuck. It's like it's saving the file, but never completes, and will sit there indefinitely. If I hit cancel, the macro just proceeds. (I blacked out the file name)
My code for this is:
Application.ScreenUpdating = False
counter = 2
Do Until ThisWorkbook.Sheets("Production_Data").Cells(Counter, 5).Value = ""
'''' Main operations go here ''''
'Save workbook to new file
Application.DisplayAlerts = False
'move worksheet to new workbook
Set newbook = Workbooks.Add(1) 'create new workbook object with only 1 sheet
newbook.Sheets(1).Name = "toDelete" 'name the worksheet
ws.Activate 'activate the temporary worksheet to be moved
Sheets(tempSheetName).Move Before:=newbook.Sheets(1)
newbook.Sheets("toDelete").Delete 'remove the blank sheet created in new workbook
'save as CSV file
fname = destPath & "/" & tempSheetName & ".csv"
newbook.SaveAs FileName:=fname, FileFormat:=xlCSV
newbook.Close
Application.DisplayAlerts = True
counter = counter + 1
loop
Application.ScreenUpdating = True
Is there any way to automatically exit this "frozen" dialog box and continue the macro? Is there something wrong with my code? Ideally this could be avoided all together.
The only other idea I've had is that my excel book with the macro is on a network drive, and maybe somehow that gets it to freeze up somehow?
edit
I tried adding set newbook = Nothing after closing it, but it still remains open in the VBA Project manager.

Suppress "Save As" prompt

I looked this topic up and found some help but the suggestions do not seem to be working.
I am opening a CSV file into EXCEL make some changes and then want to save the results back to the same file name and the CSV format.
I want to do this without the prompt that I am getting to make sure I want to save the file.
We are using a macro enabled excel file to import the data make changes and then save.
This whole process with initiated by a batch file that will open the Excel application and the designated file at regular period of time so that is why we do not want the prompt to stop the process.
Here is the code I am using in VBA to do the work, as well as the other subs I found that were suppose to help me suppress the prompt.
This code is in the TheWorkbook of the file and not a module.
Am I missing something?
code
Sub fixfile()
Const strFileName = "W:\Webshare\Documents Acquired in 2017\Jim Excel\snr-room-schedule.csv"
Dim wbkS As Workbook
Dim wshS As Worksheet
Dim wshT As Worksheet
Set wshT = Worksheets.Add(After:=Worksheets(Worksheets.Count))
Set wbkS = Workbooks.Open(Filename:=strFileName)
Set wshS = wbkS.Worksheets(1)
wshS.UsedRange.Copy Destination:=wshT.Range("A1")
wbkS.Close SaveChanges:=False
'This is the area of work that we doing to the data
'Through here
Application.DisplayAlerts = False 'IT WORKS TO DISABLE ALERT PROMPT
ActiveWorkbook.SaveAs Filename:= _
"W:\Webshare\Documents Acquired in 2017\Jim Excel\snr-room-schedule.csv", FileFormat _
:=xlCSVMSDOS, CreateBackup:=False
Application.DisplayAlerts = True 'RESETS DISPLAY ALERTS
Application.Quit
End Sub
Private Sub Workbook_Open()
fixfile
End Sub
Sub CloseandSave()
ActiveWorkbook.Close SaveChanges:=True
End Sub
Private Sub Workbook_BeforeClose(Cancel As Boolean)
ThisWorkbook.Save
End Sub
The problems in your code are due to the following.
When you call SaveAs on the macro-enabled workbook, you had already appended a worksheet to it:
Set wshT = Worksheets.Add(After:=Worksheets(Worksheets.Count))
and then you're trying to save it as csv, which is a text file with only one worksheet, so Excel complains that you will loose information.
Moreover, you're doing the update to the csv twice: once in the
ActiveWorkbook.SaveAs Filename:= ...
Where, as a result, the current workbook becomes the saved workbook, and then again in the Workbook_BeforeClose. In the latter you dont disable the alerts, but anyway there's no need to save again.
I have come to the conclusion that what you want is to use the macro-enabled wb just as a utility for calculation, and you care only for updating the CSV workbook.
For simplicity, we will disable the alerts for the whole session, because the macro-enabled WB is used as a utility and we dont want the batch job to stop for any reason. However you can do it the traditional way, before and after saving, if you feel more comfortable with it.
' Code module ThisWorkbook
Option Explicit
Private Sub Workbook_Open()
Application.DisplayAlerts = False
Application.ScreenUpdating = False
fixCSVFile
' Do the following only if you want the macro-enabled WB to keep
' a copy of the CSV worksheet. but my feeling is you dont want to
' ThisWorkbook.Save
'''''''''''''''''''''
Application.Quit
End Sub
Sub fixCSVFile()
Const strFileName = "W:\Webshare\Documents Acquired in 2017\Jim Excel\snr-room-schedule.csv"
Dim wbkS As Workbook, wshS As Worksheet, wshT As Worksheet
Set wshT = Worksheets.Add(After:=Worksheets(Worksheets.Count))
Set wbkS = Workbooks.Open(Filename:=strFileName)
Set wshS = wbkS.Worksheets(1)
wshS.UsedRange.Copy Destination:=wshT.Range("A1")
wbkS.Close SaveChanges:=False
'This is the area of work that we doing to the data
' For purpose of testing:
wshT.Range("A1").Value = wshT.Range("A1").Value + 1
' Now we will export back the modified csv
wshT.Move '<- Here we have a temporary workbook copy of the modified csv
With ActiveWorkbook
.SaveAs Filename:=strFileName, FileFormat:=xlCSVMSDOS, CreateBackup:=False
.Close False
End With
End Sub
One more thing, the macro-enabled WB is now such that it closes as soon as it opens so it will be difficult to edit or modify (although there are workarounds). Therefore you should save a back-up copy of it without the Application.Quit, as a testing/maintenance copy. Only the copy that you put in production for the sake of the batch job should have the Application.Quit statement.
Based on the comment in the answers that the reason for opening the file and immediately saving it with no other changes...
So we needed to do what we were doing to get the file edit date to
change but not the actual file.
...this is a complete X-Y problem. If you need to change a file's modified time, just change the file's modified time instead of jumping through all of the opening and re-saving hoops:
Sub UpdateFileModifiedDate()
Const filePath = "W:\Webshare\Documents Acquired in 2017\Jim Excel\snr-room-schedule.csv"
Dim handle As Integer
handle = FreeFile
Open filePath For Binary As #handle
'Read the first byte.
Dim first As Byte
Get #handle, 1, first
'Write it back
Put #handle, 1, first
Close #handle
End Sub
This will be insanely faster than your current process, will only set the file modified date and time to the time that you run the Sub, and doesn't risk any of the other issues you can run into cycling a CSV file through Excel (date formats and locale issues, truncating decimals, conversions to exponential notation, etc., etc.).
since you're going to consciously overwrite an existing file you can just:
first delete it with a Kill command
then do the SaveAs
so change this code section:
'This is the area of work that we doing to the data
'Through here
Application.DisplayAlerts = False 'IT WORKS TO DISABLE ALERT PROMPT
ActiveWorkbook.SaveAs Filename:= _
"W:\Webshare\Documents Acquired in 2017\Jim Excel\snr-room-schedule.csv", FileFormat _
:=xlCSVMSDOS, CreateBackup:=False
Application.DisplayAlerts = True 'RESETS DISPLAY ALERTS
Application.Quit
to this:
'This is the area of work that we doing to the data
'Through here
Kill strFileName '<-- delete the old file
ActiveWorkbook.SaveAs Filename:= _
"W:\Webshare\Documents Acquired in 2017\Jim Excel\snr-room-schedule.csv", FileFormat _
:=xlCSVMSDOS, CreateBackup:=False
Application.Quit
furthermore your code can be refactored by properly handling the ActiveWorkbook and ActiveSheet objects and reduce the variables and code amount, like follows:
Sub fixfile()
Const strFileName = "W:\Webshare\Documents Acquired in 2017\Jim Excel\snr-room-schedule.csv"
Workbooks.Open(Filename:=strFileName).Worksheets(1).UsedRange.Copy Destination:=Worksheets.Add(After:=Worksheets(Worksheets.Count)).Range("A1") '<--| open 'strFileName', reference and copy its 1st worksheet 'UsedRange' and paste it to a newly added worksheet in the macro workbook. After this statement we're left with the opened workbook as `ActiveWorkbook`
ActiveWorkbook.Close SaveChanges:=False '<--| close `ActiveWorkbook`, i.e. the just opened one. We're left with macro workbook as `ActiveWorkbook` and its newly created worksheet as `ActiveSheet`
'This is the area of work that we doing to the data
'Through here
ActiveSheet.Move '<--| move `ActiveSheet` (i.e. the newly created sheet in macro workbook) to a "new" workbook having that sheet as its only one. We're left with this "new" workbook as `ActiveWorkbook`
Kill strFileName '<--| delete the "old" 'strFileName'
ActiveWorkbook.SaveAs Filename:=strFileName, FileFormat:=xlCSVMSDOS, CreateBackup:=False '<--| save `ActiveWorkbook` (i.e the "new" one) as the new 'strFileName' file
ActiveWorkbook.Close SaveChanges:=False '<--| close `ActiveWorkbook` (i.e the "new" one) without changes (we just "SavedA"s it)
Application.Quit
End Sub
It seems like you are making changes to two files. In addition to the csv file that you are opening, you appear to be adding a sheet to the excel file that is running the VBA code with these lines:
Dim wshT As Worksheet
Set wshT = Worksheets.Add(After:=Worksheets(Worksheets.Count))
So my guess is that you are indeed suppressing the save prompt for the csv file but you are also getting a save prompt for the changes you made to the excel workbook when you attempt to close it. So I think you need to suppress that prompt as well by also turning off DisplayAlerts in the CloseAndSave sub, or wherever the excel workbook is actually being closed.
I don't get why you are copying the CSV sheet into a new sheet in the macro enabled workbook. This is where your problem starts!
You should just be dealing with the data in wshS and saving wbkS instead.
Done, no more problems.
When you call
ActiveWorkbook.SaveAs Filename:= _
"W:\Webshare\Documents Acquired in 2017\Jim Excel\snr-room-schedule.csv",
FileFormat:=xlCSVMSDOS, CreateBackup:=False`
you're renaming the current macro enabled file within excel to the CSV file as far as Excel sees it.
When Application.Quit is called, it is going to call
Private Sub Workbook_BeforeClose(Cancel As Boolean)
ThisWorkbook.Save
End Sub
Which is where the prompt that you are complaining about is happening.
Even if you remove it, after Workbook_BeforeClose is called, Excel is still going to check all the open files' .Saved flag.
Excel will prompt you to save any files where .Saved = False
But if you set ThisWorkbook.Saved = True then Excel will close the file without asking to save.
Solution:
Private Sub Workbook_BeforeClose(Cancel As Boolean)
ThisWorkbook.Saved = True
End Sub

Exporting excel file to HTML via VBA causes trouble - neverending "Want to save?" pop-up

I am trying to export current workbook to HTML site with current timestamp using this code
Private Sub btnSave_Click()
ActiveWorkbook.Save 'Save current file
Dim ActSheet As Worksheet
Dim ActBook As Workbook
Dim CurrentFile As String
Dim NewFileType As String
Dim NewFile As String
Application.ScreenUpdating = False ' Prevents screen refreshing.
CurrentFile = ThisWorkbook.FullName ' Remeber location of original file
NewFileType = "Web files File (*.HTML), *.html" 'Set file type
Newfilename = "Shed9-" & Format(CStr(Now), "yyyy-mm-dd_hh-mm") 'Save as timestamp
NewFile = Application.GetSaveAsFilename( _
InitialFileName:=Newfilename, _
fileFilter:=NewFileType)
If NewFile <> "" And NewFile <> "False" Then
ActiveWorkbook.SaveAs Filename:=NewFile, _
FileFormat:=xlHtml
Set ActBook = ActiveWorkbook
Workbooks.Open CurrentFile
ActBook.Close
End If
Application.ScreenUpdating = True
End Sub
In theory this procedure should save current file, save copy (with a time stamp, ignoring VBA) as a web page, close the web page (which to be honest I don't even want to open) and get back to the original spreadsheet.
Unfortunately the problem is with the closing part: Excel opens the web page (!) and then I have never-ending pop-up question "Do you want to save the file "Shed-9 .html?"
So how can I remove that pop-up and simply export without opening?
EDIT
I've tried to force-save the HTML copy before closing by putting the
ActBook.Save
ActBook.Close
But that leads to an error:
"An item with the same key has already been added". If thats important the workbook has multiple sheets and data taken through PowerQuery
EDIT
(The original code came from here) - the original author should receive his/her credit
Try:
ActBook.Close False
If you save a workbook in a non-excel format it will ask you if you want to save the file again anyway, without fail. Using the optional "False" parameter tells excel that you want to close without saving.
You could safely skip these lines, where you actually ask Excel to do just that (open the file):
Set ActBook = ActiveWorkbook
Workbooks.Open CurrentFile
ActBook.Close
I think what might confuse you is that have turned off screen updating, which hides what happens to you (behind the scenes).
Application.ScreenUpdating = False
This is all good if you really want to hide what's going on, but I imagine it might confuse you as long you have the Workbooks.Open code.