How to save Word document using Excel VBA on Mac OS? - excel

I am trying to run an Excel VBA subroutine to save a Word document.
Language version: Word/Excel version 16.41
Operating system: Mac OS Mojave 10.14.6
I tried: (https://www.reddit.com/r/vba/comments/ivwxlw/trouble_with_path_when_saving_basic_word_document/)
(https://answers.microsoft.com/en-us/msoffice/forum/all/excel-vba-macro-to-save-as-basic-word-document/df78bf58-ec21-4502-abfe-bc3df1fca7ae)
I am starting from scratch on a different computer and operating system. I am now using Mac OS Majave 10.14.6 and Word/Excel version 16.41. I was able to open tools-references-and select the Word library, but now References is unhighlighted and unclickable. (it was briefly before also)
I encounter:
Run time error -2146959355 (80080005) Automation Error.
The line that needs debugging:
Set wdApp = New Word.Application
Option Explicit
Sub CreateBasicWordReportEarlyBinding()
Dim wdApp As Word.Application
Set wdApp = New Word.Application
With wdApp
.Visible = True
.Activate
.Documents.Add
With .Selection
.ParagraphFormat.Alignment = wdAlignParagraphCenter
.BoldRun
.Font.Size = 18
.TypeText "Best Movies Ever"
.BoldRun
.Font.Size = 12
.TypeText vbNewLine
.ParagraphFormat.Alignment = wdAlignParagraphLeft
.TypeParagraph
End With
Range("A2", Range("A2").End(xlDown).End(xlToRight)).Copy
.Selection.Paste
.ActiveDocument.SaveAs2 Environ("UserProfile") & "\Desktop\MovieReport.docx"
.ActiveDocument.Close
.Quit
End With
Set wdApp = Nothing
End Sub

There have been problems using COM Automation (which is what New Word.Application", CreateObject etc are doing) on the Mac versions of Office for some years now. You may have seen similar questions elsewhere.
The trouble is that not everyone seems to experience these problems, which suggests that they could result from a configuration issue. The usual suspect would be "something to do with Mac OS Sandboxing". However, I have never seen a support document by anyone, including Microsoft, that tells you how to fix that. I have done clean installs of Office on clean installs of Mac OS and encountered and reported the problems, and that's when I think the software author should really investigate the problem and provide fix or a workaround.
Here, (same Office version, but Mac OS Catalina 10.15.6) what I find is that...
The problems are a bit different depending on which application you are running or trying to automate.
In Excel, trying to use an early-bound object of type Word.Application always fails. So you cannot use
Dim wdApp As New Word.Document
or
Dim myApp As Word.Document
Set myApp = New Word.Document
(It doesn't matter whether or not you have defined the correct reference in VBE Tools->References. If you don't, you'll see see a compile-time error anyway and VBA won't actually run the code).
So you need
Dim wdApp As Object
and to use CreateObject (if Word is not already running or when you you need a new instance of Word, on Windows at least) or GetObject (when you want to connect to a/the existing instance of Word.
However, here I find that CreateObject only works sometimes, and I haven't been able to work out why. It always starts Word if it hasn't started, but sometimes it waits for Word to start and returns a reference to the Word object and sometimes it does not. Tests are not completely conclusive, but it actually looks as if it works a maximum of "every other time you call it in an Excel session", It looks to me as if Excel retains some state information that it should not and thinks it "knows" that WOrd has started when in fact it hasn't.
In contrast, GetObject seems to work OK. Normally it returns an error if Word has not started, but returns a reference to the Word object if it has. So I tried to use something like this
Dim wdApp As Object
On Error Resume Next
Set wdApp = CreateObject("Word.Application")
Err.Clear
If wdApp Is Nothing Then
Set wdApp = GetObject(,"Word.Application")
End If
But then I still sometimes get error 429 ActiveX component can't create object in the GetObject line - in those cases it looks as if CreateObject isn't waiting for Word to start.
So I looked at the possibility of Starting Word without using COM. There are a few ways you could try to do that on Mac, but the simplest is to use the MacScript function to run a bit of AppleScript to do it. It's simplest because all the code can be in the VBA Sub/Function - you don't need any external files.
MacScript is actually deprecated because of problems with Mac OS sandboxing. You are really supposed to use AppleScriptTask instead. But MacScript currently seems to do the job, except that it always raises a VBA error (which IMO it should not), so we have to mess around with VBA error trapping.
Here, the following code always works. For now.
Dim theApp As Object
On Error Resume Next
MacScript "tell application id ""com.microsoft.Word"" to activate"
Err.Clear
'On Error Goto problem ' you need to set this up
Set theApp = GetObject(,"Word.Application")
' just be careful
If theApp Is Nothing Then
Debug.Print "theApp Is Nothing"
Else
Debug.Print TypeName(theApp)
' get on with what you need to do
End If
The other thing I tried quite hard to do was see if I could then take advantage of early binding (for Intellisense etc.) by adding this code at the appropriate points:
Dim myApp As Word.Application
Set myApp = theApp
'or
Set myApp = theApp.Application
But that never worked. So I seem to be stuck with late binding.
if you find that you cannot use MacScript, you can use AppleScriptTask. At its simplest you put a text file called myStartWordScript.scpt in a folder in the user's "Library", here
~/Library/Application Scripts/com.microsoft.Excel
I used a script like this:
on myStartWord(dummy as text)
tell application id "com.microsoft.Word"
activate
end tell
return "Word has started"
end myStartWord
Then you can ditch some of that error heandling stuff and use VBA code like this:
Dim theApp As Object
Debug.Print AppleScriptTask("myStartWordScript","myStartWord","")
'On Error Goto problem ' you need to set this up
Set theApp = GetObject(,"Word.Application")
' just be careful
If theApp Is Nothing Then
Debug.Print "theApp Is Nothing"
Else
Debug.Print TypeName(theApp)
' get on with what you need to do
End If

See freeflow's comment, which should be posted as answer. In VBE, pick Tools > References > Microsoft Word 16.0 Object Library.

There's 2 ways you can automate word from Excel:
Early Binding: Add a reference to the microsoft word object library.
Late Binding: declare your variables as objects.
In your case I would use early binding to have access to intellisense.enter image description here

To find the proper syntax for saving to a Mac OS X folder :
open a file
record a macro
save the file (choose your folder)
stop the recording
edit the macro
see how Word translated it in VisualBasic
example with Word 16 (2019):
ActiveDocument.SaveAs2 FileName:= _
"/Users/myusername/anyfolder/nameofthefile" & DocNum & ".txt" _
, FileFormat:=wdFormatText, LockComments:=False, Password:="", _
AddToRecentFiles:=True, WritePassword:="", ReadOnlyRecommended:=False, _
EmbedTrueTypeFonts:=False, SaveNativePictureFormat:=False, SaveFormsData _
:=False, SaveAsAOCELetter:=False, Encoding:=65001, InsertLineBreaks:= _
False, AllowSubstitutions:=False, LineEnding:=wdCROnly

Related

Excel VBA Using GetObject for Word Document causes Source Application May Be Busy Error

Alright, so I'm try to reference an open Word document. But no matter what I do it stalls out and causes an error. The error takes 20-30 seconds before it pops up
"The object is not responding because the source application may be busy"
Dim oWord As Object
Set oWord = GetObject(, "Word.Application")
Debug.Print oWord.Documents.Count
Just a simple code block like above when I try Documents.Count it errors out. So I can't do anything with the GetObject object. Anyone have any clue on how to solve this problem?
Thanks
I've tried everything I can find on the Internet. I can open the file using CreateObject, but once it is open I cannot access it.
SOLVED
I'm an idiot. So I went to the task manager and it turns out there were like 20 Word instances that were created through my testing processes, so the GetObject was just timing out. When I closed all the instances, then opened one instance and ran the GetObject it worked and Documents.Count gave the correct answer.
Sorry for wasting your time!!
Your code works just fine for me - provided Word is running - returning a result after about 1 second. What it lacks is code to start Word if it isn't already running, in which case it errors out.
What you need is something like:
Dim wdApp As Object, bStrt As Boolean
' Test whether Word is already running.
On Error Resume Next
bStrt = False ' Flag to record if we start Word, so we can close it later.
Set wdApp = GetObject(, "Word.Application")
'Start Word if it isn't running
If wdApp Is Nothing Then
Set wdApp = CreateObject("Word.Application")
If wdApp Is Nothing Then
MsgBox "Can't start Word.", vbExclamation
Exit Sub
End If
' Record that we've started Word, so we can terminate it later.
bStrt = True
End If
MsgBox wdApp.Documents.Count
Perhaps you should check in Task Manager for an orphaned Word session running in the background. Other than that, you may need to restart Windows. If the problem persists, you may need to repair your Office installation.

Word gets stuck during export via Excel VBA

My Excel VBA script contains an export function which results in one Word document of about 12 pages.
On my private computer, this works.
On my company's laptop this seems to take too long and probably some kind of Word watchdog is triggered. Word gets stuck after about 75% of the code and the message "Word has stopped working" pops up.
I determined the point where it gets too much for Word to handle. As the export code is quite extensive and also contains several company and project details that I don't want to reveal, I prefer to not post it here.
Here is the snippet at which Word gets stuck:
ThisWorkbook.Worksheets("Backup - Do not change").Shapes("companyLogo").Copy
With wdFrontHeaderTable
.rows.Height=30
With .Cell(1,1).Range
.Paste
.ParagraphFormat.Alignment=0
End With
With .Cell(1,1).Range.InlineShapes(.Cell(1,1).Range.InlineShapes.Count)
.LockAspectRatio=msoTrue
.Width=120 'this one still works
End With 'here, the error occurs
End With
If I set one before that point and then run the two halves of code, one after another, it works.
If I uncomment the whole block, the error occurs in the next block.
The code does what it is supposed to do, even on the company laptop. I guess it just takes too long and the watchdog "thinks" Word was stuck.
Is there a way to disable the watchdog or another way to solve this?
I tried Application.Wait (1000).
Word is initialized by
Dim wdApp As Object
Dim wdDoc As Object
Set wdApp = CreateObject("Word.Application")
Set wdDoc = wdApp.Documents.Add

Run-time error -2147023170 (800706be) when copy-pasting images from Excel to Word

I am trying to copy/paste some images from my Excel sheet to a word file. Sometimes, it works flawlessly, but often I run into the great Run-time error '-2147023170 (800706be)': Automation error. The remote procedure call failed. message. Google showed my that I'm not alone with this error and that it often results from the fact that e.g. ranges are not precisely defined.I think they are in my project, however.
Here's my code:
Dim wdDoc As Object
Dim wdApp As Object
Set wdApp = CreateObject("Word.Application")
Set wdDoc = wdApp.Documents.Add
Dim wdImg As Object
ThisWorkbook.Worksheets("Backup - Do not change").Shapes("companyLogo").Copy
With wdDoc.Sections(1).Headers(2).Range
.PageSetup.DifferentFirstPageHeaderFooter = True
.Paste
Set wdImg = .InlineShapes(.InlineShapes.Count).ConvertToShape
With wdImg
'some specifications
End With
End With
ThisWorkbook.Worksheets("Backup - Do not change").Shapes("projectLogo").Copy
With wdDoc.Sections(1).Headers(2).Range
.Paste
Set wdImg = .InlineShapes(.InlineShapes.Count).ConvertToShape
With wdImg
'some specifications
End With
End With
Application.CutCopyMode = False
The error always occurs at .Paste. I already tried .PasteSpecial DataType:=8 and various other things but it didn't help. Any help is very welcome!
Okay so instead of pasting directly to the header range, I now created a table within the header and paste the images into two different cells. Since then I've successfully run the code for more than 10x so it seems like this fixed the issue (I hope it stays like this). Still not sure what caused it, though.
I want to add to this because this was one of the first posts I come across when having a similar issue. The solution at least for me was using copypicture and pastespecial as explained here:
Stack Overflow
Despite much searching this thread never showed up for me until I started to type a question and it showed up in the list of similar questions. Hopefully this can save someone else the massive headache that this was for me to solve.

How to release an Aspen object and clear memory

This is my first time using such forum.
I have exactly the same question as here:
How to release an object and clear memory in VBA
In this thread, the question was unfortunately not solved...
With Excel VBA I connect to another program (namely Aspen EDR). For that purpose I have an according Add-In installed. To access Aspen EDR I need to add an object. After I'm done I want to release the object to save some memory. First thing I tried is this:
Dim ObjEDR As BJACApp
Dim Path As String
Path = 'assume this is the correct path to the file i want to open
Set ObjEDR = New BJACApp ' Create the BJAC object
If Not ObjEDR.FileOpen(Path) Then
MsgBox "Can't open file!"
End If
'...
Set ObjEDR = Nothing
After I set the object nothing, Excel does not release the memory (as I can see in my task manager). Of course after a few hundred iterations (I have to open a lot of these files) I get an error message, that Excel is out of memory. I read a few threads and apparently nothing only deletes some kind of reference to the object but not the object itself, so I tried adding fileclose
'...
ObjEDR.FileClose
Set ObjEDR = Nothing
When executing the FileClose I can see that a little memory is released (0.5 of 3MB) but still there is a lot of memory accumulating.
Also when not using the "Now" it is not working and I get "runtime error'424': Object required" when executing Set ObjEDR = BJACApp
I also read about "pointers" that might cause the staying memory increase, but how can I find and clear/delete them?
Does anyone has an idea?
I would really appreciate it!
If .Quit (or the object's equivalent) and setting the object to Nothing is not working for you, then you could try relying on VBA's garbage collector to do the job.
Essentially what this means is that you would need to split the sub in two, have the main sub, and within that sub call the sub that will open and close your object. Hopefully, upon the second sub exiting, VBA will clean up those objects.
Sub Main()
Dim filePath As String
For Each [..] In [..] ' Or use a Do...Loop
filePath = 'assume this is the correct path to the file i want to open
openObj filePath 'call the sub below
Next [..]
End Sub
Sub openObj(ByVal Path As String)
Dim ObjEDR As BJACApp
Set ObjEDR = New BJACApp ' Create the BJAC object
If Not ObjEDR.FileOpen(Path) Then
MsgBox "Can't open file!"
End If
[...] 'your code to perform the needed actions with your obj
ObjEDR.FileClose
Set ObjEDR = Nothing
End Sub
I don't know anything about this object, but you should also try .Quit and .Close
Another method is to not create a new object for each path. Place the Set ObjEDR on the outside of your loop, and utilize the same object every time you open the new file.
Ok, to those who are interested:
The support of Aspen Tech told me that
ObjEDR.dispose()
should work, but just for versions above V8.4.
So this did not solved my problem and I built a workaround using MATLAB which opens and closes Excel after each run. So I loose time opening and closing the Excel file, but the memory of excel is not increasing until it stops working.

VBA Closing Excel Files

Say I have some VBA code in Access that uses excel for whatever reason. Sometimes I have trouble closing the file properly.
The code (I think) should look somewhat like this:
WBO.Close savechanges:=True
Set WBO = Nothing
XLO.Application.Quit
Set XLO = Nothing
rs.Close
db.Close
Here XLO is an excel object, WBO is a workbook object, rs is a DAO recordset and db is a DAO database. Even though the physical excel file closes there's still an "EXCEL.EXE" process occurring on my system, which stops me from running my program twice in a row. Does anyone know why this happens?
EDIT
I took out the rs.Close and then db.Close lines since I decided to manually export the data I was using from Access to Excel (there's too many rows and columns to copy each cell over efficiently). However, this didn't change the problem at hand.
Thank you,
Jesse Smothermon
There isn't an actual Excel object. Application is the top-level object but that Application object has an Application property which actually points to "the creator of the specified object". So trying to quit XLO.Application won't do what you think it should.
Presuming that XLO is of type Excel.Application then try just XLO.Quit instead of XLO.Application.Quit
Why not just:
application.displayalerts = false
WBO.save (or saveas whatever it matters)
WBO.close
set WBO = nothing
I don't see a memory problem with that...
Refer to this answer.
It worked for me.
Dim sKill As String
sKill = "TASKKILL /F /IM msaccess.exe"
Shell sKill, vbHide
If that works, mark the answer in the link with a ^, not mine.

Resources