Share via

How to add watermark to multiple word files of .doc & .docx extensions?

Anonymous
2017-11-06T15:33:56+00:00

I have multiple word docs (2900 of them) and recently have been asked to add a NEW watermark to all of them in every page of all the word files.  They are in a folder with multiple sub folders.  Is there a way to do this other than manually?

I searched on net & found this code, but this code only works on .docx files & not old files with older extensions  .doc files :-/

Means watermarks are added by this macro on .docx files & files having .doc extension remain without watermark added to them.

I have MS word 2007 at my office PC.

Here is the code that I found:

Option Explicit

Sub BatchProcess()

Dim strFileName As String

Dim strPath As String

Dim oDoc As Document

Dim oLog As Document

Dim oRng As Range

Dim oHeader As HeaderFooter

Dim oSection As Section

Dim fDialog As FileDialog

Set fDialog = Application.FileDialog(msoFileDialogFolderPicker)

With fDialog

    .Title = "Select folder and click OK"

    .AllowMultiSelect = False

    .InitialView = msoFileDialogViewList

    If .Show <> -1 Then

        MsgBox "Cancelled By User", , _

               "List Folder Contents"

        Exit Sub

    End If

    strPath = fDialog.SelectedItems.Item(1)

    If Right(strPath, 1) <> "" _

       Then strPath = strPath + ""

End With

If Documents.Count > 0 Then

    Documents.Close savechanges:=wdPromptToSaveChanges

End If

Set oLog = Documents.Add

If Left(strPath, 1) = Chr(34) Then

    strPath = Mid(strPath, 2, Len(strPath) - 2)

End If

strFileName = Dir$(strPath & "*.doc?")

While Len(strFileName) <> 0

    WordBasic.DisableAutoMacros 1

    Set oDoc = Documents.Open(strPath & strFileName)

    '

    'Do what you want with oDoc here

    For Each oSection In oDoc.Sections

        For Each oHeader In oSection.Headers

            If oHeader.Exists Then

                Set oRng = oHeader.Range

                oRng.Collapse wdCollapseStart

                InsertMyBuildingBlock "CONFIDENTIAL 1", oRng

            End If

        Next oHeader

    Next oSection

    'record the name of the document processed

    oLog.Range.InsertAfter oDoc.FullName & vbCr

    '

    oDoc.Close savechanges:=wdSaveChanges

    WordBasic.DisableAutoMacros 0

    strFileName = Dir$()

Wend

End Sub

Function InsertMyBuildingBlock(BuildingBlockName As String, HeaderRange As Range)

Dim oTemplate As Template

Dim oAddin As AddIn

Dim bFound As Boolean

Dim i As Long

bFound = False

Templates.LoadBuildingBlocks

For Each oTemplate In Templates

    If InStr(1, oTemplate.Name, "Building Blocks") > 0 Then Exit For

Next

For i = 1 To Templates(oTemplate.FullName).BuildingBlockEntries.Count

    If Templates(oTemplate.FullName).BuildingBlockEntries(i).Name = BuildingBlockName Then

        Templates(oTemplate.FullName).BuildingBlockEntries(BuildingBlockName).Insert _

                Where:=HeaderRange, RichText:=True

        'set the found flag to true

        bFound = True

        'Clean up and stop looking

        Set oTemplate = Nothing

        Exit Function

    End If

Next i

If bFound = False Then        'so tell the user.

    MsgBox "Entry not found", vbInformation, "Building Block " _

                                             & Chr(145) & BuildingBlockName & Chr(146)

End If

End Function

Please help

Thanks in advance :-)

Microsoft 365 and Office | Word | For home | Windows

Locked Question. This question was migrated from the Microsoft Support Community. You can vote on whether it's helpful, but you can't add comments or replies or follow the question.

0 comments No comments

Answer accepted by question author

  1. Paul Edstein 82,861 Reputation points Volunteer Moderator
    2017-11-07T00:14:36+00:00

    Actually, you might need to change your function as well. Try:

    Function InsertMyBuildingBlock(BuildingBlockName As String, HeaderRange As Range)

    Dim oTemplate As Template, oAddin As AddIn, bFound As Boolean, i As Long

    bFound = False

    Templates.LoadBuildingBlocks

    For Each oTemplate In Templates

      If InStr(1, oTemplate.Name, "Building Blocks") > 0 Then

        For i = 1 To Templates(oTemplate.FullName).BuildingBlockEntries.Count

          If Templates(oTemplate.FullName).BuildingBlockEntries(i).Name = BuildingBlockName Then

            Templates(oTemplate.FullName).BuildingBlockEntries(BuildingBlockName).Insert Where:=HeaderRange, RichText:=True

            'set the found flag to true

            bFound = True

            'Clean up and stop looking

            Set oTemplate = Nothing

            Exit For

          End If

        Next i

        Exit For

      End If

    Next

    If bFound = False Then  'so tell the user.

      MsgBox "Entry not found", vbInformation, "Building Block " & Chr(145) & BuildingBlockName & Chr(146)

    End If

    End Function

    Was this answer helpful?

    0 comments No comments

Answer accepted by question author

  1. Paul Edstein 82,861 Reputation points Volunteer Moderator
    2017-11-06T23:51:02+00:00

    Try using the following with your existing function:

    Option Explicit

    Dim FSO As Object, oFolder As Object, StrFolds As String

    Sub Main()

    Application.ScreenUpdating = False

    Dim TopLevelFolder As String, TheFolders As Variant, aFolder As Variant, i As Long

    TopLevelFolder = GetFolder

    If TopLevelFolder = "" Then Exit Sub

    StrFolds = vbCr & TopLevelFolder

    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))

      Call UpdateDocuments(CStr(Split(StrFolds, vbCr)(i)))

    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 UpdateDocuments(oFolder As String)

    Dim strFldr As String, strFile As String, wdDoc As Document

    Dim Rng As Range, Sctn As Section, HdFt As HeaderFooter, Shp As Shape

    strFldr = oFolder

    If strFldr = "" Then Exit Sub

    strFile = Dir(strFldr & "\*.doc", vbNormal)

    While strFile <> ""

      Set wdDoc = Documents.Open(FileName:=strFldr & "" & strFile, AddToRecentFiles:=False, ReadOnly:=False, Visible:=False)

      With wdDoc

        'Loop through all headers

        For Each Sctn In .Sections

          For Each HdFt In Sctn.Headers

            With HdFt

              'Watermark headers in use

              If .Exists = True Then

                If Sctn.Index = 1 Then

                  Set Rng = .Range

                  Rng.Collapse wdCollapseStart

                  InsertMyBuildingBlock "CONFIDENTIAL 1", Rng

                ElseIf .LinkToPrevious = False Then

                  Set Rng = .Range

                  Rng.Collapse wdCollapseStart

                  InsertMyBuildingBlock "CONFIDENTIAL 1", Rng

                End If

              End If

            End With

          Next

        Next

        'Save and close the document

        .Close SaveChanges:=wdSaveChanges

      End With

      strFile = Dir()

    Wend

    Set wdDoc = Nothing

    End Sub

    Was this answer helpful?

    0 comments No comments

5 additional answers

Sort by: Most helpful
  1. Jay Freedman 207.6K Reputation points Volunteer Moderator
    2017-11-06T18:59:04+00:00

    I can't see any reason in the code that *.doc files won't be processed the same as *.docx files. The statement

    strFileName = Dir$(strPath & "*.doc?")

    does find files with both extensions, as the question mark is interpreted as "zero or one character".

    In later versions of Word, there's a page in the Options > Trust Center Settings dialog with file block settings, which could be set to prevent opening of *.doc files. However, Word 2010 is the first version where that appears.

    Try this: Open the macro editor, place the cursor in the BatchProcess macro, and start pressing the F8 key. Each press runs one statement, and the current statement is highlighted in yellow. Watch the progress as the macro works, and hover the mouse pointer over variable names or use the Watch Window to see the values. Try to determine at what point a *.doc file is being skipped, and why.

    Was this answer helpful?

    1 person found this answer helpful.
    0 comments No comments
  2. Paul Edstein 82,861 Reputation points Volunteer Moderator
    2017-11-07T05:03:18+00:00

    The simplest solution at this stage would be to run the macro a second time, changing:

    Dir(strFldr & "\*.doc", vbNormal)

    to:

    Dir(strFldr & "\*.rtf", vbNormal)

    Was this answer helpful?

    0 comments No comments
  3. Anonymous
    2017-11-07T04:26:49+00:00

    Thankyou so much :)

    Yes your code worked.

    & Yes, I had to update with your given function.

    There are some (400+ files) Rich Text Format (.rtf) files which also need to have a watermark. As MS word by default opens Rich Text Format (.rtf) files in ms word so, I want to ask you there is a way for macro to do this with the code you provided:

    Option Explicit

    Dim FSO As Object, oFolder As Object, StrFolds As String

    Sub Main()

    Application.ScreenUpdating = False

    Dim TopLevelFolder As String, TheFolders As Variant, aFolder As Variant, i As Long

    TopLevelFolder = GetFolder

    If TopLevelFolder = "" Then Exit Sub

    StrFolds = vbCr & TopLevelFolder

    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))

    Call UpdateDocuments(CStr(Split(StrFolds, vbCr)(i)))

    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 UpdateDocuments(oFolder As String)

    Dim strFldr As String, strFile As String, wdDoc As Document

    Dim Rng As Range, Sctn As Section, HdFt As HeaderFooter, Shp As Shape

    strFldr = oFolder

    If strFldr = "" Then Exit Sub

    strFile = Dir(strFldr & "\*.doc", vbNormal)

    While strFile <> ""

    Set wdDoc = Documents.Open(FileName:=strFldr & "" & strFile, AddToRecentFiles:=False, ReadOnly:=False, Visible:=False)

    With wdDoc

    'Loop through all headers

    For Each Sctn In .Sections

    For Each HdFt In Sctn.Headers

    With HdFt

    'Watermark headers in use

    If .Exists = True Then

    If Sctn.Index = 1 Then

    Set Rng = .Range

    Rng.Collapse wdCollapseStart

    InsertMyBuildingBlock "CONFIDENTIAL 1", Rng

    ElseIf .LinkToPrevious = False Then

    Set Rng = .Range

    Rng.Collapse wdCollapseStart

    InsertMyBuildingBlock "CONFIDENTIAL 1", Rng

    End If

    End If

    End With

    Next

    Next

    'Save and close the document

    .Close SaveChanges:=wdSaveChanges

    End With

    strFile = Dir()

    Wend

    Set wdDoc = Nothing

    End Sub

    Function InsertMyBuildingBlock(BuildingBlockName As String, HeaderRange As Range)

    Dim oTemplate As Template, oAddin As AddIn, bFound As Boolean, i As Long

    bFound = False

    Templates.LoadBuildingBlocks

    For Each oTemplate In Templates

      If InStr(1, oTemplate.Name, "Building Blocks") > 0 Then

        For i = 1 To Templates(oTemplate.FullName).BuildingBlockEntries.Count

          If Templates(oTemplate.FullName).BuildingBlockEntries(i).Name = BuildingBlockName Then

            Templates(oTemplate.FullName).BuildingBlockEntries(BuildingBlockName).Insert Where:=HeaderRange, RichText:=True

            'set the found flag to true

            bFound = True

            'Clean up and stop looking

            Set oTemplate = Nothing

            Exit For

          End If

        Next i

        Exit For

      End If

    Next

    If bFound = False Then  'so tell the user.

      MsgBox "Entry not found", vbInformation, "Building Block " & Chr(145) & BuildingBlockName & Chr(146)

    End If

    End Function

    Was this answer helpful?

    0 comments No comments