How to change link location in Word using VBA? - vba

My Word document has links to Excel that, when displayed, look like this:
{ LINK Excel.SheetMacroEnabled.12 "C:\\Users\\Shawn\\projects\\Workbook1.xlsm" "Range1" }
I need my macro to be able to change this to a new path/file:
strNewFile = "C:\Users\Shawn\OtherFolder\Workbook2.xlsm".
(Note the single backslashes vs. the double ones.)
What's the simplest way? (Using Word 2013)

This post seemed to have the answer:
Linked Table in MS Word
Using this code:
Dim fieldCount As Integer, x As Long
With ActiveDocument
fieldCount = .Fields.Count
For x = 1 To fieldCount
With .Fields(x)
If .Type = 56 Then
'only update Excel links. Type 56 is an excel link
Debug.Print .LinkFormat.SourceFullName
.LinkFormat.SourceFullName = newfile '
.Update
.LinkFormat.AutoUpdate = False
DoEvents
End If
End With
Next x
End With

Sub changeSource()
Dim dlgSelectFile As FileDialog 'FileDialog object
Dim thisField As Field
Dim selectedFile As Variant 'must be Variant to contain filepath of selected item
Dim newFile As Variant
Dim fieldCount As Integer
'create FileDialog object as File Picker dialog box
Set dlgSelectFile = Application.FileDialog(FileDialogType:=msoFileDialogFilePicker)
With dlgSelectFile
'use Show method to display File Picker dialog box and return user's action
If .Show = -1 Then
'step through each string in the FileDialogSelectedItems collection
For Each selectedFile In .SelectedItems
newFile = selectedFile 'gets new filepath
Next selectedFile
Else 'user clicked cancel
End If
End With
Set dlgSelectFile = Nothing
'update fields
fieldCount = ActiveDocument.Fields.Count
For x = 1 To fieldCount
ActiveDocument.Fields(x).LinkFormat.SourceFullName = newFile
Next x
End Sub

Related

split a pdf based on the text using vba acrobat api

I am trying to split pdf, based on the pages where it finds ".pdf". some of pages in the PDF contains first line with with file name "abc1.pdf" or "abc2.pdf" and so on.
The Function Extract_PDF() need to open one instance of selected PDF, go to the last page, get its text to check if it contains ".pdf". if yes then make another instance of same PDF and remove its previous pages.
For the first instance only remove the page that contains ".pdf" till the last page. save both instances. do it in loop until split all the letters.
In nutshell, This code creates a new instance of the PDF using the pdf_Doc.Create method (here it get an error type mismatch), and copies the pages from the original pdf to the new pdf instance up to the page where ".pdf" is found. Then it saves this new pdf instance with a new name.
It also removes the pages from the original pdf starting from the page where ".pdf" is found till the last page. Finally, it saves the modified original pdf.
I don't know how to handle the .Create method, let me know where it get wrong? how I can optimize this code.
Function Extract_PDF()
Dim aApp As Acrobat.CAcroApp
Dim av_Doc As Acrobat.CAcroAVDoc
Dim pdf_Doc As Acrobat.CAcroPDDoc '
Dim newPDFdoc As Acrobat.CAcroPDDoc ' new variable for the new pdf instance
Dim Sel_Text As Acrobat.CAcroPDTextSelect
Dim i As Long, j As Long
Dim pageNum, Content
Dim pageContent As Acrobat.CAcroHiliteList
Dim found As Boolean
Dim foundPage As Integer
Dim PDF_Path As String
Dim PDF_Paths As String
Dim newPDF_Paths As String ' new variable for the new pdf path
Dim pdfName As String
Dim folerPath As String
Dim FileExplorer As FileDialog
Set FileExplorer = Application.FileDialog(msoFileDialogFilePicker)
With FileExplorer
.AllowMultiSelect = False
.InitialFileName = ActiveDocument.Path
.Filters.Clear
.Filters.Add "PDF File", "*.pdf"
If .Show = -1 Then
PDF_Path = .SelectedItems.Item(1)
Else
PagesLB = "Catch me Next Time ;)"
PDF_Path = ""
Exit Function
End If
End With
Set aApp = CreateObject("AcroExch.App")
Set av_Doc = CreateObject("AcroExch.AVDoc")
' Error handling
'On Error GoTo CleanUp
If av_Doc.Open(PDF_Path, vbNull) <> True Then Exit Function
Set pdf_Doc = av_Doc.GetPDDoc
totalPages = pdf_Doc.GetNumPages
For i = totalPages - 1 To 0 Step -1
Set pageNum = pdf_Doc.AcquirePage(i)
Set pageContent = CreateObject("AcroExch.HiliteList")
If pageContent.Add(0, 9000) <> True Then Exit Function
Set Sel_Text = pageNum.CreatePageHilite(pageContent)
Content = ""
found = False
For j = 0 To Sel_Text.GetNumText - 1
Content = Content & Sel_Text.GetText(j)
If InStr(1, Content, ".pdf") > 0 Then
found = True
foundPage = i
pdfName = Content
Exit For
End If
Next j
If found Then
PDF_Paths = Left(PDF_Path, InStrRev(PDF_Path, "\")) & ValidWBName(pdfName)
newPDF_Paths = Left(PDF_Path, InStrRev(PDF_Path, "\")) & ValidWBName(pdfName)
Set pdf_Doc = av_Doc.GetPDDoc
' create new instance of pdf
Set newPDFdoc = pdf_Doc.Create 'ERROR LINE "Type Mismatch"
' copy pages from the original pdf to the new pdf
If newPDFdoc.InsertPages(0, pdf_Doc, 0, foundPage - 1, True) = False Then
Debug.Print "Failed"
End If
' save new pdf
If newPDFdoc.Save(PDSaveFull, newPDF_Paths) = False Then
Debug.Print "Failed to save new pdf "
Else
Debug.Print "New pdf saved"
End If
' remove pages from the original pdf
If pdf_Doc.DeletePages(foundPage, totalPages - foundPage) = False Then
Debug.Print "Failed to remove pages from original pdf"
Else
Debug.Print "Pages removed from original pdf"
End If
'save the original pdf
If pdf_Doc.Save(PDSaveFull, PDF_Paths) = False Then
Debug.Print "Failed to save original pdf "
Else
Debug.Print "Original pdf saved"
End If
End If
Next i
CleanUp:
' code to handle errors and clean up resources
' for example, close the pdf document and release the objects
av_Doc.Close False
aApp.Exit
Set av_Doc = Nothing
Set pdf_Doc = Nothing
Set aApp = Nothing
End Function
Function ValidWBName(agr As String) As String
Dim RegEx As Object
Set RegEx = CreateObject("VBScript.RegExp")
With RegEx
.Pattern = "[\\/:\*\?""<>\|" & Chr(13) & Chr(10) & Chr(11) & "]"
.Global = True
ValidWBName = .Replace(agr, "")
End With
End Function

Copy certain contents from document to another at specific section

I want to copy a certain section (e.g. subject of the document then main body) to another Word document. The documents have different formatting so I need to copy to a predetermined location in the document.
The code below copies the whole of the source document to the target document.
Sub CopyPaste()
Dim Word As New Word.Application
Dim WordDoc As New Word.Document 'active document
Dim WordDoc1 As New Word.Document 'document to extract from
Dim dialogBox As FileDialog
Set dialogBox = Application.FileDialog(msoFileDialogOpen)
Dim Dest_path As String
dialogBox.AllowMultiSelect = False
dialogBox.Title = "Select a file to copy from"
'Show the file path and file name
If dialogBox.Show = -1 Then
MsgBox "You have selected: " & dialogBox.SelectedItems(1)
End If
' Starts extracting from source document
Set WordDoc1 = Word.Documents.Open(dialogBox.SelectedItems(1), ReadOnly:=True)
Application.Browser.Target = wdBrowseSection
For i = 1 To ((WordDoc1.Sections.Count) - 1)
WordDoc1.Bookmarks("\Section").Range.Copy
'Paste into an active document
ActiveDocument.Bookmarks("\Section").Range.PasteAndFormat wdFormatOriginalFormatting
WordDoc.ActiveWindow.Visible = True
WordDoc1.Close
Next i
End Sub
Since you're apparently running this from Word with an activedocument, you really don't want any of:
Dim Word As New Word.Application
Dim WordDoc As New Word.Document 'active document
Dim WordDoc1 As New Word.Document 'document to extract from
since that starts a new Word session and two new empty Word documents before you even get to the dialog.
As for:
.Bookmarks("\Section")
that only works in code like:
Set Rng = ActiveDocument.GoTo(What:=wdGoToSection, Name:=i)
Set Rng = Rng.GoTo(What:=wdGoToBookmark, Name:="\section")
Try something along the lines of:
Sub Replicate()
Dim DocSrc As Document, RngSrc As Range
Dim DocTgt As Document, RngTgt As Range
With Application.FileDialog(msoFileDialogOpen)
.AllowMultiSelect = False
.Title = "Select a file for content replication"
'Show the file path and file name
If .Show = -1 Then
MsgBox "You have selected: " & .SelectedItems(1)
Set DocSrc = Documents.Open(.SelectedItems(1), ReadOnly:=True, Visible:=False)
Else: Exit Sub
End If
End With
Set DocTgt = ActiveDocument
' Starts extracting from source document
For i = 1 To ((DocSrc.Count) - 1)
Set RngTgt = DocTgt.Sections(i).Range
RngTgt.End = RngTgt.End - 1
Set RngSrc = DocSrc.Sections(i).Range
RngSrc.End = RngSrc.End - 1
RngTgt.FormattedText = RngSrc.FormattedText
Next i
DocSrc.Close False
End Sub

VBA Download files from Lotus Notes

Im trying to download attachment from certain Lotus Notes e-mails. The code below works but it goes in infinite loop (code execution never ends after the procedure) after saving all required files. Something is wrong with Do until command I guess. Would appreaciate some help in fixing this issue.
Sub Test2Dobre()
Dim sess As Object
Dim db As Object
Dim view As Object
Dim doc As Object
Dim docNext As Object
Dim mailServer As String
Dim mailFile As String
Dim fld1 As String
Dim strSQL As String
Const stPath As String = "C:\Users\kuckam\Desktop\test notes\"
Const EMBED_ATTACHMENT As Long = 1454
Const RICHTEXT As Long = 1
Dim vaItem As Variant
Dim vaAttachment As Variant
Set sess = CreateObject("Notes.NotesSession")
'Call sess.Initialize(Password)
Dim objADOConnection As Object
Set objADOConnection = CreateObject("ADODB.Connection")
'to get your mail db:
mailServer = sess.GetEnvironmentString("MailServer", True)
mailFile = sess.GetEnvironmentString("MailFile", True)
Set db = sess.GetDatabase(mailServer, mailFile)
'Get Inbox folder:
Set view = db.GetView("($Inbox)")
'Loop through all documents in Inbox:
Set doc = view.GetFirstDocument
Do Until doc Is Nothing
Set docNext = view.GetNextDocument(doc)
If doc.HasEmbedded And doc.GetItemValue("From")(0) = "<Protokoly.warszawa#linde-mh.pl>" Then
MsgBox doc.GetItemValue("subject")(0)
'MsgBox doc.GetItemValue("From")(0)
'Check if the document has an attachment or not.
Set vaItem = doc.GetFirstItem("Body")
If vaItem.Type = RICHTEXT Then
For Each vaAttachment In vaItem.EmbeddedObjects
If vaAttachment.Type = EMBED_ATTACHMENT Then
'Save the attached file into the new folder and remove it from the e-mail.
With vaAttachment
.ExtractFile stPath & vaAttachment.Name
' .Remove
End With
End If
Next vaAttachment
End If
End If
Set doc = docNext
Loop
End Sub
EDIT:
Posting working code:
Function ADOExecSQL(strSQL As String)
ADOExecSQL = 1
On Error GoTo ERROR_FUNCTION
If ADODbConnect() = 0 Then GoTo ERROR_FUNCTION
cnConn.Execute strSQL
EXIT_FUNCTION:
Exit Function
ERROR_FUNCTION:
ADOExecSQL = 0
GoTo EXIT_FUNCTION
End Function
Sub Test2Dobre()
Dim sess As Object
Dim db As Object
Dim view As Object
Dim doc As Object
Dim docNext As Object
Dim mailServer As String
Dim mailFile As String
Dim fld1 As String
Dim strSQL As String
Const stPath As String = "C:\Users\kuckam\Desktop\test notes\"
Const EMBED_ATTACHMENT As Long = 1454
Const RICHTEXT As Long = 1
Dim vaItem As Variant
Dim vaAttachment As Variant
Set sess = CreateObject("Notes.NotesSession")
'Call sess.Initialize(Password)
Dim objADOConnection As Object
Set objADOConnection = CreateObject("ADODB.Connection")
'to get your mail db:
mailServer = sess.GetEnvironmentString("MailServer", True)
mailFile = sess.GetEnvironmentString("MailFile", True)
Set db = sess.GetDatabase(mailServer, mailFile)
'Get Inbox folder:
Set view = db.GetView("($Inbox)")
view.AutoUpdate = False
'Loop through all documents in Inbox:
Set doc = view.GetFirstDocument
Do Until doc Is Nothing
Set docNext = view.GetNextDocument(doc)
'If doc.HasEmbedded And doc.GetItemValue("From")(0) = "<Protokoly.warszawa#linde-mh.pl>" Then
'If doc.GetItemValue("From")(0) = "<Protokoly.warszawa#linde-mh.pl>" Then
'MsgBox doc.GetItemValue("subject")(0)
'MsgBox doc.GetItemValue("From")(0)
'Check if the document has an attachment or not.
Set vaItem = doc.GetFirstItem("Body")
On Error GoTo Line1
If vaItem.Type = RICHTEXT And doc.GetItemValue("From")(0) = "<Protokoly.warszawa#linde-mh.pl>" Then
For Each vaAttachment In vaItem.EmbeddedObjects
If vaAttachment.Type = EMBED_ATTACHMENT Then
'Save the attached file into the new folder and remove it from the e-mail.
With vaAttachment
.ExtractFile stPath & vaAttachment.Name
' .Remove
End With
End If
'Save the e-mail in order to reflect the deleting of the attached file.
'(A more sophisticated approach may be considered if several e-mails have
'several attachments in order to avoid a repeately saving of one e-mail.)
doc.Save True, False
Next vaAttachment
End If
'End If
'Call Attachment.ExtractFile("C:\Users\kuckam\Desktop\test notes")
'Call doc.PutInFolder("C:\Users\kuckam\Desktop\test notes")
Set doc = docNext
Loop
'Release objects from memory.
Set docNext = Nothing
Set doc = Nothing
Set view = Nothing
Set sess = Nothing
Set db = Nothing
Set objADOConnection = Nothing
Set vaItem = Nothing
Line1:
End Sub

VBA invalid qualifier with string.copy

I'm writing a code that loops through the textboxes of a word document. These textboxes contain a picture and a caption. So far, I have written a code that gets the caption from the textbox (which I checked through MsgBox caption).
I want to copy the caption, clear the textbox of all content, and then paste the old caption back in (because I'm trying to replace the pictures with an updated one). However, I keep getting an error with caption.Copy and have no idea why. It says that caption is an "Invalid Qualifier." I did some digging around online but haven't solved my problem.
This was the most-related thing I found: Invalid Qualifier error in Visual Basic 6.0
Anyway, here's my code. Any help would be appreciated!
Sub ReplaceImages()
Dim str As String
Dim captionTag As String
Dim imageTag As String
'Dim objShape As Variant Type Mismatch?
Dim fileName As String
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Application.EnableEvents = False
'Select directory to match .PNG to figure in document
Set SelectFolder = Application.FileDialog(msoFileDialogFolderPicker)
With SelectFolder
.Title = "Select Directory"
.AllowMultiSelect = False
If .Show <> -1 Then GoTo ResetSettings
sPath = .SelectedItems(1) & "\"
End With
sFile = Dir(sPath & "*png")
Do While sFile <> ""
fileName = sFile
MsgBox fileName
imageTag = BetweenParentheses(fileName)
For Each objShape In ActiveDocument.Shapes
If objShape.Type = msoTextBox Then
Set shapePicture = objShape
str = objShape.TextFrame.TextRange.Text
If InStr(str, "(") > 0 Then
captionTag = BetweenParentheses(objShape.TextFrame.TextRange)
If captionTag = imageTag Then
If InStr(str, "Figure") > 0 Then
Dim firstTerm As String
Dim secondTerm As String
Dim caption As String
firstTerm = "F"
secondTerm = ")"
Dim startPos As Long
Dim stopPos As Long
Dim nextPosition As Long
nextPosition = 1
caption = objShape.TextFrame.TextRange.Text
Do Until nextPosition = 0
startPos = InStr(nextPosition, caption, firstTerm, vbTextCompare) - 1
stopPos = InStr(startPos, caption, secondTerm, vbTextCompare) + 1
caption = Mid$(caption, startPos + Len(firstTerm), stopPos - startPos - Len(firstTerm))
nextPosition = InStr(stopPos, caption, firstTerm, vbTextCompare)
Loop
caption.Copy 'This is where the error is
End If
End If
End If
End If
Next objShape
sFile = Dir
Loop
ResetSettings:
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Application.EnableEvents = False
The caption variable is a string while the Copy method only applies to objects in the Word object model.
You store the text from the TextFrame into the caption variable:
caption = objShape.TextFrame.TextRange.Text
And then manipulate it inside your loop.
If you want to keep the value of the caption variable, then assign the value to another variable:
Dim someOtherVariable As String
someOtherVariable = caption
There might be some different between Excel and Word VBA in embedded shapes, but the following should be easy enough to adopt to word:
Sub test()
Dim shp As Shape, s As String
Set shp = ActiveSheet.Shapes(1)
s = shp.TextFrame2.TextRange.Text ' this is a string which doesn't have a Copy method
Debug.Print s
'but:
shp.TextFrame2.TextRange.Copy 'copies to clipboard!
End Sub
You can double check that the text is in the clipboard by pasting it directly into the immediate window (or wherever).

Multiple dialog boxes in VB

I'm having an issue that when I try to use multiple instances of file dialogs the information from the first is always overwritten by the selection in the second dialog.
What i need to do is:
Select a template file
Select a destination folder
Save the template file as a .docm file.
What happens is that the second time application.FileDialog is used all the information in fd is lost and is overwritten by the entries into fldr.
Can there only be one dialog object per macro?
Dim fd As FileDialog
Dim FileChosen As Integer
Dim FileName As String
Dim fldr As FileDialog
Dim fldrSelect As String
Dim i As Integer
Set fd = Application.FileDialog(msoFileDialogFilePicker)
'use the standard title and filters, but change the
'initial folder
fd.InitialFileName = "H:\UpdatedSalesTemplates\"
fd.InitialView = msoFileDialogViewList
'allow multiple file selection
fd.AllowMultiSelect = True
FileChosen = fd.Show
If FileChosen = -1 Then
'Select the directory using a file dialog
Set fldr = Application.FileDialog(msoFileDialogFolderPicker)
fldr.InitialView = msoFileDialogViewList
fldr.Title = "Select Destination"
fldr.AllowMultiSelect = False
fldrSelected = fldr.Show
'
Microsoft says that there may be only one: "...Each host application can only create a single instance of the FileDialog object...".
In any case, this shouldn't represent a serious problem as far as you can store all the relevant information (selected path, initial directory, etc.) in (string) variables.
For such scenarios where you need a file/folder picker in one macro/procedure/userform, I use a custom made userform. See if you like it. Place commandbuttons and textboxes as shown below
Screenshot
Code
Note: Both the textboxes .Locked property was set to True in design time so that the user cannot modify the textboxes manually.
Option Explicit
Dim Ret
'~~> Browse File
Private Sub CommandButton1_Click()
Ret = Application.GetOpenFilename("Excel Files (*.xlsx), *.xlsx")
If Ret <> False Then TextBox1.Text = Ret
End Sub
'~~> Browse Folder
Private Sub CommandButton2_Click()
Ret = BrowseForFolder("C:\")
If Ret <> False Then TextBox2.Text = Ret
End Sub
Function BrowseForFolder(Optional OpenAt As Variant) As Variant
Dim ShellApp As Object
Set ShellApp = CreateObject("Shell.Application"). _
BrowseForFolder(0, "Please choose a folder", 0, OpenAt)
On Error Resume Next
BrowseForFolder = ShellApp.self.Path
On Error GoTo 0
Set ShellApp = Nothing
Select Case Mid(BrowseForFolder, 2, 1)
Case Is = ":"
If Left(BrowseForFolder, 1) = ":" Then GoTo Invalid
Case Is = "\"
If Not Left(BrowseForFolder, 1) = "\" Then GoTo Invalid
Case Else
GoTo Invalid
End Select
Exit Function
Invalid:
'~~> If it was determined that the selection was invalid, set to False
BrowseForFolder = False
End Function