VBA Inserting Excel complexe spreadsheet in .doc document - vba

So I've been working on a word .dotm file that will combine several .doc and .xls documents into a single .pdf file.
Right now, I have two different problems, I will only detail the first one on this topic:
When inserting a complexe (very complexe) Excel sheet in my .doc document, the output is only a pile of meta data (Well mostly looks like it, if you prefer clearer language: it is a complete mess of characters and page breaks) instead of my file. I've looked for the entire day (really, I wasted my work day looking for answers) on the internet and even asked on MSDN forum (no answer at all) about this topic and everyone seems to have his code working like a charm.
Here is my code:
Sub MergeFiles()
Documents.Open FileName:="C:\test_cea\02.doc"
Selection.EndKey Unit:=wdStory
Selection.InsertFile FileName:="C:\test_cea\03.doc"
Selection.EndKey Unit:=wdStory
Selection.InsertFile FileName:="C:\test_cea\04.xls"
ActiveDocument.SaveAs2 FileName:="C:\test_cea\output.pdf", FileFormat:=wdFormatPDF
ActiveDocument.Close SaveChanges:=doNotSaveChanges
End Sub
I've tried a TREMENDOUS amount of things, from switching to opening the .xls first, to trying every single combination of parameters possible in my InsertFile() method and nothing works.
The most amusing part is: it works perfectly when trying to do it with Word UI, meaning Word can do it, but I'm doing it wrong somehow.

Here's the final answer to that question:
As Word cannot interpret an Excel file it is not possible to force file insertion this way.
Instead use the following code:
Sub MergeFiles()
Dim appExcel As Excel.Application
Dim wdDocument As Word.Document
Set appExcel = CreateObject("Excel.Application")
Set wdDocument = Documents.Open("mydoc.doc")
appExcel.Workbooks.Open("myxls.xls")
appExcel.ActiveWorkbook.Sheets(1).Range("Print_area").CopyPicture 'Copy picture prevents weird behavior from Word'
Selection.PasteSpecial Placement:=wdInLine, DataType:=wdPasteMetafilePicture
End Sub
Obviously this is a sample code that will do the whole process but the idea is to copy the Print Area (one must be defined, you can also use Sheets(1).UsedRange but this will be a problem if the Excel file is oddly formatted) as picture and paste it into Word. You can also simply copy it and paste it but it may mess up your output table formatting.
I don't even know why people down voted my question -_-
Anyway, if you encouter the same issue, simply tell me if this code works.

Related

How to copy text from one document to another with same formatting?

I have this code to copy some text from one document to a new one.
For Each rng In docSource.SpellingErrors
docNew.Range.InsertAfter rng.text & vbCr
Next
Bus this is not copying the source format.
I'm trying with the following line but I get error
Expected function or variable
docNew.Range.InsertAfter rng.PasteAndFormat(wdPasteDefault) & vbCr
How can I do this? Thanks in advance.
Below some test text with errors.
When you create a Microsoft Word document for other people to read , it's important to spot and correct any speling mistakes
or gramatical errors you've made. You can let Word's spelling and grammmar
checkers suggest corrections automaticaly while you working , or you can check the spelling and gramar in the the file all
at once when you're finishes writing your document . Microsoft Word 2010 come with some dictionary of standardd grammar and spellings, but they are not comprehensive.
To transfer content from one Word document to another it's usually best to use Range.FormattedText rather than the Clipboard.
So something like this
Set docNewRange = docNew.Content
For Each rng In docSource.SpellingErrors
docNewRange.FormattedText = rng.FormattedText
docNewRange.Collapse wdCollapseEnd
docNewRange.InsertAfter vbCr
docNewRange.Collapse wdCollapseEnd
Next

Insert Building Blocks using Word VBA

I'm trying to insert a formatted table that I have saved in word named "DV Table" as part of the building blocks using VBA. I need this table to be inserted at the 13th paragraph of the word document.
Here's my code below. The first 3 lines just sets the selection to be at the 12th paragraph and create a new paragraph (13) after that. The last line of code is to insert the table. But when I run this, it gives the error.
Compile Error: Sub or Function not defined
I guess that this is not the proper way of defining the location. Would like some help on this. Thanks.
ActiveDocument.Paragraphs(12).Range.Select
Selection.EndKey Unit:=wdLine
Selection.Paragraphs.Add
ActiveDocument.AttachedTemplate.BuildingBlockEntries("DV Table" _
).Insert Where:=Paragraphs(13).Range.Select, RichText:=True
The Where parameter requires a Range object. There are two problems with Paragraphs(13).Range.Select
it's a method - it's an action, selecting something, not returning an object
Paragraphs(13) isn't "fully qualified" - VBA doesn't know what it is/what is meant.
One possibility would be
ActiveDocument.Paragraphs(13).Range
Notice ActiveDocument. preceding Paragraphs: this "fully qualifies" Paragraphs(13) - it tells VBA to what that belongs. And, since Where requires a Range object, Paragraphs(13).Range should be a correct "target" (I have not tested your code).
Generally, it's preferable not to work with Selection, just with Range objects. There's usually no need to actually select something using VBA. An alternative to the code snippet in the question could be
Dim rng As Word.Range
Set rng = ActiveDocument.Paragraphs(13).Range
rng.Collapse wdCollapseEnd 'like pressing right-arrow for a selection
rng.InsertParagraphAfter
rng.Collapse wdCollapseStart ' like pressing left-arrow for a selection
'rng.Select ' for testing / demo purposes
ActiveDocument.AttachedTemplate.BuildingBlockEntries("DV Table" _
).Insert Where:=rng, RichText:=True
In this case, the selection in the document does not change. There's no screen flicker; and code executes more quickly. This way of working takes getting used to, but once one is familiar with it, it's much easier to recognize what the code should be doing... Selection is rather vague as to what is being manipulated, especially if there's a lot of code using it.

Accessing Word fields and auto texts from embedded Excel

I have some Word documents/templates with embedded Excel sheets/charts. Is it possible from Excel VBA to access data (bookmark contents, fields, auto texts) that is stored in the Word document?
An example of data could be patient ID stored in a Word auto text.
The VBA code must be inside the embedded Excel, not in the Word template, as I can't modify this.
The VBA code will probably be launched by double-clicking the embedded sheet, then pressing a shortcut key, but this is not part of my question.
Try
Sub HelloWord()
Dim wordApp As Object
Set wordApp = GetObject(, "Word.Application")
MsgBox wordApp.Activedocument.FullName
End Sub
Once you've got a handle on the the wordApp, you can access all the objects in the model as normal.
The downvote might be because this doesn't sound like a very efficient solution - might it be better to get the Excel data into a Word document or format the Excel document in an acceptable way. You're invoking two pretty chunky apps here to do one thing.

Using vba to copy the contents of a word document into another word document

I haven't used VB for years, so please forgive me if this turns out to be obvious. I'm trying to write a word vba macro for use in a template which will display a userform and then import the contents of fileA.docx, fileB.docx, or fileC.docx depending on the userform. (After that I'm going to use bookmarks to fill in some form data, I don't know if that's relevant). Files A, B, and C will contain text with some basic formatting such as lists, but nothing fancy.
The solutions I've seen online can copy the contents of file to a new file, but ideally I would like to import the entirety of one of those files into the new, currently unnamed file that I'm getting from the template. I think where I'm running into problems is with switching the selection to one of those files, and then back to the new unnamed document, though I could use a hand to make sure I'm copying correctly as well.
Update: I was making things too hard, though the answers here got me pointed in the right direction (thanks!). In the end I just did
ThisDocument.Activate
Selection.InsertFile("fileA")
which gives me the raw dump of everything that I wanted.
Using commands such as these you can switch between which Document you're using and copy and paste elements:
ThisDocument.Activate 'Sets the main document active
Documents("Name.doc").Activate 'Activates another document
You can insert, copy and paste things in and out of documents using copy commands.
ThisDocument.Range.InsertAfter("String") 'Insert text
Selection.WholeStory 'Select whole document
Selection.Expand wdParagraph 'Expands your selection to current paragraph
Selection.Copy 'Copy your selection
Documents("name.doc").Activate 'Activate the other document
Selection.EndKey wdStory 'Move to end of document
Selection.PasteAndFormat wdPasteDefault 'Pastes in the content
You can then go and format such, or copy and paste them with original formatting from before.
Here is a significant improvement (I think) you will want to incorporate because it:
does not use the clipboard and thus does not make your macro vulnerable to the user changing the contents of the clipboard while your macro is running
does not use a file and thus greatly improve the speed by eliminating I/O and eliminates the potential of having to deal with file system security/permissions, etc. Please do not use .InsertFile() if you are looping through documents you will slow yourself down. Use it once, at the end -only if you have to. The example below shows how to accomplish the same result without using .InsertFile()
The idea is to transfer some portion of text found in 1 source document, to a destination document that is different than the source, and keep the source formatting.
To accomplish the above (skipping the code to open documents):
For Each oTable In oDoc_Source
'the above could have been anything that returns a Range object
'such as: ActiveDocument.Content.Find.Execute ....
'...
'logic here to identify the table, or text, you are looking for
'...
'I can't believe the MS Dev Center folks could only think
'of .InsertFile(), which is the last resort I would go for,
'especially if your code runs on a web server [concurrent web requests]!
'SAFEST
'(no user interference on clipboard possible, no need to deal with file i/o and permissions)
'you need a reference to Document.Content,
'as the act of obtaining a reference "un-collapses" the range, so the below 3 lines must be in that order.
Set oRange = oDoc_DestinationDoc.Content
oRange.Collapse Direction:=wdCollapseEnd
oRange.FormattedText = oTable.Range
'BRUTE, AND PRONE TO RANDOM ERRORS AND HANGS DUE TO USER INTERFERENCE WITH CLIPBOARD
'find a way to implement WIHTOUT using the CLIPBOARD altogether to copy the below range object
'it will be easier for PC users to use the clipboard while the macro runs
'and it will probably be safer for the output of this macro to remain uncorrupted
'oTable.Range.Copy
'Set oRange = oDoc_DestinationDoc.Content
'oRange.Collapse Direction:=wdCollapseEnd
'oRange.Paste
'THE BELOW DOES NOT WORK
' '1) - cannot add a range from another document
' 'adds only text, not the formats and not the table layout
' oTable.Range.TextRetrievalMode.IncludeFieldCodes = True
' oTable.Range.TextRetrievalMode.IncludeHiddenText = True
' oDoc_DestinationDoc.Content.InsertAfter oTable.Range
'
' '2) - cannot add a range from another document
' oDoc_DestinationDoc.Content.Tables.Add oTable.Range, iRowMax, iColMax
'
' '3) - only puts in plain text, and it replaces the range without the .Collapse call
' oDoc_DestinationDoc.Content.Text = oTable.Range
Record a macro...
start in the source document
press ctrl-a to select everything
press ctrl-c to copy it to the clipboard
switch to the target document
press ctrl-v to paste into the document
stop recording
or (assuming word 2007 or later)
start in the target document with the source document closed
on the ribbon click insert > object > Text from file...
navigate to the source document
click the insert button
stop recording
I prefer the second version so I should have put it first
I was doing the same thing, tried to select the other document, copy and paste. But it didn't worked (I received an error probably because some other application was using the clipboard, but I am not sure.). So I did a little search and found the perfect solution on Microsoft Dev Center.
https://msdn.microsoft.com/en-us/vba/word-vba/articles/selection-insertfile-method-word
Selection.Collapse Direction:=wdCollapseEnd
Selection.InsertFile FileName:="C:\TEST.DOC"
'set current doc name and path
Dim docName As String: docName = ActiveDocument.name
Dim filepath As String: filepath = ActiveDocument.Path
'create a new file
Documents.Add
'get the path of a current file
ChangeFileOpenDirectory filepath
'insert content of current file to newly created doc
Selection.InsertFile _
FileName:=docName, _
Range:="", _
ConfirmConversions:=False, _
Link:=False, _
Attachment:=False
'open prompt to save a new file
With Dialogs(wdDialogFileSaveAs)
.name = docName & "-copy"
.Show
End With

WORD 2010 Macro for Editing Headers & Footers

I have only basic VBA experince and my prior Macro experence was primarily with WORD 2003. Recording Macros used to take GoToFooter (or Edit Footer) Menu Commands and allow subsequent editing. In WORD 2010, this (and many other) commands do not "record" to the Macro (yet when in Record mode, I do get into Edit Footer function).
A research of various VBS options shows several ways to create Footers and to make global Footer setting changes within Macro. However If I simply want to Revise the Company name within the Footer (for example), I can find no way to do this within a Macro subroutine.
This subroutine is one that I would call from the Main Macro that is stepping through each file in a Folder (& subfolders). I have the main Macro functioning.
Does WORD 2010 Macro-VBA preclude simple Edit-Footer function?
Thanks in advance
So, thanks to Issun, here is my solution:
`
Sub Sub_FTR_0()
'
ActiveDocument.ActiveWindow.ActivePane.View.SeekView = wdSeekCurrentPageFooter
For i = 1 To ActiveDocument.Sections.Count
'REM: INSERT Code from RECORD MACRO recorded when editing one Footer correctly
Selection. [[xxx]], etc.
If i = ActiveDocument.Sections.Count Then GoTo Line1
ActiveDocument.ActiveWindow.ActivePane.View.NextHeaderFooter
Line1:
Next
ActiveWindow.ActivePane.View.SeekView = wdSeekMainDocument
End Sub
`
Here is a way you can access the headers/footers via VBA. As you can see, it's rather complicated syntax to get to something so simple :p there
Sub EditHeadersAndFooters()
Dim i As Long
For i = 1 To ActiveDocument.Sections.Count
With ActiveDocument.Sections(i)
.Headers(wdHeaderFooterPrimary).Range.Text = "Foo"
.Footers(wdHeaderFooterPrimary).Range.Text = "Bar"
End With
Next
End Sub
Here is a link to example code on how to change the headers in every file in a folder. It takes a different approach and I have never tried it, but for your reference: http://www.vbaexpress.com/kb/getarticle.php?kb_id=45
This worked for me for all pages in the document.
word.ActiveDocument.Sections(1).Headers(1).Range.Text = "Put the header here"