View Single Post
 
Old 02-03-2021, 11:15 PM
mbcohn mbcohn is offline Windows 10 Office 2016
Advanced Beginner
 
Join Date: Jan 2021
Posts: 32
mbcohn is on a distinguished road
Default search and replace, save, convert to PDF, recursively

So, I have a bunch of nested folders full of Word files.
My goal here is to loop through all the folders, go to each Word file, do a search and replace operation, save the word file, then export a PDF version of that Word file, then move on.


To attempt this, I have cobbled together some answers that I got on this forum to previous questions. But when I run the code, it just hangs, and I have to 'end task' on Word (and it doesn't actually process any documents, as far as I can tell.) What am I doing wrong?



Code:
 Option Explicit
Dim FSO As Object, oFolder As Object, StrFolds As String
 
Sub RecursiveDocuments()
' This recursively goes through a tree of folders
' and does something
Application.ScreenUpdating = False
Dim TopLevelFolder As String
Dim TheFolders As Variant, aFolder As Variant
Dim strFile As String, i As Long
TopLevelFolder = GetFolder
StrFolds = vbCr & TopLevelFolder
If TopLevelFolder = "" Then Exit Sub
If FSO Is Nothing Then
  Set FSO = CreateObject("Scripting.FileSystemObject")
End If
'Get the sub-folder structure
Set TheFolders = FSO.GetFolder(TopLevelFolder).SubFolders
For Each aFolder In TheFolders
  RecurseWriteFolderName (aFolder)
Next
'Process the documents in each folder
For i = 1 To UBound(Split(StrFolds, vbCr))
strFile = Dir(CStr(Split(StrFolds, vbCr)(i)) & "\*.doc", vbNormal)
Do While strFile <> ""

batchSpecsUpdate

Loop
Next
Application.ScreenUpdating = True
End Sub
 
Sub RecurseWriteFolderName(aFolder)
Dim SubFolders As Variant, SubFolder As Variant
Set SubFolders = FSO.GetFolder(aFolder).SubFolders
StrFolds = StrFolds & vbCr & CStr(aFolder)
On Error Resume Next
For Each SubFolder In SubFolders
  RecurseWriteFolderName (SubFolder)
Next
End Sub
 
Function GetFolder() As String
Dim oFolder As Object
GetFolder = ""
Set oFolder = CreateObject("Shell.Application").BrowseForFolder(0, "Choose a folder", 0)
If (Not oFolder Is Nothing) Then GetFolder = oFolder.Items.Item.Path
Set oFolder = Nothing
End Function

Sub specsUpdate()
'
' specsUpdate Macro
'
'


    If ActiveWindow.View.SplitSpecial <> wdPaneNone Then
        ActiveWindow.Panes(2).Close
    End If
    If ActiveWindow.ActivePane.View.Type = wdNormalView Or ActiveWindow. _
        ActivePane.View.Type = wdOutlineView Then
        ActiveWindow.ActivePane.View.Type = wdPrintView
    End If
    ActiveWindow.ActivePane.View.SeekView = wdSeekCurrentPageHeader
    Selection.Find.ClearFormatting
    Selection.Find.Replacement.ClearFormatting
    With Selection.Find
        .Text = "REVISION A"
        .Replacement.Text = "REVISION B"
        .Forward = True
        .Wrap = wdFindContinue
        .Format = False
        .MatchCase = False
        .MatchWholeWord = False
        .MatchWildcards = False
        .MatchSoundsLike = False
        .MatchAllWordForms = False
    End With
    Selection.Find.Execute Replace:=wdReplaceAll
    With Selection.Find
        .Text = "1 APRIL 1776"
        .Replacement.Text = "31 DECEMBER 1492"
        .Forward = True
        .Wrap = wdFindContinue
        .Format = False
        .MatchCase = False
        .MatchWholeWord = False
        .MatchWildcards = False
        .MatchSoundsLike = False
        .MatchAllWordForms = False
    End With
    Selection.Find.Execute Replace:=wdReplaceAll
End Sub

Sub batchSpecsUpdate()



 'Written by Richard V. Michaels, Office Apps and Services MVP
    'http://www.greatcirclelearning.com
    'Browse for files to update
    Dim i As Integer, selFiles() As String
    Dim strFolderPath As String, Sep As String
    Sep = Application.PathSeparator
    Erase selFiles
    #If Mac Then
        Dim iPath As String, iScript As String, iFiles As String
        Dim iSplit As Variant, N As Long, FileFormat As String
        FileFormat = "{""org.openxmlformats.wordprocessingml.document"",""com.microsoft.word.doc""," & _
            """org.openxmlformats.wordprocessingml.document.macroenabled""}"
        On Error Resume Next
        iPath = MacScript("return (path to documents folder) as String")
        If Application.Version < 15 Then
            'Mac Office 2011
            iScript = "set applescript's text item delimiters to {ASCII character 10} " & vbNewLine & _
                "set theFiles to (choose file of type" & _
                " " & FileFormat & " " & _
                "with prompt ""Select the files to update"" default location alias """ & _
                iPath & """ with multiple selections allowed) as string" & vbNewLine & _
                "set applescript's text item delimiters to """" " & vbNewLine & _
                "return theFiles"
        Else
            'Mac Office 2016
            iScript = "set theFiles to (choose file of type" & _
                " " & FileFormat & " " & _
                "with prompt ""Select the files to update"" default location alias """ & _
                iPath & """ with multiple selections allowed)" & vbNewLine & _
                "set thePOSIXFiles to {}" & vbNewLine & _
                "repeat with aFile in theFiles" & vbNewLine & _
                "set end of thePOSIXFiles to POSIX path of aFile" & vbNewLine & _
                "end repeat" & vbNewLine & _
                "set {TID, text item delimiters} to {text item delimiters, ASCII character 10}" & vbNewLine & _
                "set thePOSIXFiles to thePOSIXFiles as text" & vbNewLine & _
                "set text item delimiters to TID" & vbNewLine & _
                "return thePOSIXFiles"
        End If
        iFiles = MacScript(iScript)
        On Error GoTo 0
        If iFiles <> "" Then
            iSplit = Split(iFiles, Chr(10))
            ReDim Preserve selFiles(UBound(iSplit))
            strFolderPath = Left(iSplit(0), InStrRev(iSplit(0), Sep))
            For N = LBound(iSplit) To UBound(iSplit)
                selFiles(N) = iSplit(N)
            Next N
        Else
            Exit Sub
        End If
    #Else
        'Windows Office 2016, 2013, 2010, 2007
        With Application.FileDialog(msoFileDialogFilePicker)
            .Title = "Select the files to update"
            .InitialFileName = CurDir
            .AllowMultiSelect = True
            .Filters.Clear
            .Filters.Add "All Word Files", "*.docx; *.docm; *.doc", 1
            If .Show = 0 Then
                Exit Sub
            End If
            ReDim Preserve selFiles(.SelectedItems.Count - 1)
            strFolderPath = Left(.SelectedItems(1), InStrRev(.SelectedItems(1), Sep))
            For i = 0 To .SelectedItems.Count - 1
                selFiles(i) = .SelectedItems(i + 1)
            Next
            .Filters.Clear
        End With
    #End If

    Dim doc As Word.Document, FirstTime As Boolean

    FirstTime = True
    On Error GoTo errHandler

    For i = 0 To UBound(selFiles)
        'The following is setup to perform a conditional first time check
        'Depending on your exact requirements, you may not need it.
        If FirstTime = True Then
            Set doc = Documents.Open(FileName:=selFiles(i))

            'This is where you will insert your code for applying the edits
            'you want to perform
            specsUpdate
            Word_ExportPDF

            doc.Save
            
            
            
            DoEvents
            FirstTime = False
        Else
            On Error GoTo 0
            Set doc = Documents.Open(FileName:=selFiles(i))

            'This is where you will insert your code for replicating the edits
            'you made to the first document
            specsUpdate
            Word_ExportPDF


            doc.Close Word.WdSaveOptions.wdSaveChanges
            DoEvents
        End If
    Next

    MsgBox "Update Complete. Your original document remains open.", vbInformation, "Success"
errHandler:
    If Err.Number <> 0 Then
        MsgBox Err.Description, vbExclamation, "Uh-Oh!"
    End If
End Sub

Sub Word_ExportPDF()
'PURPOSE: Generate A PDF Document From Current Word Document
'NOTES: PDF Will Be Saved To Same Folder As Word Document File
'SOURCE: www.TheSpreadsheetGuru.com/the-code-vault

Dim CurrentFolder As String
Dim FileName As String
Dim myPath As String
Dim UniqueName As Boolean

UniqueName = False

'Store Information About Word File
  myPath = ActiveDocument.FullName
  CurrentFolder = ActiveDocument.Path & "\"
  FileName = Mid(myPath, InStrRev(myPath, "\") + 1, _
   InStrRev(myPath, ".") - InStrRev(myPath, "\") - 1)

'Does File Already Exist?
'If so, too bad
'  Do While UniqueName = False
 '   DirFile = CurrentFolder & FileName & ".pdf"
  '  If Len(Dir(DirFile)) <> 0 Then
   '   UserAnswer = MsgBox("File Already Exists! Click " & _
    '   "[Yes] to override. Click [No] to Rename.", vbYesNoCancel)
      
     ' If UserAnswer = vbYes Then
        UniqueName = True
 '     ElseIf UserAnswer = vbNo Then
 '       Do
 '         'Retrieve New File Name
 '           FileName = InputBox("Provide New File Name " & _
 '            "(will ask again if you provide an invalid file name)", _
 '            "Enter File Name", FileName)
          
          'Exit if User Wants To
  '          If FileName = "False" Or FileName = "" Then Exit Sub
  '      Loop While ValidFileName(FileName) = False
  '    Else
   '     Exit Sub 'Cancel
   '   End If
   ' Else
   '   UniqueName = True
   ' End If
'  Loop
  
'Save As PDF Document
  On Error GoTo ProblemSaving
    ActiveDocument.ExportAsFixedFormat _
     OutputFileName:=CurrentFolder & FileName & ".pdf", _
     ExportFormat:=wdExportFormatPDF
  On Error GoTo 0

'Confirm Save To User
  With ActiveDocument
    FolderName = Mid(.Path, InStrRev(.Path, "\") + 1, Len(.Path) - InStrRev(.Path, "\"))
  End With
  
 ' MsgBox "PDF Saved in the Folder: " & FolderName

Exit Sub

'Error Handlers
ProblemSaving:
  MsgBox "There was a problem saving your PDF. This is most commonly caused" & _
   " by the original PDF file already being open."
  Exit Sub

End Sub

Function ValidFileName(FileName As String) As Boolean
'PURPOSE: Determine If A Given Word Document File Name Is Valid
'SOURCE: www.TheSpreadsheetGuru.com/the-code-vault

Dim TempPath As String
Dim doc As Document

'Determine Folder Where Temporary Files Are Stored
  TempPath = Environ("TEMP")

'Create a Temporary XLS file (XLS in case there are macros)
  On Error GoTo InvalidFileName
    Set doc = ActiveDocument.SaveAs2(ActiveDocument.TempPath & _
     "\" & FileName & ".doc", wdFormatDocument)
  On Error Resume Next

'Delete Temp File
  Kill doc.FullName

'File Name is Valid
  ValidFileName = True

Exit Function

'ERROR HANDLERS
InvalidFileName:
'File Name is Invalid
  ValidFileName = False

End Function

Sub UpdateDocuments()
' This accepts changes on all files in a directory.
Application.ScreenUpdating = False
Dim strFolder As String, strFile As String, strDocNm As String, wdDoc As Document, Rng As Range
strDocNm = ActiveDocument.FullName
strFolder = GetFolder
If strFolder = "" Then Exit Sub
strFile = Dir(strFolder & "\*.doc", vbNormal)
While strFile <> ""
  If strFolder & "\" & strFile <> strDocNm Then
    Set wdDoc = Documents.Open(FileName:=strFolder & "\" & strFile, AddToRecentFiles:=False, Visible:=False)
    With wdDoc
      For Each Rng In .StoryRanges
        Rng.Revisions.AcceptAll
      Next
      .Close SaveChanges:=True
    End With
  End If
  strFile = Dir()
Wend
Set wdDoc = Nothing
Application.ScreenUpdating = True
End Sub

'Function GetFolder() As String
'Dim oFolder As Object
' GetFolder = ""
'Set oFolder = CreateObject("Shell.Application").BrowseForFolder(0, "Choose a folder", 0)
'If (Not oFolder Is Nothing) Then GetFolder = oFolder.Items.Item.Path
'Set oFolder = Nothing
'End Function

Sub batchWordToPDF()



 'Written by Richard V. Michaels, Office Apps and Services MVP
    'http://www.greatcirclelearning.com
    'Browse for files to update
    Dim i As Integer, selFiles() As String
    Dim strFolderPath As String, Sep As String
    Sep = Application.PathSeparator
    Erase selFiles
    #If Mac Then
        Dim iPath As String, iScript As String, iFiles As String
        Dim iSplit As Variant, N As Long, FileFormat As String
        FileFormat = "{""org.openxmlformats.wordprocessingml.document"",""com.microsoft.word.doc""," & _
            """org.openxmlformats.wordprocessingml.document.macroenabled""}"
        On Error Resume Next
        iPath = MacScript("return (path to documents folder) as String")
        If Application.Version < 15 Then
            'Mac Office 2011
            iScript = "set applescript's text item delimiters to {ASCII character 10} " & vbNewLine & _
                "set theFiles to (choose file of type" & _
                " " & FileFormat & " " & _
                "with prompt ""Select the files to update"" default location alias """ & _
                iPath & """ with multiple selections allowed) as string" & vbNewLine & _
                "set applescript's text item delimiters to """" " & vbNewLine & _
                "return theFiles"
        Else
            'Mac Office 2016
            iScript = "set theFiles to (choose file of type" & _
                " " & FileFormat & " " & _
                "with prompt ""Select the files to update"" default location alias """ & _
                iPath & """ with multiple selections allowed)" & vbNewLine & _
                "set thePOSIXFiles to {}" & vbNewLine & _
                "repeat with aFile in theFiles" & vbNewLine & _
                "set end of thePOSIXFiles to POSIX path of aFile" & vbNewLine & _
                "end repeat" & vbNewLine & _
                "set {TID, text item delimiters} to {text item delimiters, ASCII character 10}" & vbNewLine & _
                "set thePOSIXFiles to thePOSIXFiles as text" & vbNewLine & _
                "set text item delimiters to TID" & vbNewLine & _
                "return thePOSIXFiles"
        End If
        iFiles = MacScript(iScript)
        On Error GoTo 0
        If iFiles <> "" Then
            iSplit = Split(iFiles, Chr(10))
            ReDim Preserve selFiles(UBound(iSplit))
            strFolderPath = Left(iSplit(0), InStrRev(iSplit(0), Sep))
            For N = LBound(iSplit) To UBound(iSplit)
                selFiles(N) = iSplit(N)
            Next N
        Else
            Exit Sub
        End If
    #Else
        'Windows Office 2016, 2013, 2010, 2007
        With Application.FileDialog(msoFileDialogFilePicker)
            .Title = "Select the files to update"
            .InitialFileName = CurDir
            .AllowMultiSelect = True
            .Filters.Clear
            .Filters.Add "All Word Files", "*.docx; *.docm; *.doc", 1
            If .Show = 0 Then
                Exit Sub
            End If
            ReDim Preserve selFiles(.SelectedItems.Count - 1)
            strFolderPath = Left(.SelectedItems(1), InStrRev(.SelectedItems(1), Sep))
            For i = 0 To .SelectedItems.Count - 1
                selFiles(i) = .SelectedItems(i + 1)
            Next
            .Filters.Clear
        End With
    #End If

    Dim doc As Word.Document, FirstTime As Boolean

    FirstTime = True
    On Error GoTo errHandler

    For i = 0 To UBound(selFiles)
        'The following is setup to perform a conditional first time check
        'Depending on your exact requirements, you may not need it.
        If FirstTime = True Then
            Set doc = Documents.Open(FileName:=selFiles(i))

            'This is where you will insert your code for applying the edits
            'you want to perform

            Word_ExportPDF

            doc.Save
            
            
            
            DoEvents
            FirstTime = False
        Else
            On Error GoTo 0
            Set doc = Documents.Open(FileName:=selFiles(i))

            'This is where you will insert your code for replicating the edits
            'you made to the first document
            specsUpdate
            Word_ExportPDF


            doc.Close Word.WdSaveOptions.wdSaveChanges
            DoEvents
        End If
    Next

    MsgBox "Update Complete. Your original document remains open.", vbInformation, "Success"
errHandler:
    If Err.Number <> 0 Then
        MsgBox Err.Description, vbExclamation, "Uh-Oh!"
    End If
End Sub
Reply With Quote