Late Binding Vs Early Binding - excel

I've been using late binding code by using excel 2016, however when the earlier versions tried opening my created excel file, missing reference will happen and i have to remove it every time.
I thought late binding not suppose to be happened that way? My code as below :
Private Sub NTStep2a_Click()
Dim ws As Object
Set ws = ThisWorkbook.Sheets("Data Entry (A)")
Dim objWord As Object
Set objWord = CreateObject("Word.Application")
objWord.Visible = True
objWord.Documents.Open "C:\Users\" & Environ("username") & "\Desktop\xxx"
objWord.ActiveDocument.Unprotect Password:="xxx"
With objWord.ActiveDocument
objWord.ActiveDocument.Protect Password:="xxx", NoReset:=False, Type:=wdAllowOnlyFormFields
End With
Set objWord = Nothing
End Sub
Kindly advise.

Maybe you refer to some version of library which is not available.
For example, you use createObject("word.application.11") to create word, but word version 11 is not available.
You could try omit the version number, e.g. createObject("word.application").

Related

move selection to end of word document

i have a word document that has text in it, when the document opens the selection is in the very first line of the document so when I run the code below to add a new page the whole text moves to the new page, how do I move the selection to the end of the document so that when I add a new page the text does not move to the new page?
edit: tried below but does not work
"objSelection.EndKey Unit:=wdStory, Extend:=wdMove"
"objWord.Documents("letters.docx").Selected.EndKey Unit:=wdStory, Extend:=wdMove"
Sub exceltoword()
Dim objWord As Object
Set objWord = CreateObject("Word.Application")
objWord.Visible = True
objWord.Documents.Open "C:\Users\WORK\Desktop\letters.docx"
objWord.Activate
Set objSelection = objWord.Selection
'**MOVE TO END OF DOCUMENT BEFORE ADDING NEW PAGE**
'tried objSelection.EndKey Unit:=wdStory, Extend:=wdMove --- does not work
'tried objWord.Documents("letters.docx").Selected.EndKey Unit:=wdStory, Extend:=wdMove --- does not work
objSelection.InsertNewPage
objWord.Application.Quit
Set objWord = Nothing
End Sub
Your issue is a result of your use of late binding, declaring objWord As Object instead of setting a reference to the Word object library.
When using late binding you cannot use the enums or constants from the Word object library as Excel doesn't know what those represent. You either have to declare those constants yourself or use their underlying values.
Actually there is little value to using late binding in this instance. The only advantage to late binding is version independence, i.e. you can write code in a newer version and it will theoretically work in an older one. But that advantage is lost unless you also use late binding for the host application code as Office is usually installed as a package. It is better to use early binding when working with other Office applications and reserve late binding for other commonly used libraries, e.g. ADO or XML.
If you want to know more about late binding see https://rubberduckvba.wordpress.com/2019/04/28/late-binding/
I also noticed that you are not using Option Explicit at the top of the code module, as your code contains undeclared variables. To add this automatically to new modules open the VBE and go to Tools | Options. In the Options dialog ensure that Require Variable Declaration is checked.
You should also break the habit of using Selection. There is rarely any need to select anything when using VBA.
So your code should look similar to this:
Sub exceltoword()
Dim wdApp As Word.Application
Set wdApp = CreateObject("Word.Application")
wdApp.Visible = True
Dim wdDoc As Word.Document
Set wdDoc = wdApp.Documents.Open("C:\Users\WORK\Desktop\letters.docx")
wdDoc.Characters.Last.InsertBreak Type:=wdPageBreak
wdApp.Quit
Set wdApp = Nothing
End Sub

Not able to call second macro after first macro is generated

I have a few subs that works perfectly fine individually. However when I put few subs together to be called in one sub, it won't run properly. After first sub is called and generated, the second sub won't run and came out an error. I just don't get it how it won't run, please anyone tell me where went wrong. I tried adjusting the codes but it won't work.
Mail merge won't work for my project as I have thousands of data to be generated. Thank you in advance.
This sub below is to call sub test1 and test2 and came out an error
Sub callsubs()
test1
test2
End Sub
Here is my sub test1 and test2 is the same as test1 so I won't be putting it again.
Option Explicit
Const FilePath As String = "Z:\PJ General\Staff\Admin Dept\Ching Lu\AP LOAN v3 Test\Correspondences\"
Dim wd As New Word.Application
Sub Copy2word(bookmarkName As String, Text2Type As String)
'copy each cell to relevant Word bookmark
wd.Selection.GoTo What:=wdGoToBookmark, Name:=bookmarkName
wd.Selection.TypeText Text2Type
End Sub
Sub test1()
Dim doc As Object
Set doc = CreateObject("Word.Application")
Dim strName As String
strName = Sheet15.Range("C67")
wd.Visible = True
Dim dev_attn As String
Set doc = wd.Documents.Open(FilePath & "Step 2a LBS-LPPSA.doc", ReadOnly:=True)
doc.Unprotect Password:="stwppj312"
With wd.ActiveDocument
dev_attn = ThisWorkbook.Sheets("Data Entry B").Range("C809").Value
Copy2word "dev_attn", dev_attn
Call devref
Call stwpref
doc.SaveAs Filename:="C:\Users\" & Environ$("username") & "\Downloads\" & "Step2a " & strName & ".doc"
End With
wd.Quit
Set doc = Nothing
End Sub
In the code, you create the Word application object several times - once via Dim wd As New Word.Application (early binding; the instance is assigned to the global variable wd), and every time you run test1() and test2() via Set doc = CreateObject("Word.Application") (late binding; the instance is assigned to the local variable doc). At the end of each test1() and test2() procedure, you destroy the global wd instance via wd.Quit. So by running test1() and test2() procedures sequentially, after the first one finishes, the wd object (which you access, for example in wd.Visible = True) will no longer be bound to the Word.Application instance, hence the error.
Creating multiple instances of "Word.Application" is time-consuming and resource-intensive, so I recommend creating such an object once and using it in all procedures, and removing it when done. Accordingly, don't create a local instance of "Word.Application" inside each of test1() and test2() procedures, but use only the global one.
Dim wd As New Word.Application
...
Sub callsubs()
test1 ' without wd.Quit, without Set doc = CreateObject("Word.Application")
test2 ' without wd.Quit, without Set doc = CreateObject("Word.Application")
wd.Quit
End Sub
In addition, the command Set doc = CreateObject("Word.Application") in your procedures creates a local instance of "Word.Application" that is not used at all, but wastes time and resources. This happens as follows:
Set doc = CreateObject("Word.Application") ' a new instance of the "Word.Application" is created and bound with doc variable
...
Set doc = wd.Documents.Open(FilePath & "Step 2a LBS-LPPSA.doc", ReadOnly:=True) ' doc variable re-binding with opened Document
...
'The "Word.Application" instance hasn't been destroyed, it still lives in memory (see Task Manager, section Background Processes)
I recommend you remove the line Set doc = CreateObject("Word.Application")
It looks to me like the problem is that you've created your wd object as a global variable that you then quit in Test1. This will cause Test2 to have no wd to reference.
I would bring the wd declaration into the Test1 and Test2 and then pass it to Copy2word as a parameter instead. Something like this:
Sub Copy2word(bookmarkName As String, Text2Type As String, wd As Word.Application)
[Same code]
End Sub
Sub test1()
Dim wd As New Word.Application
...
Copy2word "dev_attn", dev_attn, wd
...
End Sub

Setting range in Word with VBA in Excel

How do I set a range in Word while opening that file with VBA in Excel?
Dim wordApp As Word.Application
Dim wordObject As Word.Document
Dim wordRange As Word.Range
Dim filePath As String
Dim fileName As String
filePath = "C:\Users\"
fileName = "somename.docx"
Set wordApp = CreateObject("Word.Application")
With wordApp
.Visible = True
.Activate
.WindowState = wdWindowStateNormal
End With
Set wordObject = wordApp.Documents.Open(filePath & fileName)
Set wordRange = Documents(fileName).Sections(1).Range
With wordRange
'code
End With
The line causing trouble:
Set wordRange = Documents(fileName).Sections(1).Range
Regardless of the string I put in this returns
4160 runtime error "Bad File Name"
If I use ActiveDocument instead of Documents(), I get
4248 runtime error: "This command is not available because no document is open".
The error persists even after opening multiple unsaved and saved Word docs whilst running the code, only to have the same error message show up.
Set wordRange = Documents(fileName).Sections(1).Range errors because Excel doesn't know what Documents is (or it resolves it to something other than Word.Documents)
To fix that, you'd use (just as you did in the previous line)
Set wordRange = wordApp.Documents(fileName).Sections(1).Range
That said, you've already Set the Document(filepath & filename) to wordObject, so use it:
Set wordRange = wordObject.Sections(1).Range
Also, Excel doesn't know wdWindowStateNormal, so a new Variant variable is created (unless you have Option Explicit, which you should, always) and assigned the default value 0. Which just happens to be the value of Word.wdWindowStateNormal so no harm done, but the code is misleading.
To fix, use
.WindowState = 0 'wdWindowStateNormal
I'm curious about the way you've created the object. Using early binding but instead of creating New Word.Application you use CreateObject
Was this an intentional decision?
What is the benefit?

Insert multiple images in MS Word bookmarks via Excel

I would want images to be inserted into bookmarks in MS Word document (.docx) with the use of Excel. I stumbled upon a Word VBA workaround that is almost perfect for the job EXCEPT that it is of course, a code that sits in Word (I just save it in the global template). The reason why I would need it to be in Excel is because I can't save the macro in the .docx file --- I can't afford to save it as a macro-enabled document as it will mess up with the existing VBA in Excel (Another person made it :). I did have exhausted all effort Googling but there is no exact solution for this. For reference, here is the 'modified' code that I was talking about. I copied it from user fumei in vbaexpress.com
Sub FillABookmark(strBM As String, strText As String)
Dim j As Long
With ActiveDocument
.Bookmarks(strBM).Range _
.InlineShapes _
.AddPicture FileName:=strText
j = ActiveDocument.InlineShapes.Count
.InlineShapes(j).Select
.Bookmarks.Add strBM, Range:=Selection.Range
End With
End Sub
Sub InsertScreenshots()
Call FillABookmark("Image_1", "C:\Users\Public\Documents\Image1.png")
Call FillABookmark("Image_2", "C:\Users\Public\Documents\Image_2.png")
Call FillABookmark("Image_3", "C:\Users\Public\Documents\Image_3.png")
End Sub
I would appreciate any kind of help :)
Update:
Shoutout to Imran :) Your code has been a great help, but I can't seem to work it off to work for multiple images,.. I can't even all of the things that my attempts did, but all of them sort of pastes the new images to one and the same bookmark. Plus a failing Office 365 to add to the dilemma,. I'm reinstalling it later and will on be available for comment tomorrow :( I'm out of my wits and tried to incorporate the looping feature in the original code that I posted. The following code is my failed attempt at it:
Sub FillABookmark(bookmarkname As String, imagepath As String)
Dim objWord As Object
Dim objDoc As Object
Set objWord = CreateObject("Word.Application")
objWord.Visible = True
objWord.Documents.Open "D:\test.docx"
Set objDoc = objWord.activedocument
With objDoc
.Bookmarks("test1").Select
.Shapes.AddPicture Filename:=imagepath
End With
With objDoc
.Bookmarks("test2").Select
.Shapes.AddPicture Filename:=imagepath
End With
With objDoc
.Bookmarks("test3").Select
.Shapes.AddPicture Filename:=imagepath
End With
End Sub
Sub InsertScreenshots()
Call FillABookmark("test1", "C:\Users\Public\Documents\image_1.png")
Call FillABookmark("test2", "C:\Users\Public\Documents\image_2.png")
Call FillABookmark("test3", "C:\Users\Public\Documents\iamge_3.png")
End Sub
If it's only the image that you want to add in a word document then use this,
Sub FillABookmark(bookmarkname As String, imagepath As String)
Dim objWord As Object
Dim objDoc As Object
On Error Resume Next
Set objWord = GetObject(, "Word.Application")
If objWord Is Nothing Then
Set objWord = CreateObject("Word.Application")
objWord.Visible = True
objWord.Documents.Open "D:\imran.docx"
End If
Set objDoc = objWord.activedocument
With objDoc
.Bookmarks(bookmarkname).Select
.Shapes.AddPicture Filename:=imagepath
End With
With objDoc
.Bookmarks(bookmarkname).Select
.Shapes.AddPicture Filename:=imagepath
End With
With objDoc
.Bookmarks(bookmarkname).Select
.Shapes.AddPicture Filename:=imagepath
End With
End Sub
Sub InsertScreenshots()
Call FillABookmark("test", "C:\Users\Public\Documents\1.jpg")
End Sub

Excel VBA - Cross Referencing Bookmark/Form Field to Word

I have very minimal knowledge about VBA but still learning as it goes.
I've been using bookmarks in the word in order to populate data from excel. However, due to the content that some data need to repeat in a document, I tried using Text Form Field/Bookmark and REF Field to duplicate the same data.
The problem came in when once I populated data to the word, the text form field/bookmark disappear which causes REF Field unable to track the data that was referred to, hence, the "Error! Reference source not found."
In conclusion, what I'm trying to do is to populate data from excel to a locked word document and at the same time to retain Text Field Form/Bookmark in order to let REF field to track and duplicate the same data.
Is there any way to retain the Text Field Form/Bookmark placeholder after data is populated to the word? Here's my code that I am unable to solve in excel VBA.
Appreciate your help in advance!
Private Sub CommandButton1_Click()
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("Sheet1")
Dim objWord As Object
Set objWord = CreateObject("Word.Application")
objWord.Visible = True
objWord.Documents.Open "C:\Users\" & Environ("username") & "\Desktop\XXX\XXX"
objWord.ActiveDocument.Unprotect Password:="xxx"
With objWord.ActiveDocument
Dim objBMRange As Range
Set objBMRange = .Bookmarks("pr1").Range.Text = ws.Range("C28").Value
objBMRange.Text = pr1
.Bookmarks.Add "pr1", BMRange
.Fields.Update
objWord.ActiveDocument.Protect Password:="xxx", NoReset:=False, Type:=wdAllowOnlyFormFields
End With
Set objWord = Nothing
End Sub
You were almost there. Very near, but you didn't get the Range object sorted out. Please try this code (only partially tested).
Private Sub CommandButton1_Click()
Dim Ws As Worksheet
Dim objWord As Object
Dim Mark As String
Dim Txt As String
Dim BmkStart As Long
Mark = "pr1"
Set Ws = ThisWorkbook.Sheets("Sheet1")
Txt = Ws.Range("C28").Value
Set objWord = CreateObject("Word.Application")
With objWord
.Visible = True
.Documents.Open "C:\Users\" & Environ("username") & "\Desktop\XXX\XXX"
With .ActiveDocument
.Unprotect Password:="xxx"
If .Bookmarks.Exists(Mark) Then
With .Bookmarks(Mark).Range
BmkStart = .Start
.Text = Txt
End With
.Bookmarks.Add Mark, .Range(BmkStart, BmkStart + Len(Txt))
End If
.Fields.Update
.Protect Password:="xxx", NoReset:=False, Type:=wdAllowOnlyFormFields
End With
End With
Set objWord = Nothing
End Sub
One point is that the Bookmark defines a Word.Range (different from an Excel.Range which you get when you specify no application while working in Excel). The other, that Bookmark defines a range but isn't a range itself, not even a Word.Range. Therefore you get or set its text by modifying it's range's Text property.

Resources