Computing.Net > Forums > Programming > Word Macro - Field Codes

Computing.Net: Over 1,000,000 posts about all things technology related! Over 90% answered within 24 hours! Click here to sign up now, it's free!

Word Macro - Field Codes

Reply to Message Icon

Original Message
Name: 24HG_Hoop
Date: August 21, 2007 at 13:55:37 Pacific
Subject: Word Macro - Field Codes
OS: XP
CPU/Ram: 3800 / 2 Gig
Model/Manufacturer: clone
Comment:

Hi all!

I'm looking for a way to batch find/replace paths in field codes using a macro. My document template has a couple hundred links to named cells in an excel template.

The process is that I open my excel template, run a macro* to open a specific .dot file, then save both the template .xls file and .dot file to a new folder with a common name. *Major props to Razor2.3 for helping out with that one! Will post the revised code if anybody wants it.

What I'm left with is a new .doc and .xls file, based on the template. The .doc template's path to the excel cells is \\\\server\\path\template.xls, but I need to append more commands to my "save as" macro [with pre-defined sName and sPath variables] so that it opens up the resultant sName.doc file and batch replaces the existing template path with my sPath\sName.xls path.

Thanks,

Hoop


Report Offensive Message For Removal


Response Number 1
Name: Razor2.3
Date: August 21, 2007 at 18:17:58 Pacific
Reply: (edit)

Know what this post could use? Some of the field codes in question. Especially if said field codes have the same name as part of the old path.


Report Offensive Follow Up For Removal

Response Number 2
Name: 24HG_Hoop
Date: August 27, 2007 at 11:38:38 Pacific
Reply: (edit)

In general, it would look like this for each link, and there are several hundred links:

{ LINK Excel.Sheet.8 "\\\\HoopServer\\VOL1\\DATA\\JOBS\\123AnywhereStreet_Anytown_Anycounty_GA\\Worksheetname.xls" ANSWERSTAB!ANS_RECONCILEDMARKETVALUE \a \t \* MERGEFORMAT }



Report Offensive Follow Up For Removal

Response Number 3
Name: Razor2.3
Date: September 3, 2007 at 19:38:56 Pacific
Reply: (edit)

Well, I'm far from happy with this code, but I don't really have time to work on it, and it does work, more or less. The biggest problem I couldn't overcome is the actual pulling of data in the fields. Apparently, there's some sort of problem with Excel running VBA code and pulling data at the same time, so Word considers the links broken. I've added code to 'fix' this, but it requires adding VBA to the Word document. I based this off of what I came up with last time.

Option Explicit

Sub AssembleReport()
Dim sTemplates As String
Dim sSaveName As String
Dim sLookFor As String
Dim oWord As Object
Dim oField As Object
Set oWord = CreateObject("Word.Application")

'Get the location of the Template directory
With CreateObject("WScript.Shell")
sTemplates = .ExpandEnvironmentStrings("%UserProfile%\Templates\")
End With

'Get this workbook's network path (What Word looks for)
sLookFor = SDblSlash(SToNetworkName(ThisWorkbook.FullName))

'Get the name/location for saving
sSaveName = SToNetworkName(SGetLoc)

'Save the Excel Sheet
ActiveWorkbook.SaveCopyAs sSaveName & ".xls"

'Open the template
With oWord.Documents.Open(sTemplates & SGetName)
oWord.Visible = True
'Update the field codes
For Each oField In .Fields
Application.StatusBar = "Updating field " & oField.Index
oField.Code.Text = Replace(oField.Code, sLookFor, """" & SDblSlash(sSaveName) & ".xls""", , , 1)
oField.Code.Text = Replace(oField.Code, SDblSlash(ThisWorkbook.FullName), "'" & SDblSlash(sSaveName) & ".xls""", , , 1)
oField.Code.Text = Replace(oField.Code, """""", """")
oField.Update
Next
Application.StatusBar = ""

.VBProject.VBComponents(1).CodeModule.AddFromString _
"Private Sub Document_Open()" & vbNewLine & _
"ThisDocument.Fields.Update" & vbNewLine & _
"End Sub"

'Saving our Word work
.SaveAs sSaveName & ".doc"
End With

'Cleanup
If Not oWord Is Nothing Then
oWord.Quit 0
Set oWord = Nothing
End If
End Sub

Private Function SGetLoc()
'Save dialog
SGetLoc = Application.GetSaveAsFilename()

'Remove any extension (I.E. .xls)
If InStrRev(SGetLoc, ".") Then _
SGetLoc = Left(SGetLoc, InStrRev(SGetLoc, ".") - 1)
End Function

Private Function SGetName()
SGetName = ActiveSheet.Range("G5").Value
End Function

Private Function SDblSlash(sIn As String)
SDblSlash = Replace(sIn, "\", "\\")
End Function

Private Function SToNetworkName(sIn As String)
Dim sName As String
Dim i As Integer
Dim cDrives As Object

sName = sIn
If Mid(sName, 2, 1) <> ":" Then
'Not a drive letter, mapped or otherwise
SToNetworkName = sName
Exit Function
End If

Set cDrives = CreateObject("WScript.Network").EnumNetworkDrives
With cDrives
For i = 0 To .Count - 1 Step 2
If InStr(1, Mid(sName, 1, 2), .Item(i), 1) And CBool(Len(.Item(i))) Then
'Found the network drive we're using
sName = .Item(i + 1) & Mid(sName, 3)
Exit For
End If
Next
End With
SToNetworkName = sName
End Function


Report Offensive Follow Up For Removal

Response Number 4
Name: 24HG_Hoop
Date: September 11, 2007 at 15:48:08 Pacific
Reply: (edit)

Thanks, Razor2.3

This ALMOST works perfectly. When I run the macro, it gives an error on the link. When you go into Edit->Links, it says:

Source file: [With correct path to file]
Item: [With correct sheet name and field name]
Type: Excel.Sheet.8 [Bonk.]

If I go in and say "Change Source" and post to the same exact source file, the "Excel.Sheet.8" part changes to "Worksheet" and the thing works.

Is there a part of what you wrote that says Excel.Sheet.8, and/or a way to change it to post a "Worksheet" into the type column?

Almost there. You the man!


Report Offensive Follow Up For Removal

Response Number 5
Name: 24HG_Hoop
Date: September 11, 2007 at 15:52:41 Pacific
Reply: (edit)

Thanks, Razor2.3

This ALMOST works perfectly. When I run the macro, it gives an error on the link. When you go into Edit->Links, it says:

Source file: [With correct path to file]
Item: [With correct sheet name and field name]
Type: Excel.Sheet.8 [Bonk.]

If I go in and say "Change Source" and post to the same exact source file, the "Excel.Sheet.8" part changes to "Worksheet" and the thing works.

Is there a part of what you wrote that says Excel.Sheet.8, and/or a way to change it to post a "Worksheet" into the type column?

It's really weird. I just tried it out with three field codes to see what was happening. I "changed source" on the first two and left the third as an invalid link. They ALL three look exactly the same in their formatting, but the third one doesn't work. Very odd.


Almost there. You the man!


Report Offensive Follow Up For Removal


Response Number 6
Name: 24HG_Hoop
Date: September 11, 2007 at 16:06:31 Pacific
Reply: (edit)

After further review...

Word doesn't like the .VBProject..... part. Error 6068.

I got it to work, sort of.

I think it has to do with the xls file (the "end product" xls file, not the template that generates the NAME.doc and NAME.xls file) not being open. I hit "Update Fields" in Edit->Links and got a dialog box about macro security that you normally get when you open the file. After it was open, it updated the links and changed the Excel.Sheet.8 part to Workbook, as it should have.

So... The solution, I think, is to open the .dot file, save it, save and close the beginning (template) xls file, open the new xls file, then open the new doc file. Both template files are closed. Both resultant "working" files are open. Then, run whatever the code is to update all fields. Can't recall that code, but I think it is on here somewhere.

Note: I also had to rearrange the flow of what you had posted. I don't know if it mattered or not, but putting the "Work goes here" section (where it gets the file name of the .dot file to open) before the o.Word.Documents.Open part made it work. Here's the code in its latest and greatest form, without the additions I think will make it work:


Sub AssembleReport()
Dim sTemplates As String
Dim sSaveName As String
Dim sLookFor As String
Dim oField As Object
Dim oWord As Object
Set oWord = CreateObject("Word.Application")

'Get the location of the Template directory
With CreateObject("WScript.Shell")
sTemplates = .ExpandEnvironmentStrings("J:\REPORT RESOURCES\TEMPLATES\")
End With

'Get this workbook's network path (What Word looks for)
sLookFor = SDblSlash(SToNetworkName(ThisWorkbook.FullName))

'Get the name/location for saving
sSaveName = SToNetworkName(SGetLoc)

'Work goes here
SGetName = ActiveSheet.Range("G5").Value

'Open the template
With oWord.Documents.Open(sTemplates & SGetName)
oWord.Visible = True
'Update the field codes
For Each oField In .Fields
Application.StatusBar = "Updating field " & oField.Index
oField.Code.Text = Replace(oField.Code, sLookFor, """" & SDblSlash(sSaveName) & ".xls""", , , 1)
oField.Code.Text = Replace(oField.Code, SDblSlash(ThisWorkbook.FullName), "'" & SDblSlash(sSaveName) & ".xls""", , , 1)
oField.Code.Text = Replace(oField.Code, """""", """")
oField.Update
Next
Application.StatusBar = ""

'Saving our work
.SaveAs sSaveName & ".doc"
End With
ActiveWorkbook.SaveCopyAs sSaveName & ".xls"

'Cleanup
If Not oWord Is Nothing Then
oWord.Quit 0
Set oWord = Nothing
End If
End Sub

Private Function SGetLoc()
'Save dialog
SGetLoc = Application.GetSaveAsFilename()

'Remove any extension (I.E. .xls)
If InStrRev(SGetLoc, ".") Then _
SGetLoc = Left(SGetLoc, InStrRev(SGetLoc, ".") - 1)
End Function


Private Function SDblSlash(sIn As String)
SDblSlash = Replace(sIn, "\", "\\")
End Function

Private Function SToNetworkName(sIn As String)
Dim sName As String
Dim i As Integer
Dim cDrives As Object

sName = sIn
If Mid(sName, 2, 1) <> ":" Then
'Not a drive letter, mapped or otherwise
SToNetworkName = sName
Exit Function
End If

Set cDrives = CreateObject("WScript.Network").EnumNetworkDrives
With cDrives
For i = 0 To .Count - 1 Step 2
If InStr(1, Mid(sName, 1, 2), .Item(i), 1) And CBool(Len(.Item(i))) Then
'Found the network drive we're using
sName = .Item(i + 1) & Mid(sName, 3)
Exit For
End If
Next
End With
SToNetworkName = sName
End Function




Report Offensive Follow Up For Removal

Response Number 7
Name: 24HG_Hoop
Date: September 11, 2007 at 18:54:07 Pacific
Reply: (edit)

I'm entirely unfamiliar with this stuff, but I'm learning as I go, so please bear with me.

First - what does "Option Explicit" do? Whenever I add it in, I get an "undefined" error.

Ok, here's what I've got thus far:

Sub AssembleReport()
Dim sTemplates As String
Dim sSaveName As String
Dim sLookFor As String
Dim oField As Object
Dim oWord As Object
Set oWord = CreateObject("Word.Application")

'Get the location of the Template directory
With CreateObject("WScript.Shell")
sTemplates = .ExpandEnvironmentStrings("J:\REPORT RESOURCES\TEMPLATES\")
End With

'Get this workbook's network path (What Word looks for)
sLookFor = SDblSlash(SToNetworkName(ThisWorkbook.FullName))

'Get the name/location for saving
sSaveName = SToNetworkName(SGetLoc)
ActiveWorkbook.SaveCopyAs sSaveName & ".xls"

'Work goes here
SGetName = ActiveSheet.Range("G5").Value

'Open the Word template
With oWord.Documents.Open(sTemplates & SGetName)
oWord.Visible = True

'Update the field codes in new Word document (working document)
For Each oField In .Fields
Application.StatusBar = "Updating field " & oField.Index
oField.Code.Text = Replace(oField.Code, sLookFor, """" & SDblSlash(sSaveName) & ".xls""", , , 1)
oField.Code.Text = Replace(oField.Code, SDblSlash(ThisWorkbook.FullName), "'" & SDblSlash(sSaveName) & ".xls""", , , 1)
oField.Code.Text = Replace(oField.Code, """""", """")
oField.Update
Next
Application.StatusBar = ""

'Saving our work
.SaveAs sSaveName & ".doc"

End With

'Open the new Excel document (working document)

'???

'Open the new Word document (working document)

'???

'Cleanup
If Not oWord Is Nothing Then
oWord.Quit 0
Set oWord = Nothing
End If
End Sub


Private Function SGetLoc()
'Save dialog
SGetLoc = Application.GetSaveAsFilename()

'Remove any extension (I.E. .xls)
If InStrRev(SGetLoc, ".") Then _
SGetLoc = Left(SGetLoc, InStrRev(SGetLoc, ".") - 1)
End Function


Private Function SDblSlash(sIn As String)
SDblSlash = Replace(sIn, "\", "\\")
End Function

Private Function SToNetworkName(sIn As String)
Dim sName As String
Dim i As Integer
Dim cDrives As Object

sName = sIn
If Mid(sName, 2, 1) <> ":" Then
'Not a drive letter, mapped or otherwise
SToNetworkName = sName
Exit Function
End If

Set cDrives = CreateObject("WScript.Network").EnumNetworkDrives
With cDrives
For i = 0 To .Count - 1 Step 2
If InStr(1, Mid(sName, 1, 2), .Item(i), 1) And CBool(Len(.Item(i))) Then
'Found the network drive we're using
sName = .Item(i + 1) & Mid(sName, 3)
Exit For
End If
Next
End With
SToNetworkName = sName
End Function


That does just about everything. ONLY problem is sometimes it "hangs" the excel file in memory and I can't open it without rebooting. Is there a way to clear out all of the memory (dims, sets, etc.)? Ever since I've started doing this, I cannot open Excel or Doc files from Explorer - I have to open each app, then browse for the file. Can't figure out why - memory thing?

I would like to, at the end of all of this, "finish off" the code by closing down the original xls file that I started with, and then FIRST open up the new Excel file (sName.xls) and then the new Doc file (sName.doc). I've tried a couple of combinations from what little I know about this stuff, but I can't get all three things to do right.

Any help is much appreciated.

Thanks again,

Hoop


Report Offensive Follow Up For Removal

Response Number 8
Name: Razor2.3
Date: September 11, 2007 at 19:49:16 Pacific
Reply: (edit)

what does "Option Explicit" do?
It forces you to explicitly define your variables. It helps with debugging. A lot. (Nothing like spending an hour trying to find out why this chunk of code doesn't work, just to find out you swapped two keys on a variable a few lines ago.)

sometimes it "hangs" the excel file
That happens from time to time when debugging code like this. One option would be to open Task Manager and kill any excel.exe and winword.exe you see (in the Processes tab). If you're running WinXP Pro, there's an easy command you can use: taskkill /f /im excel.exe /im winword.exe

closing down the original xls file that I started with...open up the new Excel file...
The easier option would be to change our workbook save action to match the GUI's Save As behavior. To do this, we change the following line:
ActiveWorkbook.SaveCopyAs sSaveName & ".xls"
to:
ActiveWorkbook.SaveAs sSaveName & ".xls"

...and then the new Doc file (sName.doc).
Well, we already have it open. We just haven't made it visible. to do that, replace this line:
oWord.Quit 0
with:
oWord.Visible = True


Report Offensive Follow Up For Removal

Response Number 9
Name: 24HG_Hoop
Date: September 12, 2007 at 18:03:17 Pacific
Reply: (edit)

You tha man!

Thanks a bunch!!

-Hoop


Report Offensive Follow Up For Removal






Post Locked

This post is quite old and has been locked from receiving new replies. Please create a new posting instead.


Go to Programming Forum Home








Do you have your own blog?

Yes
No
I did before
I will soon


View Results

Poll Finishes In 4 Days.
Discuss in The Lounge
Poll History




Data Recovery Software