MSWord .SaveAs vs .ExportAsFixedFormat - vba

I have a large Lotus Notes project, a small part of which uses Word to create PDFs. In one piece, it pastes some text into a new Word document and saves as a PDF, like this:
Set wrdApp = createObject("Word.Application")
wrdApp.visible = True
Set wrdDoc = wrdApp.documents.add()
Set selection=wrdApp.Selection
selection.InsertBefore(doc.body(0))
strSaveFilename = "HelloWorld.pdf"
wrddoc.Saveas strSaveFileName, 17
Call wrddoc.close(0)
Set wrddoc = Nothing
Call wrdapp.quit(0)
Set wrdapp = Nothing
and in another part of the same chunk, it opens a Word document and then saves it as a PDF, like this:
Set MCwrdApp = createObject("Word.Application")
McwrdApp.visible = true
Dim wrdDoc As Variant 'word document
strfilename = "HelloWorld.docx"
Set wrddoc = MCwrdApp.documents.Open(strfilename)
f2 = "HelloWorld.pdf"
wrddoc.ExportAsFixedFormat f2, 17, 0, 1
wrddoc.close(0)
Set wrddoc = Nothing
Call Mcwrdapp.quit(0)
Set McwrdApp = Nothing
The problem I'm having is that since we upgraded to Office 2016, occasionally WINWORD.EXE gets left running and I have to kill it with Task Manager. The last time it happened Word was started in the sub that does the copy/paste. But that's not the question. The question is, are there differences between using .SaveAs and .ExportAsFixedFormat in this scenario? Why would the developer (not me) have used one in one place and the other somewhere else?

Related

VBA Turn .selection from Word Document into a string

Good Evening. I've been trying to transform a whole Word doc into a string. My current problem is that I can open the doc, select the text, but I can't manage to transform into a string. Funny thing is that a msgbox print the text on the screen.
Dim s_txt as string
Dim wrdDoc As Word.Document
Set wrdApp = CreateObject("Word.Application")
wrdApp.Visible = True
s_arq = Cells(1, i_col)
Set wrdDoc = wrdApp.Documents.Open("C:\Users\USER\Desktop\TCC\pdf2doc\" & s_arq)
wrdApp.Selection.WholeStory
wrdApp.Selection.Find.ClearFormatting
MsgBox(wrdApp.Selection)
s_txt = wrdApp.Selection
wrdApp.Quit
When I try to get the string s_txt it returns nothing. But the msgbox print the text perfectly.
I tried selection.text, and it returns nothing.

Replacing text in Word doc with text from Excel

I am looking to create a via script in excel that will replace a text holder in a word doc with some text from excel.
I can get the via script to open the word doc, and then save the doc under a new name. however it will not execute the replace text part :(
Private Sub CommandButton1_Click()
Dim wdApp As Object
Dim wdDoc As Object
Set wdApp = CreateObject("Word.Application")
wdApp.Visible = False
Set wdDoc = wdApp.Documents.Open("temp.docx")
With wdDoc.Content.Find
.ClearFormatting
.Text = "<<name>>"
With .Replacement
.ClearFormatting
.Font.Bold = True
.Text = "John Smith"
End With
.Execute Replace:=wdReplaceAll
End With
wdDoc.SaveAs2 Filename:=("temp2.docx")
Set wdApp = Nothing
Set wdDoc = Nothing
End Sub
I have tried doing a search in here but can't see where I am going wrong :(
currently it opens the word doc and saves it under a new name but does not replace the find and replace the text. Can anyone see where I have gone wrong and show me how to get it right?
When I set up a test for your problem description in Word, by typing <<name>> I see that Word replaces the two angled brackets with special symbols. And it offers the possibility to undo the AutoCorrect causing this.
Querying ASC(Selection.Text) on them gives Chr(171) and Chr(187), which are also double-angled bracket symbols, but using them in Find does not work. Querying AscW() reveals the two symbols are Unicode 8810 and 8811, so they need to be searched differently.
Assuming that's the issue in your case, the following works:
With wdDoc.content.Find
.ClearFormatting
.Text = ChrW(8810) & "name" & ChrW(8811) '"<<name>>"
With .Replacement
.ClearFormatting
.Font.Bold = True
.Text = "John Smith"
End With
.Execute Replace:=wdReplaceAll
End With
Further to your code - it has other, potentially grave problems (memory leak):
If you do this: wdApp.Visible = False then you need to be absolutely certain to remove Word from memory:
wdDoc.Close
wdApp.Quit
Set wdDoc = Nothing
Set wdApp = Nothing
Unlike Excel, Word won't quit automatically when its object goes out of scope (macro ends). It will stay open, which you can see in the Task Manager.
In addition, you need to release the objects in the reverse order in which they were instantiated - wdDoc before wdApp.
Setup some DocVariables in your Word doc and run the code below, from within Excel.
Sub PushToWord()
Dim objWord As New Word.Application
Dim doc As Word.Document
Dim bkmk As Word.Bookmark
sWdFileName = Application.GetOpenFilename(, , , , False)
Set doc = objWord.Documents.Open(sWdFileName)
'On Error Resume Next
objWord.ActiveDocument.variables("BrokerFirstName").Value = Range("BrokerFirstName").Value
objWord.ActiveDocument.variables("BrokerLastName").Value = Range("BrokerLastName").Value
objWord.ActiveDocument.variables("Ryan").Value = Range("Ryan").Value
objWord.ActiveDocument.Fields.Update
'On Error Resume Next
objWord.Visible = True
End Sub
You can use essentially the same process by setting up Bookmarks in Word, and pushing data from fields in Excel to fields (Bookmarks) in Word.
Sub PushToWord()
Dim objWord As New Word.Application
Dim doc As Word.Document
Dim bkmk As Word.Bookmark
sWdFileName = Application.GetOpenFilename(, , , , False)
Set doc = objWord.Documents.Open(sWdFileName)
On Error Resume Next
ActiveDocument.Variables("BrokerFirstName").Value = Range("B1").Value
ActiveDocument.Variables("BrokerLastName").Value = Range("B2").Value
ActiveDocument.Fields.Update
On Error Resume Next
objWord.Visible = True
End Sub
The famouse hope - to have one button for all live cases with caption: "Make it OK!"
Do divide the task on parts:
- Get "... text from excel ..."
- "replace text in word doc ..." with text getted from Excel on previouse step
Do it by two separate procedures for each of tasks,
called from the third procedure united them.
.

Setting table AutoFit via VBA gives different result than clicking UI button

I'm trying to set AutoFitBehavior of a Word table to fit both content and window - clicking 'AutoFit Contents' button, then 'AutoFit Window' gives the result I want to get. The problem is, when I do this using VBA, the formatting is different. Interestingly enough, when I run the macro Step By Step (F8) it gives expected result (same as UI).
Here's my code:
Documents(1).Activate
With ActiveDocument.Tables(2)
.AllowAutoFit = True
.AutoFitBehavior 1
.AutoFitBehavior 2
End With
As you can see, it's pretty simple - I can't find any reason for it to work incorrectly.
Also I don't think the issue is related to using 'ActiveDocument' property, as in the full macro this code is executed directly on a newly created, named document, so I'm sure it's addressing a correct table in a correct file.
I am aware that I can set column widths with PreferredWidth property, but it would be much simpler to use AutoFit, as I don't always know what length will my data have.
Is there a way to make this method work as when called from UI?
Edit:
As per Cindy Meister's request, I'm adding snippet from actual code I'm using:
Set wordApp = CreateObject("Word.Application")
Set wordDoc = wordApp.Documents.Add(strPath)
With wordDoc
.Tables.Add Range:=wordDoc.Bookmarks("tableBookmark").Range, NumRows:=licenceRows, NumColumns:=3
'[omitted: populating the table]
.Tables(1).Split(splitRow)
With .Tables(2)
.Range.Collapse Direction:=0
.Range.InsertBreak Type:=7
.AllowAutoFit = True
.AutoFitBehavior 1
.AutoFitBehavior 2
End With
End With
It's called from an Excel macro I'm using to create a report file from template. I'm using Office 2013.
Also I've noticed another thing today: when I set wordApp.Visible = True, scroll to the table and literally look at the method working - it formats correctly. It's like Word application won't use this method correctly, until it has to show you every single step (as with step-by-step run).
Thanks to Cindy's answer and following comment I realised my mistake - I thought Auto Fit would make columns fit to any text, including text with line-breaking characters like spaces. Comes out it doesn't work that way.
In the end, to format the table as I wanted (window-wide table, columns fit to content) I used the following code:
'Table should fit the page and fit the contents
Sub TestFormatTableStructure()
Dim wordApp As Word.Application
Dim wordDoc As Word.Document
Dim tbl1 As Word.Table, tbl2 As Word.Table
On Error GoTo ErrHandler
Set wordApp = New Word.Application
Set wordDoc = wordApp.Documents.Add
wordApp.ScreenUpdating = False
With wordDoc
Set tbl1 = .Tables.Add(Range:=wordDoc.Paragraphs.Last.Range, _
NumRows:=6, NumColumns:=3, _
DefaultTableBehavior:=wdWord9TableBehavior, _
AutoFitBehavior:=wdAutoFitContent) 'autofit content
With tbl1
'[omitted: populating the table]
.PreferredWidthType = wdPreferredWidthPercent
.PreferredWidth = 100
End With
Set tbl2 = tbl1.Split(4)
'dont have to set formatting again for second table, its inherited
With tbl2
'[do things]
End With
End With
ErrHandler:
wordApp.Visible = True
wordApp.ScreenUpdating = True
Set tbl1 = Nothing
Set tbl2 = Nothing
Set rngtlb = Nothing
Set wordDoc = Nothing
Set wordApp = Nothing
End Sub
Thanks for the additional info. For the future, in such a case it would help if you include the automation code for running from Excel, as well, since the issue could be with that interface...
I ran the following code in Office 2013 (as well as in 2010) and it worked as expected: the table fit the width of the page (margin to margin) and the cells expanded to fit the content.
In contrast to what you have, I've used the optional arguments in Tables.Add to set the default behavior to allow AutoFit when creating the table. Then I didn't need to set all of them after-the-fact.
Notice also my use of object variables for the tables and the Ranges, releasing the objects, and updating the screen.
'Table should fit the page and fit the contents
Sub TestFormatTableStructure()
Dim wordApp As Word.Application
Dim wordDoc As Word.Document
Dim tbl1 As Word.Table, tbl2 As Word.Table
Dim rngTbl As Word.Range
On Error GoTo ErrHandler
Set wordApp = New Word.Application
Set wordDoc = wordApp.Documents.Add
wordApp.ScreenUpdating = False
With wordDoc
Set tbl1 = .Tables.Add(Range:=wordDoc.Paragraphs.Last.Range, _
NumRows:=6, NumColumns:=3, _
DefaultTableBehavior:=wdWord9TableBehavior, _
AutoFitBehavior:=2)
'[omitted: populating the table]
Set tbl2 = tbl1.Split(4)
With tbl2
Set rngTbl = .Range
rngTbl.Collapse Direction:=0
rngTbl.InsertBreak Type:=7
'.AllowAutoFit = True
'.AutoFitBehavior 1
.AutoFitBehavior 2
End With
End With
ErrHandler:
wordApp.Visible = True
wordApp.ScreenUpdating = True
Set tbl1 = Nothing
Set tbl2 = Nothing
Set rngtlb = Nothing
Set wordDoc = Nothing
Set wordApp = Nothing
End Sub

Word document : Set to landscape

I have this ridiculous problem on ms-word 2007. I have most of my macro working as intended but the orientation can't seem to stay in place. I set it to landscape using VBA but it will always go back to portrait. If I step into the code right after this line the document IS in landscape but as soon as I click even once only in the document it goes back to portrait.
Do you guys have an idea why this happens ? I can't seem to find anyone having this bug on Google.
Option Explicit
Sub créer_rapport()
Dim wdApp As Word.Application
Dim wdDoc As Word.Document
Set wdApp = New Word.Application
wdApp.Visible = True
Set wdDoc = wdApp.Documents.Open(Range("path_fichier").Value)
wdApp.Selection.WholeStory
wdApp.Selection.Font.Name = "Courier New"
wdApp.Selection.Font.Size = 7
wdDoc.PageSetup.Orientation = wdOrientLandscape
wdDoc.PageSetup.PaperSize = wdPaperLegal
wdDoc.SaveAs ActiveWorkbook.Path & "\test2", wdFormatXMLDocument
Do While wdApp.Selection.Find.Execute("Merge")
wdApp.Selection.MoveUp wdLine, 1
wdApp.Selection.InsertBreak wdPageBreak
wdApp.Selection.MoveDown wdLine, 2
Loop
With wdDoc
.SaveAs (ActiveWorkbook.Path & "\test")
.Close (True)
End With
wdApp.Quit False
End Sub
This is all there is to my macro (for now).
(Oh and you can highlight bad style, this is the first time I do VBA macros for Word (I do them all the time in Excel))
Thanks !
Instead of:
wdDoc.PageSetup.Orientation = wdOrientLandscape
Try this:
Selection.PageSetup.Orientation = wdOrientLandscape

Use VBS to copy from Notepad to Word

I'm trying to create a script to convert PDF to plain text, then copy the plain text into Word. (We do a lot of reformatting corrupt documents from scratch where I work.) I have a script that's working perfectly except for one thing: when pasting into Word, it doesn't paste the whole file. With longer files, I'm only getting part of the text.
'string to hold file path
Dim strDMM
strDMM = "[path]"
'make this directory if it doesn't exits
On Error Resume Next
MkDir strDMM
On Error GoTo 0
'get the file name to process
Dim TheFile
TheFile = InputBox("What is the file name?" & chr(13) & chr(13) & "(Example: [name].pdf)", "Name of File")
'declare some acrobat variables
Dim AcroXApp
Dim AcroXAVDoc
Dim AcroXPDDoc
'open acrobat
Set AcroXApp = CreateObject("AcroExch.App")
AcroXApp.Hide
'open the document we want
Set AcroXAVDoc = CreateObject("AcroExch.AVDoc")
AcroXAVDoc.Open "[path to desktop]" & TheFile, "Acrobat" 'users are instructed to save to the Desktop for ease of access here
'make sure the acrobat window is active
AcroXAVDoc.BringToFront
'I don't know what this does. I copied it from code online.
Set AcroXPDDoc = AcroXAVDoc.GetPDDoc
'activate JavaScript commands w/Acrobat
Dim jsObj
Set jsObj = AcroXPDDoc.GetJSObject
'save the file as plain text
jsObj.SaveAs strDMM & "pdf-plain-text.txt", "com.adobe.acrobat.plain-text"
'close the file and exit acrobat
AcroXAVDoc.Close False
AcroXApp.Hide
AcroXApp.Exit
'declare constants for manipulating the text files
Const ForReading = 1
Const ForWriting = 2
'Create a File System Object
Dim objFSO
Set objFSO = CreateObject("Scripting.FileSystemObject")
'read file and get text
dim objFile
set objFile=objFSO.OpenTextFile( strDMM & TheFile, ForReading)
Dim strText
strText=objFile.ReadAll
'Create a Word Object
Dim objWord
set objWord = CreateObject("Word.Application")
'make Word visible
With objWord
.Visible = True
End With
'Add method used to create a blank document
Dim objDoc
Set objDoc=objWord.Documents.Add()
'create a shorter variable to pass commands to Word
Dim objSelection
set objSelection=objWord.Selection
'type the read text into Word; this is the part that's failing
objSelection.TypeText strText
objFile.Close
I've tried multiple files with the same result. The funny thing is, it pastes the same material from file A each time, but when copying from file B, it pastes a different amount of material. In other words, if A gives me 8 pages of 60 on the first run, I get those same 8 pages each time. File B might give me 14 pages of 60, then it gives me the same 14 pages each time. This only changes if I delete material from the .txt file. If I delete several paragraphs from A, then run the script, I might get 12 pages. Then I get those same 12 every time. But there's no pattern (that I can discern) to predict where it cuts off.
I can't find any EOF characters, and when I read from notepad and write to notepad, the whole thing is copied perfectly. The problem is somewhere in the transfer to Word.
Is there something I'm missing? Is there a limit to the size of a string that Word can write with TypeText? (I would think that if that were the case, I wouldn't get documents of varying length, right? Shouldn't they all stop at n characters if that's the limit?)
I've read about additional libraries that let VBS work with the clipboard, but I'm a total noob and don't know if that's a more elegant solution or how to make it work. I'm also not sure that on my work computer I have the necessary access to install those libraries.
Any help is appreciated!
There is no need to read a file into Word, you can insert a text file from disk
Dim objWord
'Dim objDoc
Set objWord = CreateObject("Word.Application")
'make Word visible
With objWord
.Visible = True
'Add method used to create a blank document
.Documents.Add
.Selection.InsertFile FileNameAndPath
End With
The basic problem, which you hinted at, is that the String data type is limited to 65,400 characters. With an unknown file length, it is better to read in one line at a time and write it to Word. There is a good discussion of something similar here. The following code should help you get where you wan to go:
'read file and get text
dim objFile
set objFile=objFSO.OpenTextFile( strDMM & TheFile, ForReading)
'Don't do this!
'Dim strText
'strText=objFile.ReadAll
'Create a Word Object
Dim objWord
set objWord = CreateObject("Word.Application")
'make Word visible
With objWord
.Visible = True
End With
'Add method used to create a blank document
Dim objDoc
Set objDoc=objWord.Documents.Add()
'create a shorter variable to pass commands to Word
Dim objSelection
set objSelection=objWord.Selection
'Read one line at a time from the text file and
'type that line into Word until the end of the file is reached
Dim strLine
Do Until objFile.AtEndOfStream
strLine = objFile.ReadLine
objSelection.TypeText strLine
Loop
objFile.Close
Hope that helps!