I have some code that I am working on with the macro recorder. In word it always begins with Selection. This article https://exceloffthegrid.com/controlling-word-from-excel-using-vba/?unapproved=9388&moderation-hash=83a9b85f06d7f960463f59103685510b#comment-9388 says I should be able to assign the document to a variable and just insert this before .Selection. However the selection method doesn't appear in VBE for me after I type my document variable. I get a run time error 438 'object doesn't support this property or method' on my first use of the word Selection object (Selection.EndKey). As far as I can see the GoTo method should select the start of the heading.
Sub ExcelToWord()
'
' Select data in excel and copy to GIR
'
'
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.Calculation = xlCalculationManual
Dim wb As Workbook
Dim ws As Worksheet
Dim wdApp As Word.Application
Dim GIR As Word.Document
Dim GIRName As String
Dim GEOL As String
Dim Tbl As Long
Set wdApp = New Word.Application '<<< Create a Word application object
wdApp.Visible = True '<<<< Open word so you can see any errors
GIRName = Application.GetOpenFilename(Title:="Please choose GIR to open", _
FileFilter:="Word Files *.docm* (*.docm*),")
Set GIR = wdApp.Documents.Open(GIRName) '<< call Documents.Open on the word app
'Loop through excel workbook to copy data
Set wb = ThisWorkbook
Set ws = ActiveSheet
For Each ws In wb.Worksheets
If UCase(ws.Name) <> "TEMPLATE" And ws.Visible = True Then
ws.Name = Replace(ws.Name, "(Blank)", "NoGEOLCode")
ws.Activate
GEOL = Range("C9").Value
Tbl = 1
Range("A14").Select
Range(Selection, Selection.End(xlToRight)).Select
Range(Selection, Selection.End(xlDown)).Select
Selection.Copy
'Paste each worksheet's data into word as new heading
GIR.Activate
GIR.Content.GoTo What:=wdGoToHeading, Which:=wdGoToFirst, Count:=5, Name:=""
Selection.EndKey Unit:=wdLine
Selection.TypeParagraph
Selection.Style = ActiveDocument.Styles("Heading 2")
Selection.TypeText Text:=GEOL
Selection.TypeParagraph
Selection.Tables.Add Range:=Selection.Range, NumRows:=53, NumColumns:=7, DefaultTableBehavior:=wdWord9TableBehavior, AutoFitBehavior:=wdAutoFitWindow
With Selection.Tables(Tbl)
If .Style <> "Table1" Then
.Style = "Table1"
End If
.ApplyStyleHeadingRows = True
.ApplyStyleLastRow = False
.ApplyStyleFirstColumn = True
.ApplyStyleLastColumn = False
.ApplyStyleRowBands = True
.ApplyStyleColumnBands = False
End With
Selection.PasteAndFormat (wdFormatPlainText)
Tbl = Tbl + 1
Selection.GoTo What:=wdGoToSection, Which:=wdGoToFirst, Count:=6, Name:=""
Selection.MoveUp Unit:=wdLine, Count:=1
Selection.TypeParagraph
End If
Next
GIR.Save
Application.EnableEvents = True
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub
There are several issues with your code.
It is bad practice to use the Selection object for various reasons. It is better to use Range instead, both in Excel and Word.
You set the variable GIR to the document you opened but then use ActiveDocument instead.
You add your table into a paragraph formatted with Heading 2 style. For table styles to work correctly the underlying paragraph style must be Normal. This is because there is a hierarchy of styles in Word with table styles at the bottom, just above document default which is represented by Normal.
You set the variable NewTbl to point to the table you created but make no further use of it.
The line With wdApp.Selection.Tables(Tbl) will error as there will only be one table in the Selection.
I have rewritten your code as below. I have left the final 3 lines of Word code unaltered as I am unsure exactly what you are doing there, a consequence of attempting to debug code without the document being worked on. I have tested this code using some dummy data and it works for me in O365.
Sub ExcelToWord()
'
' Select data in excel and copy to GIR
'
'
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.Calculation = xlCalculationManual
Dim wb As Workbook
Dim ws As Worksheet
Dim wdApp As Word.Application
Dim GIR As Word.Document
Dim GIRName As String
Dim GEOL As String
Dim Tbl As Long
Dim NewTbl As Word.Table
Dim wdRange As Word.Range
Set wdApp = New Word.Application '<<< Create a Word application object
wdApp.Visible = True '<<<< Open word so you can see any errors
GIRName = Application.GetOpenFilename(Title:="Please choose GIR to open", _
FileFilter:="Word Files *.docm* (*.docm*),")
Set GIR = wdApp.Documents.Open(GIRName) '<< call Documents.Open on the word app
'Loop through excel workbook to copy data
Set wb = ThisWorkbook
Set ws = ActiveSheet
For Each ws In wb.Worksheets
If UCase(ws.Name) <> "TEMPLATE" And ws.Visible = True Then
ws.Name = Replace(ws.Name, "(Blank)", "NoGEOLCode")
ws.Activate
GEOL = Range("C9").Value
Tbl = 1
Range("A14").Select
Range(Selection, Selection.End(xlToRight)).Select
Range(Selection, Selection.End(xlDown)).Select
Selection.Copy
'Paste each worksheet's data into word as new heading
Set wdRange = wdApp.Selection.GoTo(What:=wdGoToHeading, _
Which:=wdGoToFirst, Count:=4, Name:="")
With wdRange
' wdApp.Selection.EndKey Unit:=wdLine
' wdApp.Selection.TypeParagraph
.End = .Paragraphs(1).Range.End
.InsertParagraphAfter
.MoveStart wdParagraph
.MoveEnd wdCharacter, -1
' wdApp.Selection.Style = ActiveDocument.Styles("Heading 2")
.Style = GIR.Styles(wdStyleHeading2)
' wdApp.Selection.TypeText Text:=GEOL
.Text = GEOL
' wdApp.Selection.TypeParagraph
.InsertParagraphAfter
.Collapse wdCollapseEnd
.Style = GIR.Styles(wdStyleNormal)
Set NewTbl = GIR.Tables.Add(Range:=wdRange, NumRows:=53, _
NumColumns:=7, DefaultTableBehavior:=wdWord9TableBehavior, _
AutoFitBehavior:=wdAutoFitWindow)
' With wdApp.Selection.Tables(Tbl)
With NewTbl
If .Style <> "Table1" Then
.Style = "Table1"
End If
.ApplyStyleHeadingRows = True
.ApplyStyleLastRow = False
.ApplyStyleFirstColumn = True
.ApplyStyleLastColumn = False
.ApplyStyleRowBands = True
.ApplyStyleColumnBands = False
.Range.PasteAndFormat wdFormatPlainText
End With
' wdApp.Selection.PasteAndFormat (wdFormatPlainText)
' Tbl = Tbl + 1
wdApp.Selection.GoTo What:=wdGoToSection, Which:=wdGoToFirst, _
Count:=6, Name:=""
wdApp.Selection.MoveUp Unit:=wdLine, Count:=1
wdApp.Selection.TypeParagraph
End With
End If
Next
GIR.Save
Application.EnableEvents = True
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub
Related
I have a an Excel workbook with that creates a table and exports the table to MS word. My client now wants to also insert a drop down list into the last column of the word table. I cannot find any material on this. Can it be done? I would like to create a combobox and insert it into each cell in the "Interpretation" column. Can someone point me in the right direction or supply some sample code?
Current code:
Sub ExportToWord()
Dim ws As Worksheet
Dim wrdApp As Word.Application
Dim wrdDoc As Word.Document
Dim objRange As Word.Range
Dim bWeStartedWord As Boolean
Dim newDoc As Boolean, onSave As Boolean
Dim rng As Range
Dim lRow As Integer, s As Integer
If UF_Load.check_new = True Then
newDoc = True
Else
newDoc = False
End If
Set ws = ThisWorkbook.Sheets("UI")
On Error Resume Next
Set wrdApp = GetObject(, "Word.Application")
On Error GoTo 0
Application.ScreenUpdating = False
Application.EnableEvents = False
s = ws.Range("rng_demo").Row - 1
c = ws.Range("rng_demo").Column
lRow = ws.Cells(Rows.count, s).End(xlUp).Row
Set rng = ws.Range("A" & s).Resize(lRow, 8)
rng.Copy
If wrdApp Is Nothing Then
Set wrdApp = CreateObject("Word.Application")
bWeStartedWord = True
End If
'Handle if Word Application is not found
If Err.Number = 429 Then
MsgBox "Microsoft Word document could not be found, aborting", vbExclamtion, "Microsoft Word Error 429"
GoTo SafeExit:
End If
On Error GoTo 0
'Make MS Word Visible and Active
wrdApp.Visible = True
wrdApp.Activate
'
wrdApp.Visible = True
If newDoc = True Then
Set wrdDoc = wrdApp.Documents.Add 'create as new word document
'Copy table data to word doc
Set tbl = rng 'ThisWorkbook.Sheets("UI").Range("A4:H25")
tbl.Copy
'Paste Table into Word doc
wrdDoc.Paragraphs(1).Range.PasteExcelTable _
LinkedToExcel:=False, _
WordFormatting:=False, _
RTF:=False
'Autofit table to Word doc
Set wordtable = wrdDoc.Tables(1)
wordtable.AutoFitBehavior (wdAutoFitWindow)
Else
'or open an existing document
Set wrdDoc = wrdApp.Documents.Open(filepath) 'wrdApp.Documents.Open("C:\Users\Apache Paint\Desktop\Clients\Stephen Schmitz\TestDocument.docx")
'Copy table data to word doc
With wrdDoc
Set tbl1 = .Tables.Add(Range:=wrdDoc.Paragraphs.Last.Range, _
NumRows:=1, NumColumns:=8, _
AutoFitBehavior:=wdAutoFitWindow) 'autofit content 'DefaultTableBehavior:=wdWord9TableBehavior,
With tbl1
.PreferredWidthType = wdPreferredWidthPercent
.PreferredWidth = 100
End With
Set tbl = rng 'ThisWorkbook.Sheets("UI").Range("A4:H25")
tbl.Copy
Set objRange = wrdDoc.Content
With objRange
.Collapse Direction:=0 'wdCollapseEnd
.InsertAfter vbCrLf
.Collapse Direction:=0
.InsertBreak Type:=wdPageBreak
.Paste '<< paste the table
End With
'Autofit the document
Set wordtable = objRange.Tables(1)
wordtable.AutoFitBehavior (wdAutoFitWindow)
With wordtable
.PreferredWidthType = wdPreferredWidthPercent
.PreferredWidth = 100
End With
End With
filepath = ""
End If
SafeExit:
Application.ScreenUpdating = True
Application.EnableEvents = True
Application.CutCopyMode = False
End Sub
I was able to get it to work with the code below. Thanks to those who suggested I look into ContentControl.
Now I am intermittently getting 'Run-time error 462. The remote server machine does not exist or is unavailable.'
I will update the cooment back here when it is fully resolved.
'Copy table data to word doc
Set tbl = rng 'ThisWorkbook.Sheets("UI").Range("A4:H25")
tbl.Copy
'Paste Table into Word doc
wrdDoc.Paragraphs(1).Range.PasteExcelTable _
LinkedToExcel:=False, _
WordFormatting:=False, _
RTF:=False
'Autofit table to Word doc
Set Wordtable = wrdDoc.Tables(1)
Wordtable.AutoFitBehavior (wdAutoFitWindow)
Dim oRow As Row
'Dim oRng As Range
'Loop through last table column and add Combobox
With Wordtable
For Each oRow In Wordtable.Rows
'Set oRng = oRow.Cells(1).Range
If Len(oRow.Cells(7).Range.Text) > 11 Then
Set objCC = ActiveDocument.ContentControls.Add(wdContentControlDropdownList, oRow.Cells(8).Range)
objCC.Title = "Interpretation"
If objCC.ShowingPlaceholderText Then
objCC.SetPlaceholderText , , "-Select-"
objCC.DropdownListEntries.Add "Far Below Expectaions"
objCC.DropdownListEntries.Add "Below Expectaions"
objCC.DropdownListEntries.Add "Slightly Below Expectaions"
objCC.DropdownListEntries.Add "Significant Difference"
objCC.DropdownListEntries.Add "Valid"
objCC.DropdownListEntries.Add "WNL"
Debug.Print Len(oRow.Cells(7).Range.Text)
End If
Else
End If
Next
End With
Hello and thank you for your time, in the function code below, how do I make it in a way that it will function on any users computer, not just mine.
I know I need to probably use the Environ("USERPROFILE") thing but I don't know how to incorporate it in the code below.
Function Import_Data() As Boolean
Dim x As Workbook
Dim targetWorkbook As Workbook
Dim xWs As Worksheet
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Const F_PATH As String = "C:\Users\mohammad.reza\Desktop\MyFiles.xls"
'if no file then exit and return false
If Dir(F_PATH) = "" Then
MsgBox "My Files is not found on your Desktop"
Import_Data = False
Exit Function
End If
'If the file exists than load the file and continue
Import_Data = True
' This part delets all sheets except the summary tab
For Each xWs In Application.ActiveWorkbook.Worksheets
If xWs.Name <> "Summary" Then
xWs.Delete
End If
Next
' This part will get the raw data from the downloaded file on the desktop
Set x = Workbooks.Open("C:\Users\mohammad.reza\Desktop\MyFiles.xls")
Set targetWorkbook = Application.ActiveWorkbook
' This part will copy the sheet into this workbook
With x.Sheets("MyFiles").UsedRange
ThisWorkbook.Sheets.Add(After:=Sheets(Sheets.Count)).Range("A1").Resize( _
.Rows.Count, .Columns.Count) = .Value
End With
x.Close
' This part will rename the sheet and move it to the end
ActiveSheet.Name = "RAW DATA"
ActiveSheet.Move After:=Worksheets(Worksheets.Count)
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Function
Thank you brad for your answer, however when I use it, it gives the below error:
Try this ...
Function Import_Data() As Boolean
Dim x As Workbook
Dim targetWorkbook As Workbook
Dim xWs As Worksheet
Dim sPath As String
Application.ScreenUpdating = False
Application.DisplayAlerts = False
sPath = Environ("USERPROFILE") & "\Desktop\MyFiles.xls"
'if no file then exit and return false
If Dir(sPath) = "" Then
MsgBox "My Files is not found on your Desktop"
Import_Data = False
Exit Function
End If
'If the file exists than load the file and continue
Import_Data = True
' This part delets all sheets except the summary tab
For Each xWs In Application.ActiveWorkbook.Worksheets
If xWs.Name <> "Summary" Then
xWs.Delete
End If
Next
' This part will get the raw data from the downloaded file on the desktop
Set x = Workbooks.Open(sPath)
Set targetWorkbook = Application.ActiveWorkbook
' This part will copy the sheet into this workbook
With x.Sheets("MyFiles").UsedRange
ThisWorkbook.Sheets.Add(After:=Sheets(Sheets.Count)).Range("A1").Resize( _
.Rows.Count, .Columns.Count) = .Value
End With
x.Close
' This part will rename the sheet and move it to the end
ActiveSheet.Name = "RAW DATA"
ActiveSheet.Move After:=Worksheets(Worksheets.Count)
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Function
I'm trying to create a code that reads a dynamic Excel table into an existing Word document and changes some variables in the document (for example %Username%)
The code below gives me an "Locked for editing" error by myself, but that isn't the case.
Can someone see what I have to change in the code?
The code is:
Sub Export_Table_Word()
'Word objects.
Dim wdApp As Word.Application
Dim wdDoc As Word.Document
Dim wdbmRange As Word.Range
'Excel objects.
Dim wbBook As Workbook
Dim wsSheet As Worksheet
Dim rnReport As Range
'Path of Word Template
Dim stPathTemplate As String
Dim stPathSave As String
'Dynamic Replace variables
Dim UserName As String
Dim StrFind
Dim StrRepl As String
'Loop variable
Dim i As Long
Dim msWord As Object
Set msWord = CreateObject("Word.Application")
'Define replacement variables
UserName = Application.UserName
sFirst = Split(UserName, " ")(0) 'Firstname 'sFirst = Split(UserName, ",")(1) 'Firstname
sLast = Split(UserName, " ")(1) 'Lastname
sUserName = Left(sFirst, 1) & sLast 'First letter of firstname and lastname
sFullName = sFirst & " " & sLast 'Full name
StrFind = "%User_Name%,%Full_name%, %Date%" 'Strings to be replaced in the word document
StrRepl = sUserName & "*" & sFullName & "*" & " " & Date 'Replaced by
'Initialize Path word template
stPathTemplate = "C:\Users\xxx\Desktop\VBA_TEST\VBA_Automation.docx"
stPathSave = "C:\Users\xxx\Desktop\VBA_TEST\Finished.docx"
'Initialize the Excel objects.
Set wbBook = ThisWorkbook
Set wsSheet = wbBook.Worksheets(1)
Set rnReport = wsSheet.Range("D2:D7")
'Initialize the Word objets.
Set wdApp = New Word.Application
Set wdDoc = wdApp.Documents.Open(stPathTemplate)
Set wdbmRange = wdDoc.Bookmarks("Report").Range
'If the macro has been run before, clean up any artifacts before trying to paste the table in again.
On Error Resume Next
With wdDoc.InlineShapes(1)
.Select
.Delete
End With
On Error GoTo 0
'Turn off screen updating.
Application.ScreenUpdating = True
With wdDoc
.Visible = True
.Documents.Open (stPathTemplate)
.Activate
With .ActiveDocument.Content.Find
.ClearFormatting
.Replacement.ClearFormatting
For i = 0 To UBound(Split(StrFind, ",")) 'Loop to replace all the defined dynamic strings
.Text = Split(StrFind, ",")(i)
.Replacement.Text = Split(StrRepl, "*")(i)
.Execute Replace:=wdReplaceAll
Next i
.Forward = True
.Wrap = 1 'FindContinue
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.Execute Replace:=2 'wdReplaceAll (WdReplace Enumeration)
End With
End With
'Copy the report to the clipboard.
rnReport.Copy
'Select the range defined by the "Report" bookmark and paste in the report from clipboard.
With wdbmRange
.Select
.Paste
End With
'Save and close the Word doc.
With wdDoc
'.Save
.SaveAs2 Filename:=stPathSave, _
FileFormat:=wdFormatXMLDocument, AddToRecentFiles:=False
.Close
End With
'Quit Word.
wdApp.Quit
'Null out your variables.
Set wdbmRange = Nothing
Set wdDoc = Nothing
Set wdApp = Nothing
'Clear out the clipboard, and turn screen updating back on.
With Application
.CutCopyMode = False
.ScreenUpdating = True
End With
MsgBox ("Done")
End Sub
Everything in this code works fine, except at the very end when I go to close the workbook that I am performing some operations on. I'm inserting some code into ThisWorkbook of the workbook that I'm opening from a text file and also copying a few tabs in my master spreadsheet to each workbook that I open in this loop. At the end of the loop it crashes when I try to close and move on to the next workbook.
Sub AddSht_AddCode()
Dim wb As Workbook
Dim xPro As VBIDE.VBProject
Dim xCom As Variant
Dim xMod As VBIDE.CodeModule
Dim xLine As Long
Dim strFolderPath As String
Dim strFolderPathTo As String
Dim strCodePath As String
Dim objFSO As Object
Dim objFolder As Object
Dim objFile As Object
Dim mergearea As Range
Dim c As Range
Application.ScreenUpdating = False
Application.DisplayAlerts = False
strFolderPath = Sheets("Master - DO NOT MOVE").Range("B2").Value
strCodePath = Sheets("Master - DO NOT MOVE").Range("b18").Value
If IsNull(strFolderPath) Or strFolderPath = "" Then
MsgBox "Please make sure you have a valid DFF path entered in Cell B2 on the Master worksheet.", vbOKOnly
Exit Sub
End If
Set objFSO = CreateObject("Scripting.FileSystemObject")
If Dir(strFolderPath, vbDirectory) = "" Then
MsgBox "The DFF folder path entered is not a valid path. Please edit and try again.", vbOKOnly
Exit Sub
Else
Set objFolder = objFSO.GetFolder(strFolderPath)
End If
'create_projid_array
'create_projid_new
For Each objFile In objFolder.Files
'If (InStr(objFile.Name, ".xlsm") > 0 Or InStr(objFile.Name, ".xlsx") > 0) And check_var_array(Left(objFile.Name, InStr(1, objFile.Name, ".") - 1), projarray) = 1 Then
'If (InStr(objFile.Name, ".xlsx") > 0 Or InStr(objFile.Name, ".xlsb") > 0) And check_var_array(Left(objFile.Name, InStr(1, objFile.Name, ".") - 1), projarray) = 1 Then
If (InStr(objFile.Name, ".xlsm") > 0) Then
'If check_var_array(objFile.Name, projarray) = 1 Then
Application.AutomationSecurity = msoAutomationSecurityLow
Set wb = Workbooks.Open(objFile, False)
'Application.AutomationSecurity = msoAutomationSecurityByUI
Workbooks("DFFPHI_w_QAQC.xlsm").Activate
If Right(objFile.Name, 5) = ".xlsx" Then
Sheets(Array("Template", "Log")).Copy After:=wb.Sheets(1)
If Sheets("Master - DO NOT MOVE").Range("B4") = True Then
wb.Activate
wb.Sheets("Data").UsedRange.Clear
wb.Sheets("Data").Range("A1").Value = 0
Workbooks("DFFPHI_w_QAQC.xlsm").Sheets("Data").Range("B1:BO2400").Copy Destination:=wb.Sheets("Data").Range("B1")
End If
End If
wb.Activate
wb.Sheets(1).Visible = xlSheetVisible
wb.Sheets(1).Unprotect Password:="xxxxxxxxx"
Set mergearea = wb.Sheets(1).Range("i5:l6")
For Each c In mergearea
If c.MergeCells Then
c.UnMerge
End If
Next
wb.Sheets(1).Range("J5").ClearContents
wb.Sheets(1).Range("j6").ClearContents
'Selection.UnMerge
'Selection.ClearContents
If Right(objFile.Name, 5) = ".xlsm" Then
wb.Sheets("Template").Visible = xlSheetVisible
wb.Sheets("Data").Visible = xlSheetVisible
Workbooks("DFFPHI_w_QAQC.xlsm").Activate
If Sheets("Master - DO NOT MOVE").Range("B4") = True Then
wb.Activate
wb.Sheets("Data").UsedRange.Clear
wb.Sheets("Data").Range("A1").Value = 0
Workbooks("DFFPHI_w_QAQC.xlsm").Sheets("Data").Range("B1:BO2400").Copy Destination:=wb.Sheets("Data").Range("B1")
End If
Workbooks("DFFPHI_w_QAQC.xlsm").Activate
If Sheets("Master - DO NOT MOVE").Range("B6") = True Then
wb.Activate
wb.Sheets("Template").UsedRange.Clear
Workbooks("DFFPHI_w_QAQC.xlsm").Sheets("Template").Range("A1:G524").Copy Destination:=wb.Sheets("Template").Range("A1")
If Left(wb.Sheets(1).Range("I7"), 3) = "PO " Or Left(wb.Sheets(1).Range("I7"), 3) = "PO#" Then
wb.Sheets(1).Range("I7").Copy Destination:=wb.Sheets("Template").Range("F3")
End If
End If
End If
wb.Activate
Call update_dropdowns
Call update_ga_formula(wb.Name)
wb.Sheets(Array("Template", "Data")).Select
ActiveWindow.SelectedSheets.Visible = False
wb.Activate
With wb
Set xPro = .VBProject
Set xCom = xPro.VBComponents("ThisWorkbook")
Set xMod = xCom.CodeModule
xMod.DeleteLines 1, _
xMod.CountOfLines
xMod.AddFromFile strCodePath
End With
wb.Activate
With wb.Sheets(1)
.Protect Password:="xxxxxxx", UserInterfaceOnly:=True, AllowFormattingCells:=True, AllowFormattingColumns:=True, AllowFormattingRows:=True, DrawingObjects:=False, Contents:=True, Scenarios:=True, AllowFiltering:=True
.EnableOutlining = True
End With
wb.Save
wb.Close <<<<<EXCEL CRASHES HERE>>>>>>>
End If
Next
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub
Just to finalize:
In my specific situation I was adding a BeforeClose Event to the target workbook ThisWorkbook object. In the code that is performing this operation, it was crashing after the BeforeClose code was inserted in the target workbook and upon having the source code try to close the workbook with wb.Close.
I changed:
wb.Close
to
Application.EnableEvents = False
wb.Close
Application.EnableEvents = True
So, bypassed the target workbook events altogether and it's fixed.
Check the code in the wb close / save events for any invalid actions:
BeforeClose()
BeforeSave()
SheetDeactivate()
WindowDeactivate(), etc
Not related, but remove the .Activate statements and qualify the objects if needed
For example:
Workbooks("DFFPHI_w_QAQC.xlsm").Activate
If Sheets("Master - DO NOT MOVE").Range("B4") = True Then
should be replaced with
If Workbooks("DFFPHI_w_QAQC.xlsm").Sheets("Master - DO NOT MOVE").Range("B4") = True Then
Statements .Select and .Activate are not needed and have poor performance
I wrote this VBA code to generate a report from data in an Access table and dump it into Excel with user friendly formatting.
The code works great the first time. But if I run the code again while the first generated Excel sheet is open, one of my subroutines affects the first workbook instead of the newly generated one.
Why? How can I fix this?
I think the issue is where I pass my worksheet and recordset to the subroutine called GetHeaders that prints the columns, but I'm not sure.
Sub testROWReport()
DoCmd.Hourglass True
'local declarations
Dim strSQL As String
Dim rs1 As Recordset
'excel assests
Dim xlapp As excel.Application
Dim wb1 As Workbook
Dim ws1 As Worksheet
Dim tempWS As Worksheet
'report workbook dimentions
Dim intColumnCounter As Integer
Dim lngRowCounter As Long
'initialize SQL container
strSQL = ""
'BEGIN: construct SQL statement {
--this is a bunch of code that makes the SQL Statement
'END: SQL construction}
'Debug.Print (strSQL) '***DEBUG***
Set rs1 = CurrentDb.OpenRecordset(strSQL)
'BEGIN: excel export {
Set xlapp = CreateObject("Excel.Application")
xlapp.Visible = False
xlapp.ScreenUpdating = False
xlapp.DisplayAlerts = False
'xlapp.Visible = True '***DEBUG***
'xlapp.ScreenUpdating = True '***DEBUG***
'xlapp.DisplayAlerts = True '***DEBUG***
Set wb1 = xlapp.Workbooks.Add
wb1.Activate
Set ws1 = wb1.Sheets(1)
xlapp.Calculation = xlCalculationManual
'xlapp.Calculation = xlCalculationAutomatic '***DEBUG***
'BEGIN: Construct Report
ws1.Cells.Borders.Color = vbWhite
Call GetHeaders(ws1, rs1) 'Pastes and formats headers
ws1.Range("A2").CopyFromRecordset rs1 'Inserts query data
Call FreezePaneFormatting(xlapp, ws1, 1) 'autofit formatting, freezing 1 row,0 columns
ws1.Name = "ROW Extract"
'Special Formating
'Add borders
'Header background to LaSenza Pink
'Fix Comment column width
'Wrap Comment text
'grey out blank columns
'END: Report Construction
'release assets
xlapp.ScreenUpdating = True
xlapp.DisplayAlerts = True
xlapp.Calculation = xlCalculationAutomatic
xlapp.Visible = True
Set wb1 = Nothing
Set ws1 = Nothing
Set xlapp = Nothing
DoCmd.Hourglass False
'END: excel export}
End Sub
Sub GetHeaders(ws As Worksheet, rs As Recordset, Optional startCell As Range)
ws.Activate 'this is to ensure selection can occur w/o error
If startCell Is Nothing Then
Set startCell = ws.Range("A1")
End If
'Paste column headers into columns starting at the startCell
For i = 0 To rs.Fields.Count - 1
startCell.Offset(0, i).Select
Selection.Value = rs.Fields(i).Name
Next
'Format Bold Text
ws.Range(startCell, startCell.Offset(0, rs.Fields.Count)).Font.Bold = True
End Sub
Sub FreezePaneFormatting(xlapp As excel.Application, ws As Worksheet, Optional lngRowFreeze As Long = 0, Optional lngColumnFreeze As Long = 0)
Cells.WrapText = False
Columns.AutoFit
ws.Activate
With xlapp.ActiveWindow
.SplitColumn = lngColumnFreeze
.SplitRow = lngRowFreeze
End With
xlapp.ActiveWindow.FreezePanes = True
End Sub
When Cells and Columns are used alone, they refer to ActiveSheet.Cells and ActiveSheet.Columns.
Try to prefix them with the targeted sheet:
Sub FreezePaneFormatting(xlapp As Excel.Application, ws As Worksheet, Optional lngRowFreeze As Long = 0, Optional lngColumnFreeze As Long = 0)
ws.Cells.WrapText = False
ws.Columns.AutoFit
...
End Sub
Okay, I figured out the issue here. I guess I can't use the ".Select" or "Selection." when I'm working with an invisible, non updating workbook. I found that when I changed some code from automated selecting to simply directly changing the value of cells, it worked out.
OLD:
startCell.Offset(0, i).Select
Selection.Value = rs.Fields(i).Name
NEW:
ws.Cells(startCell.Row, startCell.Column).Offset(0, i).Value = rs.Fields(i).Name