Accessing a linked file in a Word document using VBA

R

Robin

Hi -

Basic question, in my Word template I have some linked images. I want to use
VBA to change the path and filename of some of these links ... can anyone
give me a clue as to how I should best do this?

Thanks
Robin
 
R

Robin

Hi and thanks for the info, but it's not really what I want. All I want to do
is programatically change the name of the file that is being referenced. For
example if my document (or template file) has a link c:\My Pictures\house.gif
in it, then I want to change that to c:\My Pictures\apartment.gif

thanks
Robin
 
M

macropod

Hi Robin,

Your original post said "I want to use VBA to change the path and filename", but you gave no details of the criteria to be used for
either (and you still haven't). The link I pointed you to showed how you might go about changing the path automatically. To change
the filename as well (interactively), you could modify the macro as follows:

1. Create two new variables:
Dim OldFile As String
Dim NewFile As String
before:
Dim i As Integer

2. replace everything between:
OldPath = Replace(.LinkFormat.SourcePath, "\", "\\")
and:
End If
with:
' Get the old filename
OldFile = .LinkFormat.SourceName
' Get the new filename
getname:
NewFile = InputBox("What is the New Filename?", "Change Filename", OldFile)
If NewFile = "" Or InStr(NewFile, ".") = 0 Then GoTo getname
' Replace the link to the external file
.Code.Text = Replace(.Code.Text, OldPath & "\\" & OldFile, NewPath & "\\" & NewFile)
..Update

If you don't want to vary the path, simply change:
.Code.Text = Replace(.Code.Text, OldPath & "\\" & OldFile, NewPath & "\\" & NewFile)
to
.Code.Text = Replace(.Code.Text, OldFile, NewFile)
and delete the other bits of code & comments relating to OldPath and NewPath.

If this still doesn't suit, perhaps you could clarify exactly what it is you want to change and the criteria for making the
change(s).
 
F

Fumei2 via OfficeKB.com

Please try to be very explicit and clear. You write:

For
example if my document (or template file) has a link c:\My Pictures\house.gif

in it, then I want to change that to c:\My Pictures\apartment.gif

Now if you are asking about a hyperlink, you can do something like:

With Selection.Hyperlinks(1)
.Address = "C:\WhatEVER.jpg"
.TextToDisplay = "New text Yadda Yadda"
End With

This changes the hyperlink at the cursor (the Selection) to point to (link) c:
\whatever.jpg, and display the text ""New text Yadda Yadda" as the - well,
the displayed text.

So you change both the actual Address hyperlinked to, AND the text that is
displayed.
 
R

Robin

OK, I can try and explain the problem like this...

A company has a set of 50 document templates. In each of these templates
there are various images (pictures), for example a product logo, company logo
etc. There may be as many as 10 of these images in each template, and nearly
all are common to all templates. To make things easier we inserted these
images as linked and embedded objects with the intention that we could just
update the source image file (being linked to) and the new image would appear
in the template(s). This is a classic situation where a company chnages its
logo every few years. In theory this should work, but there are problems.

The problem has arisen that some of the images have been used in Headers and
Footers, and these Heasders and Footers have been included in the template's
Building Blocks (and Quick Lists). We did this because some headers we need
to replace on the fly, for example using a macro can change a Confidential
Document header to an Internal Document header and thereby void having even
more temples to cover each of these nuances. Now when we change the source
file there are problems. Firstly the Building Block does not update with the
new image, even though the Links dialog in the template shows there is a link
to the image file. If I try to edit the link to point to a different image
file (in the Links dialog) then Word crashes (Office 2007).

As a last resort I want to try and edit the image file paths and file names
programatically - that means using different image files, but maybe it will
work. So that is why I want to access the path and file names and replace
them. Any suggestions would be welcome.

thanks
Robin
 
R

Robin

OK, I can try and explain the problem like this...

A company has a set of 50 document templates. In each of these templates
there are various images (pictures), for example a product logo, company logo
etc. There may be as many as 10 of these images in each template, and nearly
all are common to all templates. To make things easier we inserted these
images as linked and embedded objects with the intention that we could just
update the source image file (being linked to) and the new image would appear
in the template(s). This is a classic situation where a company chnages its
logo every few years. In theory this should work, but there are problems.

The problem has arisen that some of the images have been used in Headers and
Footers, and these Heasders and Footers have been included in the template's
Building Blocks (and Quick Lists). We did this because some headers we need
to replace on the fly, for example using a macro can change a Confidential
Document header to an Internal Document header and thereby void having even
more temples to cover each of these nuances. Now when we change the source
file there are problems. Firstly the Building Block does not update with the
new image, even though the Links dialog in the template shows there is a link
to the image file. If I try to edit the link to point to a different image
file (in the Links dialog) then Word crashes (Office 2007).

As a last resort I want to try and edit the image file paths and file names
programatically - that means using different image files, but maybe it will
work. So that is why I want to access the path and file names and replace
them. Any suggestions would be welcome.

thanks
Robin
 
M

macropod

If I try to edit the link to point to a different image file (in the Links dialog) then Word crashes (Office 2007).
OK, Is your Word installation fully updated (SP2+)? Have you tried repairing it (Word Options|Resources|Detect & Repair)?

Beyond that, try the following code, which is based on the link I posted previously, plus the alterations I suggested in my previous
posts:

Option Explicit
' Word macro to automatically update IncludePicture field links.
' Created by macropod.
Dim TrkStatus As Boolean ' Track Changes flag
Dim Pwd As String ' String variable to hold passwords for protected documents
Dim pState As Boolean ' Document protection state flag

Sub ChangePicLinks()
' This routine runs whenever the document is opened.
' It calls on the others to do the real work.
' Prepare the environment.
With ActiveDocument
' Insert your document's password between the double quotes on the next line
Pwd = ""
' Initialise the protection state
pState = False
' If the document is protected, unprotect it
If .ProtectionType <> wdNoProtection Then
' Update the protection state
pState = True
' Unprotect the document
.Unprotect Pwd
End If
Call MacroEntry
' Most of the work is done by this routine.
Call UpdateIncludePictureFields
' Go to the start of the document
Selection.HomeKey Unit:=wdStory
' Clean up and exit.
Call MacroExit
' If the document was protected, reprotect it, preserving any formfield contents
If pState = True Then .Protect wdAllowOnlyFormFields, Noreset:=True, Password:=Pwd
End With
End Sub

Private Sub MacroEntry()
' Store current Track Changes status, then switch off temporarily.
With ActiveDocument
TrkStatus = .TrackRevisions
.TrackRevisions = False
End With
' Turn Off Screen Updating temporarily.
Application.ScreenUpdating = False
End Sub

Private Sub MacroExit()
' Restore original Track Changes status
ActiveDocument.TrackRevisions = TrkStatus
' Restore Screen Updating
Application.ScreenUpdating = True
End Sub

Private Sub UpdateIncludePictureFields()
' This routine sets the new path for external links, pointing them to the current folder.
Dim oRange As Range
Dim oField As Field
Dim OldPath As String
Dim NewPath As String
Dim OldFile As String
Dim NewFile As String
' Go through all story ranges in the document, including shapes,
' headers & footers.
For Each oRange In ActiveDocument.StoryRanges
' Go through the fields in the story range.
For Each oField In oRange.Fields
With oField
' Skip over fields that don't have links to image files.
If .Type = wdFieldIncludePicture Then
' Get the old path
OldPath = .LinkFormat.SourcePath
' Get the old filename
OldFile = .LinkFormat.SourceName
' Get the new path.
GetPath:
NewPath = InputBox("The document contains a link to an image named:" _
& vbCr & OldFile & vbCr & "in the folder below." & vbCr & _
"What is the new Path?", "Change File Path", OldPath)
If NewPath = "" Or InStr(NewPath, ":") = 0 Then GoTo GetPath
OldPath = Replace(.LinkFormat.SourcePath, "\", "\\")
' Get the new filename
GetName:
NewFile = InputBox("What is the new Filename?", "Change Filename", OldFile)
If NewFile = "" Or InStr(NewFile, ".") = 0 Then GoTo GetName
' Replace the link to the external file
.Code.Text = Replace(.Code.Text, OldPath & "\\" & OldFile, NewPath & "\\" & NewFile)
.Update
End If
End With
Next oField
Next oRange
End Sub

Place the code in your document's template (or Normal.dot/dotm), then activate the document to be updated and run the macro
'ChangePicLinks'.
 
R

Robin

Hi Macropod,

I have checked and diagnosed my Word 2007 - no problems and I'm using the
latest SP2.

I have tried the macro you listed - but it does not prompt. I have a
document with 2 inserted and linked pictures in it. One is in the header
defintiion in the header Gallery. The other is where the header has been
applied in the document. The Links dialog correctly lists this as two links.

When I run the macro in debug mode I see it loops 6 times on the "For each
oField in oRange.Fields", but I never see any of the prompts? Any clues?

Thanks again for the guidance.
Robin

macropod said:
If I try to edit the link to point to a different image file (in the Links dialog) then Word crashes (Office 2007).
OK, Is your Word installation fully updated (SP2+)? Have you tried repairing it (Word Options|Resources|Detect & Repair)?

Beyond that, try the following code, which is based on the link I posted previously, plus the alterations I suggested in my previous
posts:

Option Explicit
' Word macro to automatically update IncludePicture field links.
' Created by macropod.
Dim TrkStatus As Boolean ' Track Changes flag
Dim Pwd As String ' String variable to hold passwords for protected documents
Dim pState As Boolean ' Document protection state flag

Sub ChangePicLinks()
' This routine runs whenever the document is opened.
' It calls on the others to do the real work.
' Prepare the environment.
With ActiveDocument
' Insert your document's password between the double quotes on the next line
Pwd = ""
' Initialise the protection state
pState = False
' If the document is protected, unprotect it
If .ProtectionType <> wdNoProtection Then
' Update the protection state
pState = True
' Unprotect the document
.Unprotect Pwd
End If
Call MacroEntry
' Most of the work is done by this routine.
Call UpdateIncludePictureFields
' Go to the start of the document
Selection.HomeKey Unit:=wdStory
' Clean up and exit.
Call MacroExit
' If the document was protected, reprotect it, preserving any formfield contents
If pState = True Then .Protect wdAllowOnlyFormFields, Noreset:=True, Password:=Pwd
End With
End Sub

Private Sub MacroEntry()
' Store current Track Changes status, then switch off temporarily.
With ActiveDocument
TrkStatus = .TrackRevisions
.TrackRevisions = False
End With
' Turn Off Screen Updating temporarily.
Application.ScreenUpdating = False
End Sub

Private Sub MacroExit()
' Restore original Track Changes status
ActiveDocument.TrackRevisions = TrkStatus
' Restore Screen Updating
Application.ScreenUpdating = True
End Sub

Private Sub UpdateIncludePictureFields()
' This routine sets the new path for external links, pointing them to the current folder.
Dim oRange As Range
Dim oField As Field
Dim OldPath As String
Dim NewPath As String
Dim OldFile As String
Dim NewFile As String
' Go through all story ranges in the document, including shapes,
' headers & footers.
For Each oRange In ActiveDocument.StoryRanges
' Go through the fields in the story range.
For Each oField In oRange.Fields
With oField
' Skip over fields that don't have links to image files.
If .Type = wdFieldIncludePicture Then
' Get the old path
OldPath = .LinkFormat.SourcePath
' Get the old filename
OldFile = .LinkFormat.SourceName
' Get the new path.
GetPath:
NewPath = InputBox("The document contains a link to an image named:" _
& vbCr & OldFile & vbCr & "in the folder below." & vbCr & _
"What is the new Path?", "Change File Path", OldPath)
If NewPath = "" Or InStr(NewPath, ":") = 0 Then GoTo GetPath
OldPath = Replace(.LinkFormat.SourcePath, "\", "\\")
' Get the new filename
GetName:
NewFile = InputBox("What is the new Filename?", "Change Filename", OldFile)
If NewFile = "" Or InStr(NewFile, ".") = 0 Then GoTo GetName
' Replace the link to the external file
.Code.Text = Replace(.Code.Text, OldPath & "\\" & OldFile, NewPath & "\\" & NewFile)
.Update
End If
End With
Next oField
Next oRange
End Sub

Place the code in your document's template (or Normal.dot/dotm), then activate the document to be updated and run the macro
'ChangePicLinks'.

--
Cheers
macropod
[Microsoft MVP - Word]


Robin said:
OK, I can try and explain the problem like this...

A company has a set of 50 document templates. In each of these templates
there are various images (pictures), for example a product logo, company logo
etc. There may be as many as 10 of these images in each template, and nearly
all are common to all templates. To make things easier we inserted these
images as linked and embedded objects with the intention that we could just
update the source image file (being linked to) and the new image would appear
in the template(s). This is a classic situation where a company chnages its
logo every few years. In theory this should work, but there are problems.

The problem has arisen that some of the images have been used in Headers and
Footers, and these Heasders and Footers have been included in the template's
Building Blocks (and Quick Lists). We did this because some headers we need
to replace on the fly, for example using a macro can change a Confidential
Document header to an Internal Document header and thereby void having even
more temples to cover each of these nuances. Now when we change the source
file there are problems. Firstly the Building Block does not update with the
new image, even though the Links dialog in the template shows there is a link
to the image file. If I try to edit the link to point to a different image
file (in the Links dialog) then Word crashes (Office 2007).

As a last resort I want to try and edit the image file paths and file names
programatically - that means using different image files, but maybe it will
work. So that is why I want to access the path and file names and replace
them. Any suggestions would be welcome.

thanks
Robin

.
 
M

macropod

Hi Robin,

Are the pictures formatted as in-line or some other layout (eg square)?

--
Cheers
macropod
[Microsoft MVP - Word]


Robin said:
Hi Macropod,

I have checked and diagnosed my Word 2007 - no problems and I'm using the
latest SP2.

I have tried the macro you listed - but it does not prompt. I have a
document with 2 inserted and linked pictures in it. One is in the header
defintiion in the header Gallery. The other is where the header has been
applied in the document. The Links dialog correctly lists this as two links.

When I run the macro in debug mode I see it loops 6 times on the "For each
oField in oRange.Fields", but I never see any of the prompts? Any clues?

Thanks again for the guidance.
Robin

macropod said:
If I try to edit the link to point to a different image file (in the Links dialog) then Word crashes (Office 2007).
OK, Is your Word installation fully updated (SP2+)? Have you tried repairing it (Word Options|Resources|Detect & Repair)?

Beyond that, try the following code, which is based on the link I posted previously, plus the alterations I suggested in my
previous
posts:

Option Explicit
' Word macro to automatically update IncludePicture field links.
' Created by macropod.
Dim TrkStatus As Boolean ' Track Changes flag
Dim Pwd As String ' String variable to hold passwords for protected documents
Dim pState As Boolean ' Document protection state flag

Sub ChangePicLinks()
' This routine runs whenever the document is opened.
' It calls on the others to do the real work.
' Prepare the environment.
With ActiveDocument
' Insert your document's password between the double quotes on the next line
Pwd = ""
' Initialise the protection state
pState = False
' If the document is protected, unprotect it
If .ProtectionType <> wdNoProtection Then
' Update the protection state
pState = True
' Unprotect the document
.Unprotect Pwd
End If
Call MacroEntry
' Most of the work is done by this routine.
Call UpdateIncludePictureFields
' Go to the start of the document
Selection.HomeKey Unit:=wdStory
' Clean up and exit.
Call MacroExit
' If the document was protected, reprotect it, preserving any formfield contents
If pState = True Then .Protect wdAllowOnlyFormFields, Noreset:=True, Password:=Pwd
End With
End Sub

Private Sub MacroEntry()
' Store current Track Changes status, then switch off temporarily.
With ActiveDocument
TrkStatus = .TrackRevisions
.TrackRevisions = False
End With
' Turn Off Screen Updating temporarily.
Application.ScreenUpdating = False
End Sub

Private Sub MacroExit()
' Restore original Track Changes status
ActiveDocument.TrackRevisions = TrkStatus
' Restore Screen Updating
Application.ScreenUpdating = True
End Sub

Private Sub UpdateIncludePictureFields()
' This routine sets the new path for external links, pointing them to the current folder.
Dim oRange As Range
Dim oField As Field
Dim OldPath As String
Dim NewPath As String
Dim OldFile As String
Dim NewFile As String
' Go through all story ranges in the document, including shapes,
' headers & footers.
For Each oRange In ActiveDocument.StoryRanges
' Go through the fields in the story range.
For Each oField In oRange.Fields
With oField
' Skip over fields that don't have links to image files.
If .Type = wdFieldIncludePicture Then
' Get the old path
OldPath = .LinkFormat.SourcePath
' Get the old filename
OldFile = .LinkFormat.SourceName
' Get the new path.
GetPath:
NewPath = InputBox("The document contains a link to an image named:" _
& vbCr & OldFile & vbCr & "in the folder below." & vbCr & _
"What is the new Path?", "Change File Path", OldPath)
If NewPath = "" Or InStr(NewPath, ":") = 0 Then GoTo GetPath
OldPath = Replace(.LinkFormat.SourcePath, "\", "\\")
' Get the new filename
GetName:
NewFile = InputBox("What is the new Filename?", "Change Filename", OldFile)
If NewFile = "" Or InStr(NewFile, ".") = 0 Then GoTo GetName
' Replace the link to the external file
.Code.Text = Replace(.Code.Text, OldPath & "\\" & OldFile, NewPath & "\\" & NewFile)
.Update
End If
End With
Next oField
Next oRange
End Sub

Place the code in your document's template (or Normal.dot/dotm), then activate the document to be updated and run the macro
'ChangePicLinks'.

--
Cheers
macropod
[Microsoft MVP - Word]


Robin said:
OK, I can try and explain the problem like this...

A company has a set of 50 document templates. In each of these templates
there are various images (pictures), for example a product logo, company logo
etc. There may be as many as 10 of these images in each template, and nearly
all are common to all templates. To make things easier we inserted these
images as linked and embedded objects with the intention that we could just
update the source image file (being linked to) and the new image would appear
in the template(s). This is a classic situation where a company chnages its
logo every few years. In theory this should work, but there are problems.

The problem has arisen that some of the images have been used in Headers and
Footers, and these Heasders and Footers have been included in the template's
Building Blocks (and Quick Lists). We did this because some headers we need
to replace on the fly, for example using a macro can change a Confidential
Document header to an Internal Document header and thereby void having even
more temples to cover each of these nuances. Now when we change the source
file there are problems. Firstly the Building Block does not update with the
new image, even though the Links dialog in the template shows there is a link
to the image file. If I try to edit the link to point to a different image
file (in the Links dialog) then Word crashes (Office 2007).

As a last resort I want to try and edit the image file paths and file names
programatically - that means using different image files, but maybe it will
work. So that is why I want to access the path and file names and replace
them. Any suggestions would be welcome.

thanks
Robin

.
 
R

Robin

I have a few more details that maybe resolves some issues here...

The pictures in the document (or template) we are using have been inserted
by the Insert > Picture function. There is no way that I can access the field
in the Word GUI for this type of insertion, for example using ALT+F9. I guess
it's not even a field definition that's used.

However, if I use the Insert > Quick Parts > Field > Include Picture
function, then the INCLUDEPICTURE field is applied and is accessible using
ALT+F9, but only if the picture has its text wrapping set to inline. So the
macro would work for these types of pictures, but not those inserted using
Insert > Picture.

All the inserted pictures that we use have been included using the Insert >
Picture function. They are also not inline, but set to be behind text. So
would I have to would use some Picture object property to change the file
reference for each of these and not use the Field.Code.Text property?

Sorry about all the details and confusion, but appreciate the help.
Robin
 
M

macropod

Hi Robin,

For some reason, Word 2007 doesn't allow access to field codes in documents with the docx or docm format. I'm not sure how to code
around that, though working through the Shapes and Inlineshapes collections might work. Curiously, saving the same document in the
Word 97-2003 doc format allows access to the field codes (eg via Alt-F9).
 
P

Peter Jamieson

FWIW when you save as .docx/.docm in this scenario, I do not believe the
field code is saved at all. What seems to be saved is
a. a "relationship" that specifies the pathname of the image file.
Interestingly enough, this is a relative pathname
b. a copy of the image, renamed, inside a "media" folder within the
..docx - e.g. it may be named image1.jpeg
c. a relationship that specifies that image's pathname within the .docx.

I haven't had time to pursue it beyond that, but modifing the first
relationship manually and replacing image1.jpeg with the second image
does cause the .docx to open with the new picture in it as you might
hope. There may be additional info. in the document .xml (I haven't
looked) but with any luck everything Word actually needs to display the
correct picture will be in those relationships and copied image files.
If you can't access/modify the image pathname from the Word object
model, I guess the only thing for it - other than stick to .doc format -
is to try to do it by directly manipulating the OOXML. Not something I
have code for at this point.

Peter Jamieson

http://tips.pjmsn.me.uk
 
R

Robin

Yes that was my impression as well - and 2007 crashes dismally when trying to
update a link to an image placed in a header quick list. I have to try and
find all sorts of workarounds here and appreciate your help tremendously.

Robin
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top