Why can't Excel loop through large datasets?!
I have 2 different document forms which need to be exported to PDF by the hundreds. I pulled the batch export script from the internet and modified it for my usage so it would process either of these forms depending on the checkbox selected on the "Batch PDF Printer" worksheet.
Everything runs well - for the first 10-15 workbooks accessed by the loop, and then it crashes. Every Excel document freezes (Not Responding) and the page that is currently accessed by the Macro partially opens with no visible data or cells. The "Publishing" message box may also freeze at this point. Once it reported a lack of memory error - but I have not been able to repeat this. Shouldn't Excel be deleting unused cache's so as to not overload the memory? I would suspect a bum loop if it didn't run well for a while. I've heard there is no way to script in a "cache dump" or something of that nature. Is it bad code, or am I asking too much of my processor?
Sub Convert2PDF()
'Update the checkbox linked formulas on the GUI workbook
Sheet1.Range("A2").Formula = Sheet1.Range("A2").Formula
Sheet1.Range("B2").Formula = Sheet1.Range("B2").Formula
Sheet1.Range("C2").Formula = Sheet1.Range("C2").Formula
Dim strFolder As String
Dim strXLFile As String
Dim strPDFFile As String
Dim wbk As Workbook
Dim lngPos As Long
' set folder
strFolder = ThisWorkbook.Path & "\putfileshere" & "\"
Application.ScreenUpdating = False
' Get first filename
strXLFile = Dir(strFolder & "*.xls*")
' Loop through Excel workbooks in folder
Do While strXLFile <> ""
' Open workbook
Set wbk = Workbooks.Open(Filename:=strFolder & strXLFile)
' Assemble the PDF filename
lngPos = InStrRev(strXLFile, ".")
strPDFFile = Left(strXLFile, lngPos) & "pdf"
' Export to PDF
'Do the next 8 lines crash the Macro because they recalculate for every sheet? Page1, Page2, Page3 value are the same for all workbooks processed in a batch
Dim Page1 As String
Dim Page2 As String
Dim Page3 As String
Dim Page4 As String
Page1 = ThisWorkbook.Sheets("Batch PDF Printer").Range("A2")
Page2 = ThisWorkbook.Sheets("Batch PDF Printer").Range("B2")
Page3 = ThisWorkbook.Sheets("Batch PDF Printer").Range("C2")
If ThisWorkbook.Sheets("Batch PDF Printer").Range("C2") = "" Then
wbk.Sheets(Array(Page1, Page2)).Select
ActiveSheet.ExportAsFixedFormat Type:=xlTypePDF, Filename:= _
ThisWorkbook.Path & "\pdfsgohere" & "\" & wbk.Name, _
Quality:=xlQualityStandard, IncludeDocProperties:=False, _
IgnorePrintAreas:=False, OpenAfterPublish:=False
'run process for format option 2
Else:
wbk.Sheets(Array(Page1, Page2, Page3)).Select
ActiveSheet.ExportAsFixedFormat Type:=xlTypePDF, Filename:= _
ThisWorkbook.Path & "\pdfsgohere" & "\" & wbk.Name, _
Quality:=xlQualityStandard, IncludeDocProperties:=False, _
IgnorePrintAreas:=False, OpenAfterPublish:=False
'Tried killing the finished document to improve function
Dim xFullName As String
xFullName = Application.ActiveWorkbook.FullName
ActiveWorkbook.Saved = True
Application.ActiveWorkbook.ChangeFileAccess xlReadOnly
Kill xFullName
Application.ActiveWorkbook.Close False
End If
' Close workbook - didn't seem to help (can't do it when the workbook is gone)
'wbk.Close SaveChanges:=False
' Get next filename
strXLFile = Dir
Loop
Application.ScreenUpdating = True
MsgBox "All Done"
Thanks for the help. I've been trying to figure this out for days now.
This ran for me on >30 files with no problem:
Sub Convert2PDF()
Dim strFolder As String, strXLFile As String
Dim strPDFFile As String
Dim wbk As Workbook
Dim lngPos As Long
Dim pages(1 To 4) As String
Dim shtBatch As Worksheet, arr
Set shtBatch = ThisWorkbook.Sheets("Batch PDF Printer")
shtBatch.Range("A2:C2").Calculate '<< assume this was the point of resetting the formulas?
pages(1) = shtBatch.Range("A2").Value
pages(2) = shtBatch.Range("B2").Value
pages(3) = shtBatch.Range("C2").Value
'what pages to print? Only need to do this once
arr = IIf(Len(pages(3)) = 0, Array(pages(1), pages(2)), _
Array(pages(1), pages(2), pages(3)))
strFolder = ThisWorkbook.Path & "\putfileshere\"
strXLFile = Dir(strFolder & "*.xls*")
Do While strXLFile <> ""
Set wbk = Workbooks.Open(Filename:=strFolder & strXLFile, ReadOnly:=True)
lngPos = InStrRev(strXLFile, ".")
strPDFFile = Left(strXLFile, lngPos) & "pdf"
wbk.Sheets(arr).Select
ActiveSheet.ExportAsFixedFormat Type:=xlTypePDF, _
Filename:=ThisWorkbook.Path & "\pdfsgohere\" & strPDFFile, _
Quality:=xlQualityStandard, IncludeDocProperties:=False, _
IgnorePrintAreas:=False, OpenAfterPublish:=False
wbk.Close False
strXLFile = Dir
Loop
MsgBox "All Done"
End Sub
Even if your visible system RAM is not overloading, the internal capacity of the Excel application seems to be exceeded for a brief moment. I was able to finally view the message box "Not enough system resources to display completely" before the app went into automatic reboot. Try streamlining the workbooks being accessed by the loop. If your workbooks take a while to start up, that may be indication of heavy background processes (calculations and VBA subs). DoEvents may help the code run more smoothly by asking for more processing time so the system can sort it's demands. Ultimately,
Application.Calculation = xlManual
at the top of the loop was sufficient to reduce the computational demands on the 20 gig system (which I never expected to overload).
If you have linked images in your exports.
Exported linked images leaves behind a bit or byte in the kernel, which accumulates and eventually breaks excel.
I found this solution only 1 place on the internet and i cannot find it again, but it got me from 200s to 1000 loops of VBA Macro by removing linked images.
Nothing in the VBA code would help, i used pauses, save the workbook to clear memory, disable events etc...
I wrote an answer to my problem here: https://stackoverflow.com/a/53600884/10069870
Disregard if you have no linked images in your exports :)
Related
Going through the stack overflow and other sources on the internet, I found a couple of VBA codes to print multiple active worksheets to separate PDF files.
I would like to use the same printing area in each sheet and save the PDFs as separate files. While trying to (re)create the code, I have now reached the following state and am stuck. More specifically, it seems that the last four lines before "Next" are erroneous (makred in red in Excel VBA Console and causing syntax error), but I am unable to pinpoint what that is so. Can someone here help me out. Thanks in advance.
Sub SetPrintAreas2()
Dim sPrintArea As String
Dim wks As Worksheet
sPrintArea = "C8:E25"
For Each wks In ActiveWindow.SelectedSheets
wks.PageSetup.PrintArea = sPrintArea
wks.PageSetup.Orientation = xlLandscape
wks.PageSetup.PaperSize = xlPaperA4
wks.PageSetup.CenterHorizontally = True
wks.PageSetup.CenterVertically = True
wks.PageSetup.FitToPagesWide = 1
wks.PageSetup.FitToPagesTall = 1
wks.ExportAsFixedFormat Type:=xlTypePDF, _
Filename:=Application.ActiveWorkbook.Path & “\” & wks.Name, _
Quality:=xlQualityStandard, _
IgnorePrintAreas:=False, _
OpenAfterPublish:=False
Next
Set wks = Nothing
End Sub
Thanks to all of you helped make a completely unworkable code full functional. This is how the final working code looks:
Sub SetPrintSameAreasOfActiveSheetsAsPDFs()
Dim sPrintArea As String
Dim wks As Worksheet
sPrintArea = "C8:E25"
For Each wks In ActiveWindow.SelectedSheets
wks.PageSetup.PrintArea = sPrintArea
wks.PageSetup.Orientation = xlLandscape
wks.PageSetup.PaperSize = xlPaperA4
wks.PageSetup.CenterHorizontally = True
wks.PageSetup.CenterVertically = True
wks.PageSetup.FitToPagesWide = 1
wks.PageSetup.FitToPagesTall = 1
wks.ExportAsFixedFormat Type:=xlTypePDF, _
Filename:=Application.ActiveWorkbook.Path & Application.PathSeparator & wks.Name, _
Quality:=xlQualityStandard, _
IgnorePrintAreas:=False, _
OpenAfterPublish:=False
Next
Set wks = Nothing
End Sub
It prints the Cells between C8:E25 for all selected worksheets in an Excel workbook as PDFs to the same directory. The PDFs take up the name of the worksheet. To use it, after inserting it as a VBA module in the excel sheet, go to the developer tab, Click on Macros, select SetPrintSameAreasOfActiveSheetsAsPDFs() and press "Run".
Change this text to below. your “\” is wrong character.
“\”
to
"\"
or
Application.PathSeparator
I'd like to create several new workbooks. The VBA code below runs fine with Excel 365 and 2010. BUT with Excel 2013 or 2016, it runs fine the first time (and create the files)... and on the second run, Excel crashes without any error message.
If I run it step by step, I see that it's the SaveAs line that causes the crash.
I tried to kill the file before saving, too. To use a timer...
I tried to repair Office, to rename a HKEY (Identities), I tried to run it on 2 different windows (7 or 10). Nothing helps :/
Sub ExtraireType()
Dim shVentes As Worksheet
Dim rngVentes As Range
Dim rngTypes As Range
Dim shNew As Worksheet
Dim wkbNew As Workbook
Dim strPath As String
Dim zaza As Range
Application.DisplayAlerts = False
Set shVentes = ThisWorkbook.Worksheets("Ventes")
Set rngVentes = shVentes.Range("A1").CurrentRegion
Set rngTypes = ThisWorkbook.Worksheets("Liste").Range("A2:A4")
strPath = ThisWorkbook.Path
For Each zaza In rngTypes
rngVentes.AutoFilter
rngVentes.AutoFilter field:=3, Criteria1:=zaza.Value
rngVentes.Copy
Set shNew = ThisWorkbook.Worksheets.Add
shNew.Paste
Application.CutCopyMode = False
shNew.Move
Set wkbNew = ActiveWorkbook
wkbNew.SaveAs strPath & "\Type" & zaza.Value & Format(Date, "yyyymmdd")
wkbNew.Close
Set shNew = Nothing
Set wkbNew = Nothing
Next zaza
Set rngVentes = Nothing
Set shVentes = Nothing
Set rngTypes = Nothing
Application.DisplayAlerts = False
End Sub
This code runs well with Excel 2010 or 2019/365. But I have to use it with 2013 or 2016 :(
What am I doing wrong? Thanks for any help !
I was having this problem as well and have found a workaround - use .SaveCopyAs instead.
In the below example, .SaveAs crashes Excel every second time if I've left the Excel spreadsheet open and deleted the resultant file, whilst .SaveCopyAs saves every time irrespective. The only difference between the two is that .SaveAs has more options for how to save whereas .SaveCopyAs's only option is the filename.
Private Sub SaveAsExcelFile(TempExcelFile As Workbook, _
NewFullFileName as string, _
Optional FileFormat As XlFileFormat = xlOpenXMLWorkbook, _
Optional CreateBackup As Boolean = False)
'
' created & last edited 2020-03-06 by Timothy Daniel Cox
'
' For this example it is assumed the new file name is valid and in .xlsx format
'
Dim NewFullFileName2 as string
NewFullFileName2 = Replace(NewFullFileName, ".xlsx", "2.xlsx")
Application.EnableEvents = False
TempExcelFile.SaveCopyAs Filename:=NewFullFileName 'doesn't crash here on 2nd run
TempExcelFile.SaveAs Filename:=NewFullFileName2, FileFormat:=FileFormat, _
CreateBackup:=False 'will crash here on 2nd run
Application.EnableEvents = true
End Sub
I still think there is a bug in Excel regarding the .SaveAs however:
There's a long thread at
https://chandoo.org/forum/threads/worksheet-save-as-to-new-workbook-crashes-excel-on-second-run.40136/#post-241024
which after meandering has an apparent resolution as linked but - having
downloaded the file to see what changes have been made - he only
appears to have changed the output directory and removed a
conflicting fileformat which was set. IMO it did not resolve the
issue.
There's another similar unsolved thread at https://www.reddit.com/r/excel/comments/58fqlg/my_vba_code_works_at_first_but_if_used_twice_in_a/ which has no useful answers.
The one of the reasons that your code crash (it crushed in my case, Excel 2016), might be because you didn't add file extension at the end of:
wkbNew.SaveAs strPath & "\Type" & zaza.Value & Format(Date, "yyyymmdd")
so it might be like:
wkbNew.SaveAs strPath & "\Type" & zaza.Value & Format(Date, "yyyymmdd") & ".xlsx"
Hope it helps.
I have inherited an excel program built in vba that generates a document in a worksheet to be printed into pdf.
My problem is that with the exact same inputs I can get two different documents. The main differences is the line spacing between cells. For one user there might be 2 words that appear on the last line of the cell leaving no space between the cells while for another user might have all their words appear on the previous line and now has a line space between the two cells.
I have tried manually adding line break at the end of the cells to try to make sure that all cells have some spacing between the two but this has now caused a few users to get double line spacing between their cells.
I'm a little lost as to what might be causing this. All my users are running the same version of excel and since this is still in the testing phase are using the exact same inputs. Also we are all part of the same organization and I believe our environments are almost identical ( did not set up so no guarantee )
How do I go about to make sure that when my vba sends the worksheet the be printed as a pdf that it comes out identical for all my users.
Function RDB_Create_PDF(Myvar As Object, FixedFilePathName As String, _
OverwriteIfFileExist As Boolean, OpenPDFAfterPublish As Boolean) As String
Dim FileFormatstr As String
Dim Fname As Variant
'Test to see if the Microsoft Create/Send add-in is installed.
If Dir(Environ("commonprogramfiles") & "\Microsoft Shared\OFFICE" _
& Format(Val(Application.Version), "00") & "\EXP_PDF.DLL") <> "" Then
If FixedFilePathName = "" Then
'Open the GetSaveAsFilename dialog to enter a file name for the PDF file.
FileFormatstr = "PDF Files (*.pdf), *.pdf"
Fname = Application.GetSaveAsFilename("", filefilter:=FileFormatstr, _
Title:="Create PDF")
'If you cancel this dialog, exit the function.
If Fname = False Then Exit Function
Else
Fname = FixedFilePathName
End If
'If OverwriteIfFileExist = False then test to see if the PDF
'already exists in the folder and exit the function if it does.
If OverwriteIfFileExist = False Then
If Dir(Fname) <> "" Then Exit Function
End If
'Now export the PDF file.
On Error Resume Next
Myvar.ExportAsFixedFormat _
Type:=xlTypePDF, _
Filename:=Fname, _
Quality:=xlQualityStandard, _
IncludeDocProperties:=True, _
IgnorePrintAreas:=False, _
OpenAfterPublish:=OpenPDFAfterPublish
On Error GoTo 0
'If the export is successful, return the file name.
If Dir(Fname) <> "" Then RDB_Create_PDF = Fname
End If
End Function
I recently updated to office 2016 and now my macro that i am using to select a range in excel, and then convert this range to PDF and automatically send an email, does not fully work.
Before when i used this macro, the filename was automatically filled in the SaveAs dialog box, but now it is empty. I do not understand why.
Does anyone else has a problem like this or know how to fix it?
Here is my code:
Function Skicka_projektunderlag_PDF(Myvar As Object, FixedFilePathName As String, _
OverwriteIfFileExist As Boolean, OpenPDFAfterPublish As Boolean) As String
Dim FileFormatstr As String
Dim Fname As Variant
Dim ws As Worksheet
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Set ws = Sheets("Partner_information")
Set ws1 = Sheets("Kundinformation")
Set ws2 = Sheets("Kalkyl")
If Dir(Environ("commonprogramfiles") & "\Microsoft Shared\OFFICE" _
& Format(Val(Application.Version), "00") & "\EXP_PDF.DLL") <> "" Then
If FixedFilePathName = "" Then
FileFormatstr = "PDF Files (*.pdf), *.pdf"
Fname = Application.GetSaveAsFilename(ws.Range("B1").Value & " - Projektunderlag " & ws2.Range("BF104").Value & " " & ws1.Range("B3").Value _
, FileFilter:=FileFormatstr, Title:="Create PDF")
If Fname = False Then Exit Function
Else
Fname = FixedFilePathName
End If
If OverwriteIfFileExist = False Then
If Dir(Fname) <> "" Then Exit Function
End If
On Error Resume Next
Myvar.ExportAsFixedFormat _
Type:=xlTypePDF, _
FileName:=Fname, _
Quality:=xlQualityStandard, _
IncludeDocProperties:=True, _
IgnorePrintAreas:=False, _
OpenAfterPublish:=OpenPDFAfterPublish
On Error GoTo 0
If Dir(Fname) <> "" Then Skicka_projektunderlag_PDF = Fname
End If
End Function
Best regards
AgatonSaxx
The following answer isn't refined but I have also been struggling with this problem in Word 2016 VBA to generate a default file name when Save As is selected in Word 2016
and wanted to share what I've found thus far as it is working with some success.
I was able to get the code semi-working again by adding an event handler.
Application.DocumentBeforeSave Event
example here https://msdn.microsoft.com/en-us/library/office/ff838299.aspx
tied to Using Events with Application Object
example here https://msdn.microsoft.com/en-us/library/office/ff821218.aspx
I moved my actual code to within the class module
Cancel=true
had to be added to the end of the code or the Save As dialog box would open twice.
This "solution" has some drawbacks that it only works once per document. So, if for some reason, you want to use SaveAs on the same document more than once, the name won't default. It also seems a bit clunky/limited for my taste but it is a start.
This "solution" is Word based but you should be able to do/ find something similar for Excel.
Hope this helps put you on the path to success. Apologies for not being a perfect answer. Just wanted to share lessons learned as maybe it will cut down on your time to a solution!
I have a Workbook with multiple sheets which I want to select and convert to a single PDF file.
I have written the following code which works fine and creates the file:
Sub Print_Project_Report_To_PDF
Dim FilePathandName As String
MyDate = Format(DateSerial(Year(Now), Month(Now) - 1, 1), "mmmm yyyy")
MyPath = ThisWorkbook.Path & "\"
MyFile = "Project Progress Report - " & MyDate & ".pdf"
FilePathandName = MyPath & MyFile
ThisWorkbook.Sheets(Array("PR_COVER_PAGE", "PR_SUMMARY", _
"PR_PROJECT_DETAILS", "PR_INTERNAL RESOURCES", "PR_TIME", _
"PR_REVENUE_FORECAST_SUMMARY", "PR_ORIGINAL_REVENUE_FORECAST", _
"PR_ACTUAL_REVENUE_FORECAST", "PR_COSTS", "PR_ISSUES", "MONTHLY FINANCIAL REPORT", _
"PG-SC_COVER_LETTER", "PG-SC_CLAIM_SUMMARY", "PG-SC_TRADE", "PG-SC_HYDRAULICS", _
"PG-SC_MECHANICAL", "PG-SC_MEDICAL_GASES", "PG-SC_ELECTRICAL", "PG-SC_VARIATION", _
"PG-SC_MONTHLY_CASHFLOW", "PG-MH_COVER_LETTER", "PG-MH_CLAIM_SUMMARY", _
"PG-MH_TRADE", "PG-MH_HYDRAULICS", "PG-MH_MECHANICAL", "PG-MH_MEDICAL_GASES", _
"PG-MH_ELECTRICAL", "PG-MH_VARIATION", "PG-MH_MONTHLY_CASHFLOW", "CLIENT_COVER", _
"CLIENT_SUMMARY", "CLIENT_ISSUES")).Select
ActiveSheet.ExportAsFixedFormat Type:=xlTypePDF, Filename:=FilePathandName, _
Quality:=xlQualityStandard, IncludeDocProperties:=True, _
IgnorePrintAreas:=False, OpenAfterPublish:=True
ThisWorkbook.Sheets("Dashboard").Select
End Sub
The problem is that the PDF file is not created with the sheets in order which I have specified in the array. They are in the order which they appear in the Workbook (Left to right). It correctly only includes the sheets I want but not in the order i want.
I dont want to change the order of the sheets in the Workbook either because it is setup in a specific, progressive way.
Can anyone help me with code which will allow me to be specific with the order of the sheets when the document is published?
Any help would be greatly appreciated.
I agree with #SiddharthRout in first idea/comment below the question. However, in quite similar situation when I print complicated PowerPoint presentation I use
PDFCreator application
At the first step I run that software and set 'stop printing' option. Than you could send to that software (in the way you print worksheet) each worksheet separately which would be separate document stacked in the list in the right order at the beginning. Using special feature you can match them into one document then and print it. It's very useful and quite reliable solution.
Here is some sample VBA code how copy the current workbook into a temp file and reorder a list of sheets. Use such a routine before printing:
Sub CopyAndReorder()
Dim wbCopy As Workbook
ThisWorkbook.SaveCopyAs "C:\TEMP\XXXX.XLS"
Set wbCopy = Workbooks.Open("C:\TEMP\XXXX.XLS")
ReorderSheets wbCopy
End Sub
Sub ReorderSheets(wb As Workbook)
Dim shNames As Variant, shName As Variant, sh As Worksheet
shNames = Array("Table3", "Table2", "Table1")
For Each shName In shNames
Set sh = wb.Sheets(shName)
sh.Move After:=wb.Sheets(wb.Sheets.Count)
Next
End Sub
(You have to adapt this code snippet to your needs, of course, use a better temp file name, delete the new file afterwards, provide the list of sheets from outside, etc, but I think you get the idea).