Tweaking Mail Merge Code

Ark68

Well-known Member
Joined
Mar 23, 2004
Messages
4,564
Office Version
  1. 365
  2. 2016
Platform
  1. Windows
So I finally found some success with this code ... but it can be improved. Perhaps I can tap into the expertise of the knowledgeable friends here at Mr. Excel.

Code:
Sub report()
Set ObjWord = CreateObject("Word.Application")
Set Odoc = GetObject("E:\SA09-02\Reports10\SO10-DR_HPL.Doc")
ObjWord.Visible = True
Odoc.Application.Visible = True
Odoc.mailmerge.Destination = wdsendtonewdocument
Odoc.mailmerge.Execute
Set ObjWord = Nothing
Set Odoc = Nothing
End Sub

1) I have been told Word constants (wdOpenFormatAuto and wdsendtonewdocument) are not valid in Excel, so I need to declare them or use literals. What does this mean, and how is it accomplished.

2) The main mail merge document, in this case is SO-DR_HPL.doc, is one of 15 different reports each with their own unique SQL query. Rather than repeating this same code 15 different times with the only difference being the path, is their a means I can substitute the file name with a variable? The variable would equal the value of cell F21 in my active worksheet.

3) This code will display two word documents ... one is the main mail merge document (SO10DR_HPL.doc), and the second is the product of that merge (the completed document). How would I go about just closing the main mail merge document? How can I ensure that the user focus goes to the new Word document rather than remaining on the Excel worksheet?

4) And finally ... not necessarily Excel related, but maybe can be done from Excel code, how can I automatically name the produced Word document so that the user doesn't have to try to remember the format of the filename. I need to specify a file name based on the report, but it has to be placed into a directory for the date of the report (represented in cell A1 of the worksheet) So, if the date was 21-Aug-10, I want this produced document automatically named DR_HPL.doc in a folder (if not there, make it!) 21-Aug-10?

Thanks folks!!

Jenn
 

Excel Facts

Excel Can Read to You
Customize Quick Access Toolbar. From All Commands, add Speak Cells or Speak Cells on Enter to QAT. Select cells. Press Speak Cells.
1) I have been told Word constants (wdOpenFormatAuto and wdsendtonewdocument) are not valid in Excel, so I need to declare them or use literals. What does this mean, and how is it accomplished.

Once you have created an instance of Word via Excel everything concerning Word is preceded with the object variable name. We write code as if we are actually using Word, and use Word macro syntax.

It is often easier to start by recording macros in Word and include them in the Excel code - when all they need is the additional reference.
Make sure in Excel Editor you got to Tools/References and include the 'Microsoft Word xx Object Library'.

Word macros are not quite so easy to record as Excel because the mouse doesn't always record things. The best method is to use the keyboard for *everything* you want to record in Word. I still begin most projects by recording macros of various stages. Not only does it cut down typing errors, but it gets over the "blank sheet" stage.

Putting the line
x = wdOpenFormatAuto
into a module pressing F8 to start the macro, hover mouse pointer over the variable, shows me its value is zero.

These are system variable names exclusive to VBA, as compared with our personal variable names we make up.
You could therefore equally as well use 0 (zero) instead. Perhaps you can begin to see the necessity of using variable names meaningful (to you) instead of numbers or whatever. With the mentioned reference to Word in Excel (or any other Office application code module) it will understand this variable name too.

'wdsendtonewdocument' does not appear in Word 2000. It looks like this is from a later version. It also looks like the poster of the code did not really know what he/she was doing. I could be wrong. If it had been available it would have been capitalised/formatted correctly like the other one. Unfortunately a lot of code on the web is useless because users just copy/paste someone else's without testing it first. The example you have picked up could be such. This is an obvious error ...

Code:
    ' these 2 lines mean exactly the same in your code
    ObjWord.Visible = True
    Odoc.Application.Visible = True

So do not use "Reserved words" for your variable names in code - ie. names that VBA already uses for something else eg. Sheet, Document, Row, Column .......
We often get away with it to start with, but bigger projects fail "inexplicably" at a later stage. We do not tend to look for bugs in code that is already "working".

Need to get into good habits with formatting code etc. Not only does it get faster with practice, but you will come back and understand it 12 months later if you (or someone else) need to make changes. You only need to see some of the garbage that appears here to see what I mean. What you have posted is not bad. Needs correct indentation.

======================================================================================================
2) The main mail merge document, in this case is SO-DR_HPL.doc, is one of 15 different reports each with their own unique SQL query. Rather than repeating this same code 15 different times with the only difference being the path, is their a means I can substitute the file name with a variable? The variable would equal the value of cell F21 in my active worksheet.
Please see code below. A subroutine would be good for this. you will see why.
3) This code will display two word documents ... one is the main mail merge document (SO10DR_HPL.doc), and the second is the product of that merge (the completed document). How would I go about just closing the main mail merge document? How can I ensure that the user focus goes to the new Word document rather than remaining on the Excel worksheet?
Please see code below
4) And finally ... not necessarily Excel related, but maybe can be done from Excel code, how can I automatically name the produced Word document so that the user doesn't have to try to remember the format of the filename. I need to specify a file name based on the report, but it has to be placed into a directory for the date of the report (represented in cell A1 of the worksheet) So, if the date was 21-Aug-10, I want this produced document automatically named DR_HPL.doc in a folder (if not there, make it!) 21-Aug-10?
Please see code below
Code:
'=============================================================================
'- BASIC EXCEL CODE TO USE WORD. SHOWS BASIC USE OF A VARIABLE LOOP
'- ALSO HOW TO CLOSE AN INSTANCE OF WORD - WHICH WILL OTHERWISE REMAIN IN MEMORY
'- otherwise could use up a lot of system memory especially during development
'- NB. Need to close Word (etc.) in the same way as we do it manually
'- Best to record Word macros first to get the code
'=============================================================================
'- variables here can be shared by all subroutines
Dim ExcelSheet As Worksheet     ' Excel worksheet object
Dim WordApp As Object           ' Word application object
Dim WordDoc As Object           ' variable document object
Dim WordDocName As String       ' variable document name
Dim MyDate As String            ' today's date
Dim d As Integer                ' loop counter
Dim MyFolder As String          ' target document folder
'=============================================================================
'- MAIN ROUTINE
'- Document names in Excel range A1 to A3. Run from this worksheet (don't need name)
'- Makes a new set of Word documents with today's date in the file name
'=============================================================================
Sub test()
    '-------------------------------------------------------------------------
    '- INITIALISE VARIABLES
    Set ExcelSheet = ActiveSheet
    Set WordApp = CreateObject("Word.Application")  ' start at the top level
    WordApp.Visible = True
    WordApp.Activate                        ' bring to top
    MyFolder = "F:\TEST\"                   ' here with final " \ ""
    MyDate = Format(Date, "dd-mm-yyyy")     ' make date string
    '-------------------------------------------------------------------------
    '- LOOP WORKSHEET TO GET NAMES
    For d = 1 To 3
        WordDocName = ExcelSheet.Cells(d, 1).Value & ".doc" ' get name
        MAKE_WORD_DOCUMENT      ' CALL SUBROUTINE
    Next
    '-------------------------------------------------------------------------
    '- FINISH - close everything & clear object variables
    'ActiveDocument.Close   ' not needed. all documents have been closed here
    WordApp.Quit            ' close Word
    Set ExcelSheet = Nothing
    Set WordDoc = Nothing
    Set WordApp = Nothing
    MsgBox ("Done")
    '-------------------------------------------------------------------------
End Sub
'=============================================================================
'=============================================================================
'- SUBROUTINE : CODE TO MAKE & SAVE A NEW DOCUMENT
'- Would not necessarily use a subroutine for such a small amount of code,
'- but it shows the method.
'- Don't always need to have a Document Object - but better in larger
'- projects requiring more code. Saves typing the object name each time.
'- Private Sub does not show in the macro list
'=============================================================================
Private Sub MAKE_WORD_DOCUMENT()
    '-------------------------------------------------------------------------
    '- APPLICATION LEVEL
    '-------------------------------------------------------------------------
    With WordApp            ' saves keep writing the variable name
        .Documents.Add      ' new empty document
        '- ADD SOME TEXT
        .Selection.TypeText Text:="THIS IS A TEST DOCUMENT " & MyDate
        '---------------------------------------------------------------------
        '- DOCUMENT LEVEL
        '---------------------------------------------------------------------
        Set WordDoc = ActiveDocument
        With WordDoc
            '-----------------------------------------------------------------
            '- SAVE & CLOSE
            .SaveAs Filename:=MyFolder & WordDocName & " " & MyDate
            '-----------------------------------------------------------------
            '- could be '.Close' addition for information
            .Close savechanges:=False ' or True. stops "save" message
            '-----------------------------------------------------------------
        End With
        '---------------------------------------------------------------------
    End With
    '-------------------------------------------------------------------------
End Sub
'============ end of subroutine ==============================================
 
Last edited:
Upvote 0
Brian, a fantastic explanation. I appreciate the effort you put into your thorough reply.

I am playing with the code you provided to see how things work in action. I'm stalled though with an "object required" error on the line ...
Rich (BB code):
 .Documents.Add      ' new empty document

BTW ... I am using Excel 2003 SP3, so 'wdsendtonewdocument' has worked successfully in my code.

Since my initial post, I have referred to some online resources (Google! LOL) and managed to get my mail merge/Excel component kinda working. I may integrate your logic into my code as there are still some errors causingme frustration.

Rich (BB code):
Sub report()
Set ObjWord = CreateObject("Word.Application")
'Set Odoc = GetObject("E:\SA09-02\Reports10\SO10-DR_HPL.Doc")

' open the main mail merge document based on the name contained in F21 (path + report name). This cell is volatile based on which of the 15 possible reports available
Set Odoc = ObjWord.documents.Open(Range("f21").Value)

Odoc.Application.Visible = True Word visible
Odoc.mailmerge.Destination = wdsendtonewdocument  'merge to new document
Odoc.mailmerge.Execute 'execute mail merge
Odoc.Close False ' close main mail merge document, keep produced document open

mypath = "e:\SA09-02\Workorders\" & Format(Date, "dd-mmm-yy")' creat path to save produced document 
If Len(Dir(mypath, vbDirectory)) = 0 Then MkDir mypath ' make the directory if it doesn't exist
odoc2.SaveAs mypath & "\" & (Range("a1").Value & ".doc") ' save the document in the directory created and call it the "value in cell A1".doc

'Odoc.Application.Quit  ' close Word

Set ObjWord = Nothing
Set Odoc = Nothing
End Sub

Error 1 (first highlighted line)- "Run-time error '5852' : Requested object is not available."
Error 2 (second highlighted line) - ""Run-time error '424' : Object required."

Code works well if the first erronous line is simply
Set Odoc = GetObject("E:\SA09-02\Reports10\SO10-DR_HPL.Doc")

I of course am grateful for all replies and advice!!

jenn
 
Upvote 0
You are still not indenting your code correctly.
If you have any more code in a message than you have there it is unlikely to get a reply. We need to be able to read it easily so formatting is important. It is hard enough trying to understand someone else's code anyway. The comments etc. are a big plus. See how my code doesn't go outside the box.

Although on the face of it your code should work I am surprised that you are not using the exact same method as I have supplied. Presumably my code does work on your machine ? There are reasons why I suggest this method instead of numerous other possibilities.;)

The VB Editor needs Tools/Reference to "Microsoft Word xx Object Library"
 
Last edited:
Upvote 0
Code:
Set Odoc = ObjWord.Documents.Open Filename:="YourName.doc"
Set Odoc = ObjWord.Documents.Open Filename:=  _
       Cstr(Sheets("Sheet1").Range("f21").Value)
HTH. Dave
 
Upvote 0
Hi Brian,

Thank you for your support. Next round of code I promise to improve the formatting!!

I was all pumped to replace my existing code with your suggestion, and I had embarked on that journey but got caught up in the error mentioned with the .documents.add line and was unable to test beyond that to see how it worked, and adapt to my needs accordingly.

As I pondered support for that problem, I continued to work on my existing code ... as basically, it was giving me success for the most important function ... the integration of Word mail merge with my Excel database. The areas I'm struggling with now are superficial ... user ease ....

The easiest workaround for loading up variable file names is to write repetitive working code 15 times with the filename being the only difference. But if I can simplify by using a variable ... it will only ease things.

The easiest way to save the file in a specific location with a specific name, is to simply get the user to do that. But, I'd prefer not to have to rely on them doing that for reasons of consistency.

Dave has posted some information in the interim ... I continue to overcome the hurdles in both coding options until I find one that works.

Thanks again for your help, I am not intentionally trying to frustrate anyone, just looking for supportive direction. :)

Jenn
 
Upvote 0
Code:
Set Odoc = ObjWord.Documents.Open Filename:="YourName.doc"
Set Odoc = ObjWord.Documents.Open Filename:=  _
       Cstr(Sheets("Sheet1").Range("f21").Value)
HTH. Dave

Thank you Dave ...

Did you leave me two different options here? Or are both lines needed to do the same thing? I'm reading the first setting of odoc to open just a static filename ... not variable. Odoc=YourName.doc?

Then I read the second line as also assigning odoc a value, but in this case, it is volatile ... seting odoc to equal whatever is in cell F21 of sheet1.

If that is the case, then I need the latter. It contains a syntax error I'm working on now to isolate before I can test it further.

Jenn
 
Upvote 0
Rich (BB code):
'+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 
' An Excel based routine to open one of 15 different Word mail merge documents,
' merge information from the Excel datasource, close the main mail merge document after
' merge has finished, and save the resulting file in a directory defined by the report's date,
' with a filename determined by the report's name.
'+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Sub report()

  'define variables 

     Set ObjWord = CreateObject("Word.Application")
     'Set Odoc = GetObject("E:\SA09-02\Reports10\SO10-DR_HPL.Doc") ' this works but limits the report to only one specified merge document
     set Odoc = ObjWord.Documents.Open Filename:= _
         Cstr(Sheets("Sheet1").Range("f21").Value)  'opens the mail merge document as defined in cell F21 of the active worksheet. F21 includes the path and filename of the main mail merge document.
     set odoc2 = ' stuck here ... don't know how to define odoc2 which will be the document produced by the merge

     MsgBox Odoc.FullName 'temporary - what report is being called
     ObjWord.Visible = True 'Word application is visible to the user
     'Odoc.Application.Visible = True (redundant line - to be removed)
     
     Odoc.mailmerge.Destination = wdsendtonewdocument 'create new document
     Odoc.mailmerge.Execute 'perform merge
    
 ' Close main mail merge document

          Odoc.Close False 'not sure what this does
 
     'save produced document
   
          mypath = ("e:\SA09-02\Workorders\" & Range("a1").Value) 'A1 holds a date value representing the date of the data in the report
          If Len(Dir(mypath, vbDirectory)) = 0 Then MkDir mypath 'creat edirectory if it doesn't exist
          odoc2.SaveAs mypath & "\" & (Range("c1").Value & ".doc")'save the file as the value held in C1 of the worksheet as a .doc in the directory created above

     'clean up
     
     Set ObjWord = Nothing
     Set Odoc = Nothing

End Sub

When the code executes the line in red, the application lags, becomes somewhat unresponsive and gets into an unbreakable loop of "Microsoft Office Excel is waiting for another application to complete an OLE action."

The only way I can break this is by ending the WINWORD.exe process in Windows task manager.

Augh! This is getting painful!

Jenn
 
Upvote 0
Jenn please accept my apologies... I should have tested it first. My previous thread did offer 2 different methods to open a .doc (the first static the second variable). However, the variable code syntax was incorrect. This works. Dave
Code:
Set Odoc = ObjWord.Documents.Open _
          (Filename:=CStr(Sheets("Sheet1").Range("F21").Value))
ps. Have you considered just making 1 Word template and then sending the XL info to it?
 
Last edited:
Upvote 0
I think we are getting to the stage where the problem may not be an Excel one at all. I don't think any of us can see an error in your code.

1. I have noticed that when Create Object etc. code fails we often need to reboot the computer. So do this first.

2. I suggest you copy/paste my code - which is complete and will run with a couple of changes - into a *new empty workbook* module. Make sure the module has reference to the Word Object Library. Put "test1",Test2" and "test3" into cells A1:A3. Change "MyFolder = "F:\TEST\" " to a valid drive. Run and see what happens. You should get 3 new Word documents in the folder.

3. If the above works, it may be you have a corrupted file and will need to take measures to make a new clean one. Come back for instructions on this. It is not just a matter of copying things.

4. It may be a system problem. Have a look at this recent post
http://www.mrexcel.com/forum/showthread.php?p=2288098#post2288098

5. There may be problems with the other documents you are using.
 
Last edited:
Upvote 0

Forum statistics

Threads
1,215,420
Messages
6,124,803
Members
449,190
Latest member
cindykay

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top