How to find and replace content of Word? - vba

I want to update text in numerous Word files (in a lot of folders and sub folders). I have a function to loop through all of them.
I want to find and replace in the whole document. I can see the files are being opened and closed, but at the end nothing is saved.
Sub UpdateOneFolderToUnicode()
Dim strFolder As String, strFile As String
strFolder = "my folder here"
If strFolder = "" Then Exit Sub
'strFile = Dir(strFolder & "\*.docx", vbNormal) ' for docx files
strFile = Dir(strFolder & "\*.doc", vbNormal)
While strFile <> ""
updateOneFile strFolder & "\" & strFile
strFile = Dir()
Wend
End Sub
Sub updateOneFile(filePath)
Dim wdDoc As Document
Application.ScreenUpdating = True
On Error GoTo UpdateErr
Set wdDoc = Documents.Open(FileName:=filePath, AddToRecentFiles:=False, Visible:=False)
With wdDoc
With .Range.Find
.Text = "~"
.Replacement.Text = ChrW(625)
.Wrap = wdFindContinue
.MatchCase = True
End With
.Range.Find.Execute Replace:=wdReplaceAll
End With
wdDoc.Close SaveChanges:=True
Set wdDoc = Nothing
Application.ScreenUpdating = True
Exit Sub
UpdateErr:
Debug.Print "Update file: " & filePath & " Error: " & Err.Description
Set wdDoc = Nothing
End Sub

there is no errors.
and I made it work by updating part of the code to:
Set wdDoc = Documents.Open(FileName:=filePath, AddToRecentFiles:=False, Visible:=False)
Set myRange = wdDoc.Content
With myRange.Find
.Text = "Ä"
.Replacement.Text = ChrW(256)
.Wrap = wdFindContinue
.MatchCase = True
End With
myRange.Find.Execute Replace:=wdReplaceAll
Basically use Content instead of Range, and I have to put the wdDoc.Conent into a variable, otherwise still not working (not sure why).

Related

How do I extract the line my selection.find found? It will only return to me the first character

In the following code I am trying to insert a picuture into my word document based on the text I found while searchiung. The problem is it will only return to me the firsat character od the text. How do I get all of the text? How do I get the actual line it was found in? The text I am looking for is directly after the text found. IE: "Insert screen shot here of Boxshot" So I am trying to load a file called Boxshot. NOT working. Help.
Sub NewPic()
'
' NewPic Macro
'
Dim screenshot, Dirname, selfound As String
Dim Dn As Long
'
With Selection.Find
.Text = "Insert screen shot here of "
'.Replacement.Text = ""
.Forward = True
End With
Selection.Find.Execute
'
'Insert picture and find next match
'
While Selection.Find.Found
Selection.TypeParagraph
Selection.TypeParagraph
Selection.ParagraphFormat.Alignment = wdAlignParagraphCenter
Selection.Select
selfound = Selection.Characters.First
MsgBox ("Text=" & selfound)
'
'Is picture there?
'
Dirname = ActiveDocument.Name
Dn = InStr(Dirname, "User")
Dirname = Left(Dirname, Dn)
screenshot = "C:\Users\User 1\Desktop\VB Upload files\CD's\" & Dirname & "\" &
Selection.Text & ".jpg"
MsgBox ("Screenshot= " & screenshot & ", Sellectedtext=" & Selection.Text)
'
If Dir(screenshot) <> "" Then
Else
screenshot = "C:\Users\User 1\Desktop\Mylogo.jpg"
End If
'
Selection.InlineShapes.AddPicture FileName:= _
screenshot, LinkToFile:=False, SaveWithDocument _
:=True
'"C:\Users\User 1\Desktop\Mylogo.jpg", LinkToFile:=False, SaveWithDocument _
':=True
Selection.TypeParagraph
Selection.TypeParagraph
Selection.MoveDown Unit:=wdParagraph, Count:=1
Selection.TypeParagraph
Selection.Find.Execute
Wend
'
End Sub
Your use of Selection makes your code unnecessarily complex and slow. The following macro will insert the relevant pictures wherever "Insert screen shot here of " is followed by the pic name (no error-checking for valid names & files). If you don't want to retain the pic names below the pics, simply un-comment the commented-out line.
Sub NewPics()
Application.ScreenUpdating = False
With ActiveDocument.Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = "Insert screen shot here of "
.Replacement.Text = ""
.Forward = True
.Format = False
.Wrap = wdFindContinue
End With
Do While .Find.Execute
.Text = vbCr
.Collapse wdCollapseEnd
.End = .Paragraphs.Last.Range.End - 1
.ParagraphFormat.Alignment = wdAlignParagraphCenter
.InlineShapes.AddPicture FileName:=ActiveDocument.Path & "\" & .Text & ".jpg", LinkToFile:=False, SaveWithDocument:=True
'.Start = .Start + 1: .Delete
Loop
End With
Application.ScreenUpdating = True
End Sub

Search and replace wildcard in word documents

I have created this macro script that suppose to do the following:
Ask the user to select a directory.
Search for all docx files in the selected directory.
For each file found:
Open the file.
Replace a wildcard with an empty string.
Save the file
For some reason, text is not being replaced and the file is not saved.
Sub Remove_time_blocks()
Dim WdDoc As Document, sFile As String
Dim FilePath As String
Dim dlgSaveAs As FileDialog
Set dlgSaveAs = Application.FileDialog( _
FileDialogType:=msoFileDialogFolderPicker)
If dlgSaveAs.Show = -1 Then
FilePath = dlgSaveAs.SelectedItems(1)
sFile = Dir(FilePath & "/*.docx")
'Loop through all .doc files in that path
Do While sFile <> ""
Set WdDoc = Application.Documents.Open(FilePath & "\" & sFile)
With WdDoc.Content.Find
.Forward = True
.Wrap = wdFindStop
.Text = "^l^l[0-9]{1,}^l*:*--*,[0-9]{3}"
.Replacement.Text = ""
.Execute Replace:=wdReplaceAll, Forward:=True
End With
WdDoc.Save
sFile = Dir
Loop
End If
End Sub

dataSource.RecordCount in a mailMerge

I'm trying to use a macro I found online to save each doc from a mail merge into an individual PDF. But the macro does nothing. (never used macros before or VB) I tried stepping through the code and I get .DataSource.RecordCount = -1.
I can see the previewed documents, so the datasource is there. I figure there is something wrong with how it's getting the count value.
Any help is appreciated.
This is the whole macro:
Sub Merge_To_Individual_Files()
' Sourced from: https://www.msofficeforums.com/mail-merge/21803-mailmerge-tips-tricks.html
Application.ScreenUpdating = False
Dim StrFolder As String, StrName As String, MainDoc As Document, i As Long, j As Long
Const StrNoChr As String = """*./\:?|"
Set MainDoc = ActiveDocument
With MainDoc
StrFolder = .Path & "\"
With .MailMerge
.Destination = wdSendToNewDocument
.SuppressBlankLines = True
On Error Resume Next
For i = 1 To .DataSource.RecordCount
With .DataSource
.FirstRecord = i
.LastRecord = i
.ActiveRecord = i
If Trim(.DataFields("Last_Name")) = "" Then Exit For
'StrFolder = .DataFields("Folder") & "\"
StrName = .DataFields("key")
End With
On Error GoTo NextRecord
.Execute Pause:=False
For j = 1 To Len(StrNoChr)
StrName = Replace(StrName, Mid(StrNoChr, j, 1), "_")
Next
StrName = Trim(StrName)
With ActiveDocument
'Add the name to the footer
'.Sections(1).Footers(wdHeaderFooterPrimary).Range.InsertBefore StrName
.SaveAs FileName:=StrFolder & StrName & ".docx", FileFormat:=wdFormatXMLDocument, AddToRecentFiles:=False
' and/or:
.SaveAs FileName:=StrFolder & StrName & ".pdf", FileFormat:=wdFormatPDF, AddToRecentFiles:=False
.Close SaveChanges:=False
End With
NextRecord:
Next i
End With
End With
Application.ScreenUpdating = True
End Sub

VBA Word The remote server machine does not exist or is unavailable

This is a problem similar to several already posted. I need specific help though since I don't know how to apply the answers to other questions.
Basically, I'm writing code in Access that references MSWord, and if I run the code multiple times, it starts failing with the message
The remote server machine does not exist or is unavailable
Here's the code:
Private Sub CreateWordMergeDoc_Click()
On Error GoTo Err_CreateWordMergeDoc_Click
Dim strSQL, strChurch, strDistLang, strFind, strReplace As String
Dim wrdApp As Word.Application
Dim wrdDoc As Word.Document
Dim wrdMergeDoc As Word.Document
Dim strFilepath As String
strFilepath = "O:\Church Phone List"
'Require choice for church and district
If IsNull(Me![ChurchCombo]) = True Then
MsgBox "Select church", , "Church Phone List"
Me.ChurchCombo.SetFocus
GoTo CloseSub
End If
strChurch = Me![ChurchCombo]
strDistLang = Me![DistrictChoiceCombo]
If strDistLang = "" Then
MsgBox "Select District", , "Church Phone List"
Me.DistrictChoiceCombo.SetFocus
GoTo CloseSub
Else
strDistLang = IIf(Me![DistrictChoiceCombo] = "", "Church", Me![DistrictChoiceCombo])
End If
'Create SQL string from present church/district information
strSQL = "SELECT Churches.* " & vbCrLf & _
"FROM Churches " & vbCrLf & _
"WHERE (((Churches.Church)='" & strChurch & "') AND ((Churches.[District/Language])Like'" & strDistLang & "')) " & vbCrLf & _
"ORDER BY Churches.NAME;"
Set wrdApp = CreateObject("Word.Application")
wrdApp.Visible = True
Set wrdDoc = wrdApp.Documents.Open(strFilepath & "\Phone Merge Document.docx")
With wrdDoc
With .ActiveWindow
'Open the header/footer and add the church (and district if appropriate)
.ActivePane.View.SeekView = WdSeekView.wdSeekCurrentPageHeader
.Selection.EndKey Unit:=wdLine
.Selection.TypeText Text:=strChurch & IIf(strDistLang <> "Church", " (" & strDistLang & ")", "")
'Close header/footer
.ActivePane.View.SeekView = WdSeekView.wdSeekMainDocument
End With
With .MailMerge
.MainDocumentType = wdCatalog
.OpenDataSource NAME:= _
GetNamePath _
, ConfirmConversions:=False, ReadOnly:=False, LinkToSource:=True, _
AddToRecentFiles:=False, PasswordDocument:="", PasswordTemplate:="", _
WritePasswordDocument:="", WritePasswordTemplate:="", Revert:=False, _
Format:=wdOpenFormatAuto, Connection:= _
"DSN=MS Access Database;DBQ=" & strFilepath & "2017\Phone List 2017.mdb;DriverId=25;FIL=MS Access;MaxBufferSize=2048;PageTimeout=5;" _
, SQLStatement:=strSQL, SubType:= _
wdMergeSubTypeOther
.Destination = wdSendToNewDocument
.SuppressBlankLines = True
With .DataSource
.FirstRecord = wdDefaultFirstRecord
.LastRecord = wdDefaultLastRecord
End With
.Execute Pause:=False
End With
.Close SaveChanges:=wdDoNotSaveChanges
End With
With wrdApp
.Selection.WholeStory
With .Selection.ParagraphFormat
.SpaceBeforeAuto = False
.SpaceAfterAuto = False
End With
.Selection.ParagraphFormat.TabStops.ClearAll
.ActiveDocument.DefaultTabStop = InchesToPoints(0.5)
'Add a tab stop
.Selection.ParagraphFormat.TabStops.Add Position:=InchesToPoints(0.1), _
Alignment:=wdAlignTabLeft, Leader:=wdTabLeaderSpaces
'Replace (C) and (¢) with [C] and [c] since auto replace for (c) may be enabled
.Selection.Find.Replacement.ClearFormatting
With .Selection.Find
.Text = "(C)"
.Replacement.Text = "[C]"
.Forward = True
.Wrap = wdFindContinue
.Format = False
.MatchCase = True
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
.Selection.Find.Execute Replace:=wdReplaceAll
With .Selection.Find
.Text = "(¢)"
.Replacement.Text = "[c]"
.Forward = True
.Wrap = wdFindContinue
.Format = False
.MatchCase = True
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
.Selection.Find.Execute Replace:=wdReplaceAll
'Lock document so track changes stays on
.ActiveDocument.Protect Password:="onebody1", NoReset:=False, Type:= _
wdAllowOnlyRevisions, UseIRM:=False, EnforceStyleLock:=False
.ChangeFileOpenDirectory _
strFilepath & "\Track-Change Documents\"
End With
strFind = "/"
strReplace = " "
strDistLang = Replace(strDistLang, strFind, strReplace)
wrdApp.ActiveDocument.SaveAs2 FileName:=strChurch & IIf(strDistLang <> "Church", " - " & strDistLang, ""), FileFormat _
:=wdFormatXMLDocument, LockComments:=False, Password:="", _
AddToRecentFiles:=True, WritePassword:="", ReadOnlyRecommended:=False, _
EmbedTrueTypeFonts:=False, SaveNativePictureFormat:=False, SaveFormsData _
:=False, SaveAsAOCELetter:=False, CompatibilityMode:=14
wrdApp.ActiveDocument.Activate
'quit the word application:
wrdApp.Quit
MsgBox "Completed", , "Church Phone List"
CloseSub:
'Clear the object variables:
Set wrdDoc = Nothing
Set wrdApp = Nothing
Exit_CreateWordMergeDoc_Click:
Set wrdDoc = Nothing
Set wrdApp = Nothing
Exit Sub
Err_CreateWordMergeDoc_Click:
MsgBox Err.Description
Resume Exit_CreateWordMergeDoc_Click
End Sub
I'd be quite thankful if someone could help clean up the code with regard to the error message.
It appears that your problem is likely due to the calls to the unqualified InchesToPoints methods.
It doesn't appear (from what I can see on MSDN) that Access' Application object includes that method, and therefore it is defaulting to using the method which is part of the Word.Application object. This will create an instance of that object that isn't being released at the end of your program.
The easiest fix is to simply qualify the call by specifying that you want to use the late-bound Word.Application object you create, i.e. use wrdApp.InchesToPoints.

List attachments in Outlook email under signature

I am experienced with VBA in Excel but very new to it in Outlook. Does anyone know of a script to list the attachments in an outgoing email, under the signature? To be triggered by a ribbon item or keyboard shortcut?
I often send emails with attachments and would like to know what I sent by looking at any email in the conversation rather than having to find the email with the attached items.
Hopefully this image will clarify:
I would like to generate the last line of that email. I have a script to extract this info when replying to emails* but I don't know how to get attachment info out of an email I am about to send.
* Available here: http://www.slipstick.com/developer/code-samples/insert-attachment-names-replying/
You will probably need to make some adjustments, but you can use some of the existing code and just put it in the ItemSend event procedure:
This will automatically list the attachments whenever you send an email.
Private Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean)
Dim oAtt As Attachment
Dim strAtt As String
Dim olInspector As Inspector
Dim olDocument As Object
Dim olSelection As Object
For Each oAtt In Item.Attachments
strAtt = strAtt & "<<" & oAtt.filename & ">> "
Next
Set olInspector = Application.ActiveInspector()
Set olDocument = olInspector.WordEditor
Set olSelection = olDocument.Application.Selection
olSelection.InsertBefore strAtt
End Sub
It's certainly possible to do this using Ribbon customization, i.e., to hijack an existing context-menu so you would have an option to right-click & display attachment names, but frankly Ribbon UI development is fairly advanced technique and probably overkill for this specific need.
This is my solution. On "send" it detects desired attachment names and then appends them just after the signature. If there is an existing list of attachments then it overwrites it.
I have used the with function to encapsulate separate sections - the "'check to see if attachment info has already been added" section is optional. To use this in a standard module just replace the second line with sub() AttachmentLister
'This sub inserts the name of any meaningful attachments just after the signature
Private Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean)
Dim oAtt As Attachment
Dim strAtt, DateMark, ShortTime, FinalMsg, AttachName As String
Dim olInspector, oInspector As Inspector
Dim olDocument As Object
Dim olSelection As Object
Dim NewMail As MailItem
Dim AttchCount, i As Integer
Set oInspector = Application.ActiveInspector
Set NewMail = oInspector.CurrentItem
With NewMail
AttchCount = .Attachments.Count
If AttchCount > 0 Then
For i = 1 To AttchCount
AttachName = .Attachments.Item(i).DisplayName
If InStr(AttachName, "pdf") <> 0 Or InStr(AttachName, "xls") <> 0 Or InStr(AttachName, "doc") <> 0 Then
strAtt = strAtt & "<<" & AttachName & ">> " & vbNewLine
End If
Next i
End If
End With
GoTo skipsect ' this section is an alternative method of getting attachment names
For Each oAtt In Item.Attachments
If InStr(oAtt.FileName, "xls") <> 0 Or InStr(oAtt.FileName, "doc") <> 0 Or InStr(oAtt.FileName, "pdf") <> 0 Or InStr(oAtt.FileName, "ppt") <> 0 Or InStr(oAtt.FileName, "msg") <> 0 Or oAtt.Size > 95200 Then
strAtt = strAtt & "<<" & oAtt.FileName & ">> " & vbNewLine
End If
Next
Set olInspector = Application.ActiveInspector()
Set olDocument = olInspector.WordEditor
Set olSelection = olDocument.Application.Selection
skipsect:
'ShortTime = Format(Time, "Hh") & ":" & Format(Time, "Nn") & " "
DateMark = " (dated " & Date & ShortTime & ")"
If strAtt = "" Then
FinalMsg = ""
Else
FinalMsg = "Documents attached to this email" & DateMark & ": " & vbNewLine & strAtt
End If
Dim inputArea, SearchTerm As String
Dim SignatureLine, EndOfEmail As Integer
'Find the end of the signature
With ActiveInspector.WordEditor.Application
.Selection.WholeStory
.Selection.Find.ClearFormatting
With .Selection.Find
.Text = "Sales Co-ordinator"
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindAsk
.Format = False
.MatchCase = False
End With
.Selection.Find.Execute
SignatureLine = .Selection.Range.Information(wdFirstCharacterLineNumber) + 1
.Selection.EndKey Unit:=wdLine
End With
'check to see if attachment info has already been added
With ActiveInspector.WordEditor.Application
.Selection.MoveDown Unit:=wdLine, Count:=4, Extend:=wdExtend
inputArea = .Selection
.Selection.MoveUp Unit:=wdLine, Count:=4, Extend:=wdExtend
'detect existing attachment lists
If Not InStr(inputArea, "Documents attached to this email") <> 0 Then
.Selection.TypeParagraph
.Selection.TypeParagraph
Else
With .Selection.Find
.Text = "From:"
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindAsk
.Format = False
.MatchCase = True
.Execute
End With
'In case the email being replied to is not in english,
'try to detect the first line of the next email by looking for mailto
If .Selection.Find.Found = False Then
With .Selection.Find
.Text = "mailto"
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindAsk
.Format = False
.Execute
End With
End If
'designate the last line of the email and delete anything between this and the signature
EndOfEmail = .Selection.Range.Information(wdFirstCharacterLineNumber) - 1
.Selection.MoveUp Unit:=wdLine, Count:=1, Extend:=wdMove
.Selection.MoveUp Unit:=wdLine, Count:=EndOfEmail - SignatureLine, Extend:=wdExtend
.Selection.Expand wdLine
.Selection.Delete
End If
End With
'Insert the text and format it.
With ActiveInspector.WordEditor.Application
.Selection.TypeParagraph
.Selection.InsertAfter FinalMsg 'insert the message at the cursor.
.Selection.Font.Name = "Calibri"
.Selection.Font.Size = 9
.Selection.Font.Color = wdColorBlack
End With
lastline:
End Sub