Opening and then breaking links to a Word document from Excel - vba

I have an excel spreadsheet that is linked to multiple Word documents (.docx), which act as templates.
I have written a macro that opens the required word template from excel (the template chosen is dependent on the value of cell M17). The links in the word template update automatically as word opens. I am then trying to break the links of the document that I opened. This is what I have so far:
Function FnOpeneWordDoc()
Dim objWord
Dim objDoc
Dim path As String
path = Range("M17")
Set objWord = CreateObject("Word.Application")
Set objDoc = objWord.Documents.Open("*file_path*" & path & ".docx")
objWord.Visible = True
Application.Wait (Now + TimeValue("0:00:30"))
objDoc.Fields.Unlink
End Function
I suspect that it isn't working because the macro is trying to break the links before the document has fully loaded (and therefore the existing links haven't had a chance to update?), which is why I added the wait. Unfortunately this doesn't seem to be the solution.

The above code would have been fine, but I didn't realise that the code had to be different if the text was in textboxes.
I struggled to break the links within textboxes, and kept getting run-time error 438. However, I found a workaround:
I wrote a sub in the word documents:
Sub Unlink
Selection.Fields.Unlink
End Sub
I then called this macro from my excel document:
Sub FnOpeneWordDoc()
Dim objWord
Dim objDoc
Set objWord = CreateObject("Word.Application")
Set objDoc = objWord.Documents.Open("filename")
objWord.Visible = True
For i = 1 To objDoc.Shapes.Count
objDoc.Shapes(i).Select
objDoc.Application.Run ("unlink")
Next
End Sub

Related

Check if Word document closed from Excel VBA

I'm performing several prints of embedded Word document witch has some fields linked to some cells, by my PrintOut macro, in a For..Next loop, as below.
I need after each print task, that the program wait for document to close and then doing the next print.
In this situation I receive error. Can anyone help ?
Sub contract()
Dim i As Integer
For i = 1 To 100
Cells(Sheets("SheetName").ListObjects("StaffInfo").ListRows.Count + 9, 8).Value = i
General.PrintIt ("EmbeddedDoc") 'Doc has many linked fields
Next i
End Sub
Print method
Sub PrintIt(P As String)
Dim objWord As Object
Dim ObjDoc As Object
Dim Oshp As Object
Application.ScreenUpdating = False
ActiveSheet.OLEObjects(P).Activate
Set objWord = GetObject(, "Word.Application")
objWord.Visible = False
Set ObjDoc = objWord.ActiveDocument
ObjDoc.Fields.Update
For Each Oshp In ObjDoc.Content.ShapeRange
Oshp.TextFrame.TextRange.Fields.Update
Next
ObjDoc.PrintOut Background:=False
ObjDoc.PrintOut
objWord.Quit SaveChanges:=False
Application.ScreenUpdating = True
End Sub 'Print it
Introduced problem was solved by this code.
Above code do open and close embedded word document, 100 times, and that problem was happening in close document.
Exactly, I cant understand why closing document immediately after printout command that where after open and update fields, generating that error.
Thus I cleaned the problem ask!
By integrating "PrintIt" method in "Contract" method that is parent of that, without calling "PrintIt" for each document printout, embedded document opens each one, perform doc links updating and printing 100 times in for next loop and close word app and document, at last, each one too.
In short, I cant find reason of problem in several Open-Print-Close document in order immediately; But i change the algorithm to Open-Several print-Close and problem been cleaned!
Sub contract()
Application.ScreenUpdating = False
Sheets("SheetName").Unprotect
'Declare variables
Dim i As Integer
Dim objWord, ObjDoc As Object
'Core
ActiveSheet.OLEObjects("Contract").Activate
Set objWord = GetObject(, "Word.Application")
objWord.Visible = False
Set ObjDoc = objWord.ActiveDocument
For i = 1 To 100
Cells(x, y).Value = i 'A specific cell that
' word embedded document fields are linked to
'corresponding fields they values change
'by changing this cell.
ObjDoc.Fields.Update
ObjDoc.PrintOut Background:=False
ObjDoc.PrintOut
Next i
objWord.Quit SaveChanges:=False
Sheets("SheetName").Protect AllowFiltering:=True
End Sub

How to use Words selection methods through Excel VBA

In Word VBA you are able to set and move the cursor position by using the Selection.MoveLeft, Selection.MovRight etc...
However while trying to use this same method in Excel VBA I get an error saying "Object doesnt support this property or method."
I have imported the Word Object Library reference.
How am I able to move the cursor position on the Word document using VBA on the Excel application. Any help will be greatly appreciated.
Code:
Set Doc = ActiveDocument.Content
With Doc.Find
.Execute FindText:="*", ReplaceWith:="NEW*"
End With
Selection.HomeKey Unit:=wdStory
Selection.MoveDown Unit:=wdParagraph, Count:=11
Selection.MoveRight Unit:=wdWord, Count:=4
Selection.MoveRight Unit:=wdWord, Count:=2, Extend:=wdExtend
Selection.Font.Bold = False
Selection.Font.Name = "Arial"
Selection.Font.Size = 9
Your problem will go away if you would rephrase your question, "move the cursor position on the Word document using VBA on the Excel application". You can't move the cursor in a Word document using the Excel application.
When you open an Excel workbook you load an instance of the Excel application. You can use this same instance to open several workbooks. It also contains Excel VBA with all objects, methods and functions of the Excel application. This instance has no name.
But you could create another instance of the Excel application with code like
Dim XlApp as Excel.Application
Set XlApp = New Excel.Application
The new instance you have thus created has all the facilities of the first instance but is completely separate form it. You can open workbooks in it with code like
Dim Wb as workbook
Set Wb = XlApp.Workbooks.Add([Template])
Now, if you have set a reference to the MS Word Object Library you can create a Word application using similar code, for example,
Dim WdApp as Word.Application
Set WdApp = New Word.Application
This could be the only instance of MS Word running on your computer or it could be a new instance created in addition to other instances already running. This instance knows all the objects and methods of MS Word.
You can control both instances, XlApp and WdApp, in the same VBA project, but you should be careful to differentiate the objects. Both Excel and Word have a Range object for example. They are very different animals. You can specify, for example,
Dim xlRng As Excel.Range
Dim wdRng As Word.Range
Dim MyRng As Range
In this example, MyRng will be an Excel range if your VBA project is an Excel project. While you have both applications running this kind of defaulting will cause hair loss.
Dim Wb As Workbook
Dim Doc As Document
don't cause similar confusion because there is no Workbook object in MS Word and no Document object in MS Excel. VBA will use the correct application automatically, provided it is available.
When manipulating the WdRng you will have access to all the methods of the Word Range object, including Move, but there is no Address property, for example, which is a property of the XlRng.
Dealing with the two Selection objects is problematic. You will have to activate a window or document or workbook, and VBA will know which Selection object you mean by looking at the application running in the selected window. You won't have that problem if you specify the document/workbook object and use the WdRng or XlRng objects to manipulate your data.
As your code stands the keyword "selection" refers to the currently selected cell in excel, not the cursor position in your Word document. And the Excel Selection object does not have move methods. You might have more success using Range rather than selection: You example code translates as
With ActiveDocument
With .Content.Find
.Execute FindText:="*", ReplaceWith:="NEW*"
End With
with .Paragraphs(4).Range.Words(5).Font
.Bold = false
.name = "Arial"
.size = 9
end with
With .Paragraphs(4).Range.Words(6)
.Bold = false
.name = "Arial"
.size = 9
end with
end with
'Something Basic
'Session of word
'Existing document
Sub fromaWordDoc0()
Dim wdApp As Word.Application
Dim wdDoc As Word.Document
Set wdApp = CreateObject("word.application")
wdApp.Visible = True
Set wdDoc = wdApp.Documents.Add("C:\Documents\words.docx")
With wdApp.Selection
wdApp.Selection.MoveRight Unit:=wdWord, Count:=4
End With
Set wdApp = Nothing: Set wdDoc = Nothing
End Sub

Inserting text in a embedded Word template, at a bookmark, from excel. "error 13 Type mismatch" error

I am currently working on a project that have one word template embedded in one excel template.
A button in excel was created for opening the embedded word template, exporting the data from excel and puting them into word by using bookmarks in word template. The issue is that word report can be generated only once, because the text will be insert into the original bookmark rather than overwrite the previous data.
I'm trying to export a named field from excel(CoverPageRCA) and copy it into an embedded word template using a bookmark (bkmtable1_1).
I get:
run-time error 13 Type mismatch
that occurs at the following line:
Set bkMark = ActiveDocument.Bookmarks(bookmarkname).Range
I searched the web and spent almost 24 hrs on it. Can anybody please suggest a solution?
Option Explicit
Dim WD As New Word.Application
Dim RCAcell1 As Range
Sub CreateRCAReports1()
Dim wordDoc As Word.Document
Dim oleObj As oleObject
Dim WordApp As Word.Application
WD.Visible = True
Set oleObj = ActiveWorkbook.Sheets("CoverPageRCA").OLEObjects(1)
oleObj.Verb xlVerbPrimary
Set WordApp = oleObj.Object.Application
With WordApp
.Visible = True
.Activate
Set wordDoc = .Documents(1)
End With
'-------------------------------------------------------
ThisWorkbook.Sheets("CoverPageRCA").Activate
ActiveSheet.Range("B2").Select
Set RCAcell1 = ActiveSheet.Range(ActiveCell, ActiveCell.End(xlDown))
'go to each bookmark and type in details
CopyCell1 "bkmtable1_1", 1
Set WD = Nothing
End Sub
'----------------------------------------------------------
Sub CopyCell1(bookmarkname As String, RowOffset As Integer)
Dim bkMark As Range
'clear content on each bookmark and add new bookmarK
Set bkMark = ActiveDocument.Bookmarks(bookmarkname).Range
bkMark.Select
bkMark.Text = "dsfsf"
ActiveDocument.Bookmarks.Add bookmarkname, bkMark
'copy each cell to relevant Word bookmark
WD.Selection.GoTo What:=wdGoToBookmark, Name:=bookmarkname
WD.Selection.TypeText RCAcell1(RowOffset, 1).Value
End Sub
Looking at the code, the issue is on declaration of bkMark:
Dim bkMark As Range
The range object exists on both Excel and Word (different objects), and as the code above runs on excel, it will declare bkMark as an Excel Range object, not a Word Range object.
But the range returned on the line below is a Word range, causing the type mismatch error.:
Set bkMark = ActiveDocument.Bookmarks(bookmarkname).Range
To fix this issue, you must declare bkMark as a Word range,:
Dim bkMark As Word.Range

How to save an embedded Word document in an Excel workbook as a separate file using VBA

I am creating a workbook that will populate an embedded Word document template with pictures, and then save the document elsewhere, without editing the embedded template.
However, when I try to save the document, I get a Run-Time Error 4605 telling me:
"The SaveAs method or property is not available because this document is being edited in another applicator"
This is the sub to open the template:
Sub OpenWord()
'Opens the template when the main function first runs
Set WDObj = Sheets("Template").OLEObjects("Template")
WDObj.Activate
WDObj.Object.Application.Visible = False
Set WDApp = GetObject(, "Word.Application")
Set WDDoc = WDApp.ActiveDocument
End Sub
After this a main sub runs which populates the template, then when I try to save the document using:
WDDoc.SaveAs "myDocument.doc", FileFormat:=wdFormatDocumentDefault
I get the error.
Please has anyone encountered this error before/ know to to fix it, I have done much Googling which still has not gotten me anywhere.
I tested the following, which worked on my system/installation:
Sub OpenWord()
'Opens the template when the main function first runs
Dim WDObj As Object
Dim WDApp As Object
Set WDApp = GetObject(, "Word.Application")
Set WDObj = Sheets("Template").OLEObjects("Template")
WDObj.Activate
WDObj.Object.Application.Visible = False
WDApp.ActiveDocument.SaveAs ("YourFilename.doc")
Set WDObj = Nothing
Set WDApp = Nothing
End Sub

Selecting and copying Outlook email body with a VBA macro

I'm a beginner to VBA macros in Excel, and this is the first attempt in Outlook, but here's what I am trying to do:
In Outlook 2010, assign a macro to a button that, when pushed,
Gets the entire body of the active email
Copies the body including all formatting and html to the clipboard
Opens a new word document
Pastes the content of the clipboard to this word doc
Clears the clipboard
So far, all I have are steps 1 and 3 (and I wonder if I'm going about this the wrong way in step 1) below:
Sub pasteToWord()
Dim activeMailMessage As Outlook.MailItem 'variable for email that will be copied.
Dim activeBody
Dim clearIt As String 'Intended to eventually clear clipboard.
'Code to get to the body of the active email.
If TypeName(ActiveExplorer.Selection.Item(1)) = "MailItem" Then _
Set activeMailMessage = ActiveExplorer.Selection.Item(1)
activeBody = activeMailMessage.Body
'MsgBox activeBody
'^This displayed what I want in plaintext form,
'so I think im on the right track
'Code to copy selection to clipboard
'Code to open new Word doc
Set WordApp = CreateObject("Word.Application")
WordApp.Documents.Add
WordApp.Visible = True
'Code to paste contents of clipboard to active word document
'Code to clear clipboard
End Sub
Any guidance to fill in the blanks above would be much appreciated.
Edit:
Here is what has come the closest so far, thanks to David Zemens. I think I am missing some reference though, because my compiler doesn't understand "DataObject" for the ClearClipboard() function. It does copy and paste into word with formatting though, as is below (though I had to comment out the last function to avoid errors):
Sub pasteToWord()
Dim WordApp As Word.Application 'Need to link Microsoft Word Object library
Dim wdDoc As Word.Document 'for these to be understood by compiler
Dim activeMailMessage As Outlook.MailItem
Dim activeBody As String
If TypeName(ActiveExplorer.Selection.Item(1)) = "MailItem" Then
'Get a handle on the email
Set activeMailMessage = ActiveExplorer.Selection.Item(1)
'Ensure Word Application is open
Set WordApp = CreateObject("Word.Application")
'Make Word Application visible
WordApp.Visible = True
'Create a new Document and get a handle on it
Set wdDoc = WordApp.Documents.Add
'Copy the formatted text:
activeMailMessage.GetInspector().WordEditor.Range.FormattedText.Copy
'Paste to the word document
wdDoc.Range.Paste
'Clear the clipboard entirely:
Call ClearClipBoard
End If
End Sub
Public Sub ClearClipBoard()
Dim oData As New DataObject 'object to use the clipboard -- Compiler error,
'I think I'm missing a reference here.
oData.SetText Text:=Empty 'Clear
oData.PutInClipboard 'take in the clipboard to empty it
End Sub
This method will copy the formatted text from the selected mailitem, and paste it in to word document:
Dim WordApp As Word.Application
Dim wdDoc As Word.Document
Dim activeMailMessage As MailItem
If TypeName(ActiveExplorer.Selection.Item(1)) = "MailItem" Then
'Get a handle on the email
Set activeMailMessage = ActiveExplorer.Selection.Item(1)
'Ensure Word Application is open
Set WordApp = CreateObject("Word.Application")
'Make Word Application visible
WordApp.Visible = True
'Create a new Document and get a handle on it
Set wdDoc = WordApp.Documents.Add
'Copy the formatted text:
activeMailMessage.GetInspector().WordEditor.Range.FormattedText.Copy
'Paste to the word document
wdDocument.Range.Paste
'Clear the clipboard entirely:
Call ClearClipBoard
End If
NOTE Clearing the clipboard entirely can be done pretty easily with a function like the one described here:
Public Sub ClearClipBoard()
Dim oData As New DataObject 'object to use the clipboard
oData.SetText Text:=Empty 'Clear
oData.PutInClipboard 'take in the clipboard to empty it
End Sub
You can use the Word object model when dealing woth item bodies.
Word is used as an email editor in Outlook. The WordEditor property of the Inspector class returns an instance of the Document class from the Word object model which represents the Body of your email. See Chapter 17: Working with Item Bodies for more information.
As you may see, there is no need to use any extra tools or classes (Clipboard and etc.). You can copy the document using built-in mechanisms or save the document as is.