Consulting

Page 1 of 2 1 2 LastLast
Results 1 to 20 of 23

Thread: Use Excel To Open Word

  1. #1
    VBAX Tutor jo15765's Avatar
    Joined
    Oct 2011
    Posts
    281
    Location

    Use Excel To Open Word

    I have several employees and each employee has a table in a access 2000 database with a primary key defined. What I am wanting is to be able to build a form in excel, that has two boxes, one for the Employee name, and the other for the ID. Then a press button, and once this button is pressed it will open the word doc that is in let's say EmployeeName field on the form, and run a mail merge with the ID that is in the IDRequested field on the form.

    I have all of these steps set up manually, ie the access database is built, the word doc with mail merge set up etc. I just would like to try to automate it and make it as simple as enter the employee name, enter the ID requested an Bam, there is what you are looking for.

    I have this code that will open word for me, I just don't know how to pass the two parameters....
    [vba]
    Dim wdApp As Word.Application, wdDoc As Word.Document

    On Error Resume Next
    Set wdApp = GetObject(, "Word.Application")
    If Err.Number <> 0 Then 'Word isn't already running
    Set wdApp = CreateObject("Word.Application")
    End If
    On Error GoTo 0

    Set wdDoc = wdApp.Documents.Open("C:\temp\anyolddoc.doc")

    wdApp.Visible = True

    End Sub

    [/vba]
    Last edited by Aussiebear; 10-27-2011 at 03:16 PM. Reason: adjusted the code tags for the correct usage

  2. #2
    VBAX Guru Kenneth Hobs's Avatar
    Joined
    Nov 2005
    Location
    Tecumseh, OK
    Posts
    4,956
    Location
    Doing it manually is the first step. In fact, you are almost done. Of course this could all be done in MSWord but doing it in Excel is what we are here for. After you complete your project, please post the code here if you don't mind. This helps others by having real world examples.

    Are the ID's not in the same record as the Names? I can see a case where you might have two John Does but different IDs. Your SQL should limit records to ID most likely.

    Record a macro in MSWord where you do the merge. Then adapt that code for Excel. To get the ID and/or Names, you can do that in listbox controls on the Sheet or a Userform with listbox controls by use of ADO methods.

    See this link for an example doing mail merge to MSWord from Excel. The key is to pass the correct SQL string. http://www.excelforum.com/excel-prog...rom-excel.html

    For ADO methods, see: http://www.erlandsendata.no/english/...php?t=envbadac and Ron's examples, http://www.rondebruin.nl/tips.htm.

    In this thread, http://www.vbaexpress.com/forum/showthread.php?p=167033, I showed how to use ADO to fill a listbox control in a userform from an MDB file. Similar to that, I did it in ActiveX listbox controls. I attached a spreadsheet to show both listbox control methods. To test it, you will need the readily available NWind.mdb file as explained in the thread and replace the paths in the code routines.

    For more information and examples see:
    'Word 's Catalogue/Directory Mailmerge facility (the terminology depends on the Word version). _
    To see how to group records with any mailmerge data source supported by Word, _
    check out my Microsoft Word Catalogue/Directory Mailmerge Tutorial at:
    ' http://lounge.windowssecrets.com/ind...owtopic=731107
    ' or
    ' http://www.gmayor.com/Zips/Catalogue%20Mailmerge.zip
    Attached Files Attached Files

  3. #3
    VBAX Tutor jo15765's Avatar
    Joined
    Oct 2011
    Posts
    281
    Location
    I am not sure how to get a macro in word to record what I am doing. It is set up currently that when you open the worddoc, let's take Mark for example when I double click on Mark.doc it opens, and then it opens the access database and automatically asks me for the id I want to view in word. How could I record a macro that catches those steps?

  4. #4
    VBAX Guru Kenneth Hobs's Avatar
    Joined
    Nov 2005
    Location
    Tecumseh, OK
    Posts
    4,956
    Location
    It has been awhile since I did that. Why not start the recording in MSWord and then do a File > Open rather an open via Explorer or other method?

  5. #5
    VBAX Tutor jo15765's Avatar
    Joined
    Oct 2011
    Posts
    281
    Location
    I tried opening word and recording a macro to catch what goes on "behind the scenes" but the macro record looses it becuase once the ID is entered it opens a new instance of word, and that "New" instance is not the active.document

    Because opening the word document only opens the template, I then still have to enter the ID that I wish to "merge". I was able to capture the code through a macro that actually "merges" the template with the ID Document and that is:
    [vba]
    With ActiveDocument.MailMerge
    .Destination = wdSendToNewDocument
    .MailAsAttachment = False
    .MailAddressFieldName = ""
    .MailSubject = ""
    .SuppressBlankLines = True
    With .DataSource
    .FirstRecord = wdDefaultFirstRecord
    .LastRecord = wdDefaultLastRecord
    End With
    .Execute Pause:=True
    End With
    [/vba]
    Last edited by Aussiebear; 10-27-2011 at 03:18 PM. Reason: adjusted the code tags for the correct usage

  6. #6
    VBAX Guru Kenneth Hobs's Avatar
    Joined
    Nov 2005
    Location
    Tecumseh, OK
    Posts
    4,956
    Location
    You need to get the string for the SQLStatement. Record a simple merge to get what you need. e.g. Open a new file, add one field, do the merge.

    I used a txt file for this merge example as a standard routine in MSWord's VBA. The FRM file is the DOC file of course. Notice how I suppressed the initial merge in the Documents.Open. I initially did this project in WordPerfect for a consultant fee. They then asked for an MSWord solution and I gave it to them but they never paid for that. Oh well, so much for consulting.

    Once you have the SQL string, that can easily be added to this routine.

    [VBA]Sub MergeRun(frmFile As String, datFile As String, _
    Optional bClose As Boolean = True, Optional bPrint As Boolean = True, _
    Optional iNoCopies As Integer = 1)
    If Dir(frmFile) = "" Or Dir(datFile) = "" Then Exit Sub

    'On Error GoTo endnow
    Application.DisplayAlerts = wdAlertsNone

    'Open form file and associate data file
    Documents.Open frmFile, False, True, False
    ActiveDocument.MailMerge.MainDocumentType = wdFormLetters
    ActiveDocument.MailMerge.OpenDataSource name:=datFile, _
    ConfirmConversions:=False, ReadOnly:=False, LinkToSource:=True, _
    AddToRecentFiles:=False, PasswordDocument:="", PasswordTemplate:="", _
    WritePasswordDocument:="", WritePasswordTemplate:="", Revert:=False, _
    Format:=wdOpenFormatAuto, Connection:="", SQLStatement:="", SQLStatement1 _
    :="", SubType:=wdMergeSubTypeOther
    'Merge to a new document
    With ActiveDocument.MailMerge
    .Destination = wdSendToNewDocument
    .SuppressBlankLines = True
    With .DataSource
    .FirstRecord = wdDefaultFirstRecord
    .LastRecord = wdDefaultLastRecord
    End With
    .Execute Pause:=False
    End With

    If bPrint = True Then
    Application.PrintOut FileName:="", Range:=wdPrintAllDocument, Item:= _
    wdPrintDocumentContent, Copies:=iNoCopies, Pages:="", PageType:=wdPrintAllPages, _
    ManualDuplexPrint:=False, Collate:=True, Background:=True, PrintToFile:= _
    False, PrintZoomColumn:=0, PrintZoomRow:=0, PrintZoomPaperWidth:=0, _
    PrintZoomPaperHeight:=0
    End If

    If bClose = True Then
    ActiveDocument.Close False
    ActiveDocument.Close False
    End If
    endnow:
    Application.DisplayAlerts = wdAlertsAll
    End Sub

    [/VBA]

    Of course this routine needs tweaked to add the MSWord references to use it as a standard Excel routine.

  7. #7
    VBAX Tutor jo15765's Avatar
    Joined
    Oct 2011
    Posts
    281
    Location
    And the SQL string is just simply the SQL from the query that the mail merge calls, correct?

    Here is a snippet of the SQL for my access query..And ID is the prompt that displays as soon as you open Richard.doc so that once you enter the ID it pulls in all of the data from the query.
    [vba]
    SELECT tbl_Richard.ID, tbl_Richard.FName, tbl_Richard.lName, tbl_Richard.phone...
    FROM tbl_Richard
    WHERE (((tbl_Richard.ID)=[ID]));
    [/vba]
    Last edited by Aussiebear; 10-27-2011 at 03:18 PM. Reason: adjusted the code tags for the correct usage

  8. #8
    VBAX Guru Kenneth Hobs's Avatar
    Joined
    Nov 2005
    Location
    Tecumseh, OK
    Posts
    4,956
    Location
    Right, it should be fairly similar. What you will do is to rebuild the string that will replace the [ID] with the value from the selection list in Excel for that ID that matches the Name that you need.

    I did that one project several years ago so I would have to make up a new example to see the exact syntax.

  9. #9
    VBAX Tutor jo15765's Avatar
    Joined
    Oct 2011
    Posts
    281
    Location
    I am wanting the ID to be entered into a text box on form in Excel. So I would have to say something like ID = Textbox1.Value or something similar to that, correct?

  10. #10
    VBAX Guru Kenneth Hobs's Avatar
    Joined
    Nov 2005
    Location
    Tecumseh, OK
    Posts
    4,956
    Location
    Right. Try a hard coded string first but it may go something like:
    [vba]s = "SELECT tbl_Richard.ID, tbl_Richard.FName, tbl_Richard.lName, tbl_Richard.phone FROM tbl_Richard WHERE (((tbl_Richard.ID)=" & "'" & Textbox1.value & "')))"[/vba] more or less. Note the single quotes around the value.

    If I get time, I will see if I can make up a quick example using nwind.mdb in an MSWord file using an SQL string in my MergeRun routine. Note how I set the path to the datFile in MergeRun which in this case would be the MDB file.

  11. #11
    VBAX Guru Kenneth Hobs's Avatar
    Joined
    Nov 2005
    Location
    Tecumseh, OK
    Posts
    4,956
    Location
    Here is my simple recorded MSWord VBA mailmerge code. In particular, note this syntax:
    [VBA]ActiveDocument.MailMerge.DataSource.QueryString = _
    "SELECT * FROM `Employees` WHERE `EmployeeID` = 3" & ""[/VBA]

    [VBA]Sub Macro4()
    '
    ' Macro4 Macro
    '
    '
    ActiveDocument.MailMerge.MainDocumentType = wdFormLetters
    ActiveDocument.MailMerge.EditMainDocument
    ActiveDocument.MailMerge.OpenDataSource Name:= _
    "C:\MyFiles\Access\Nwind.mdb", ConfirmConversions:=False, ReadOnly:=False _
    , LinkToSource:=True, AddToRecentFiles:=False, PasswordDocument:="", _
    PasswordTemplate:="", WritePasswordDocument:="", WritePasswordTemplate:= _
    "", Revert:=False, Format:=wdOpenFormatAuto, Connection:= _
    "Provider=Microsoft.ACE.OLEDB.12.0;User ID=Admin;Data Source=C:\MyFiles\Access\Nwind.mdb;Mode=Read;Extended Properties="""";Jet OLEDB:System database="""";Jet OLEDB:Registry Path="""";Jet OLEDB:Engine Type=4;Jet OLEDBatabase Locking Mode=0;Jet OLEDB:Global Par" _
    , SQLStatement:="SELECT * FROM `Employees`", SQLStatement1:="", SubType:= _
    wdMergeSubTypeAccess
    ActiveDocument.MailMerge.EditMainDocument
    ActiveDocument.MailMerge.Fields.Add Range:=Selection.Range, Name:= _
    "EmployeeID"
    Selection.TypeParagraph
    ActiveDocument.MailMerge.Fields.Add Range:=Selection.Range, Name:= _
    "LastName"
    Selection.TypeParagraph
    ActiveDocument.MailMerge.Fields.Add Range:=Selection.Range, Name:= _
    "FirstName"
    ChangeFileOpenDirectory "X:\MSWord\MailMerge\KenExample\"
    ActiveDocument.SaveAs2 FileName:="KenExample.docx", FileFormat:= _
    wdFormatXMLDocument, LockComments:=False, Password:="", AddToRecentFiles _
    :=True, WritePassword:="", ReadOnlyRecommended:=False, EmbedTrueTypeFonts _
    :=False, SaveNativePictureFormat:=False, SaveFormsData:=False, _
    SaveAsAOCELetter:=False, CompatibilityMode:=14
    ActiveDocument.MailMerge.DataSource.QueryString = _
    "SELECT * FROM `Employees` WHERE `EmployeeID` = 3" & ""
    ActiveDocument.Save
    ActiveDocument.MailMerge.DataSource.QueryString = _
    "SELECT * FROM `Employees` WHERE `EmployeeID` = 3" & ""
    With ActiveDocument.MailMerge
    .Destination = wdSendToNewDocument
    .MailAsAttachment = False
    .MailAddressFieldName = ""
    .MailSubject = ""
    .SuppressBlankLines = True
    With .DataSource
    .FirstRecord = wdDefaultFirstRecord
    .LastRecord = wdDefaultLastRecord
    End With
    .Execute Pause:=True
    End With
    ActiveDocument.SaveAs2 FileName:="1.docx", FileFormat:=wdFormatXMLDocument _
    , LockComments:=False, Password:="", AddToRecentFiles:=True, _
    WritePassword:="", ReadOnlyRecommended:=False, EmbedTrueTypeFonts:=False, _
    SaveNativePictureFormat:=False, SaveFormsData:=False, SaveAsAOCELetter:= _
    False, CompatibilityMode:=14
    ActiveWindow.Close
    ActiveWindow.Close
    Application.Quit
    End Sub
    [/VBA]

  12. #12
    VBAX Guru Kenneth Hobs's Avatar
    Joined
    Nov 2005
    Location
    Tecumseh, OK
    Posts
    4,956
    Location
    I put it all together for you in the XLSM file with an example DOCX. I used ADO to fill a combobox with the LastName, FirstName, EmployeeID from the Employees table in the Northwind database. I parsed the ID name from the string value in the combobox to build the SQL string. You will need to get nwind.mdb and change the paths accordingly. There are a few more routines in it than you really need. Look at the Sheet1 code which contains the code for the two command buttons.

    Here is one place to get mwind.mdb. http://www.microsoft.com/download/en....aspx?id=19704
    Attached Files Attached Files

  13. #13
    VBAX Guru Kenneth Hobs's Avatar
    Joined
    Nov 2005
    Location
    Tecumseh, OK
    Posts
    4,956
    Location
    I updated the MergeRunMDB routine to:
    [VBA]'Add Tools > References... > Microsoft Word Word 14.0 Object Libraray
    Sub MergeRunMDB(frmFile As String, datFile As String, _
    sSQL As String, _
    Optional bClose As Boolean = False, Optional bPrint As Boolean = False, _
    Optional iNoCopies As Integer = 1)

    Dim wd As Word.Application, doc As Word.Document

    If Dir(frmFile) = "" Or Dir(datFile) = "" Then Exit Sub

    On Error Resume Next
    Set wd = GetObject(, "Word.Application")
    If wd Is Nothing Then
    Set wd = CreateObject("Word.Application")
    End If
    wd.Visible = False
    On Error GoTo 0
    wd.Application.DisplayAlerts = wdAlertsNone

    'Open form file and associate data file
    Set doc = wd.Documents.Open(frmFile, False, True, False)
    With doc
    .MailMerge.MainDocumentType = wdFormLetters
    .MailMerge.OpenDataSource Name:= _
    datFile, ConfirmConversions:=False, ReadOnly:=False _
    , LinkToSource:=True, AddToRecentFiles:=False, PasswordDocument:="", _
    PasswordTemplate:="", WritePasswordDocument:="", WritePasswordTemplate:= _
    "", Revert:=False, Format:=wdOpenFormatAuto, Connection:= _
    "Provider=Microsoft.ACE.OLEDB.12.0;User ID=Admin;Data Source=datfile;Mode=Read;Extended Properties="""";Jet OLEDB:System database="""";Jet OLEDB:Registry Path="""";Jet OLEDB:Engine Type=4;Jet OLEDBatabase Locking Mode=0;Jet OLEDB:Global Par" _
    , SQLStatement:=sSQL, SQLStatement1:="", SubType:= _
    wdMergeSubTypeAccess

    'sSQL = "SELECT * FROM `Employees`"
    'Merge to a new document
    With .MailMerge
    .Destination = wdSendToNewDocument
    .SuppressBlankLines = True
    With .DataSource
    .FirstRecord = wdDefaultFirstRecord
    .LastRecord = wdDefaultLastRecord
    End With
    .Execute Pause:=False
    End With

    If bPrint = True Then
    wd.ActiveDocument.PrintOut Range:=wdPrintAllDocument, Item:= _
    wdPrintDocumentContent, Copies:=iNoCopies, Pages:="", PageType:=wdPrintAllPages, _
    ManualDuplexPrint:=False, Collate:=True, Background:=True, PrintToFile:= _
    False, PrintZoomColumn:=0, PrintZoomRow:=0, PrintZoomPaperWidth:=0, _
    PrintZoomPaperHeight:=0
    End If

    .Application.DisplayAlerts = wdAlertsAll
    If Not bClose Then wd.Visible = True
    .Close False
    If bClose = True Then
    wd.ActiveDocument.Close False
    wd.Quit
    Set doc = Nothing
    Set wd = Nothing
    End If
    End With
    End Sub

    [/VBA]

  14. #14
    VBAX Tutor jo15765's Avatar
    Joined
    Oct 2011
    Posts
    281
    Location
    This is what I want my form to look like, and I know I need to add in the directory where myd atabase is stored, as well as my SQL string...My question tho, is it is possible to pass data that is entered on this form into the query, and essentially into the mail merge?
    Attached Files Attached Files
    Last edited by jo15765; 10-28-2011 at 06:25 AM.

  15. #15
    VBAX Guru Kenneth Hobs's Avatar
    Joined
    Nov 2005
    Location
    Tecumseh, OK
    Posts
    4,956
    Location
    It should work ok after the conversion and replacement of MergeRunMDB and edits to the paths for the MDB and DOCX or DOC files. You will just need to reference the lower versions of the early bound objects. In VBE for the Excel file, go to menus Tools > References... and uncheck the Missing ones and replace with the next lower version.

    snb at ExcelForum does more concise code. http://www.excelforum.com/excel-prog...-document.html

  16. #16
    VBAX Tutor jo15765's Avatar
    Joined
    Oct 2011
    Posts
    281
    Location
    One possible snag that I see is that the SQL statement that is run, is dependent upon whose template is chosen (see attachment above). The SQL varies slightly for each different template as they each have there own query. Could the code say something like TemplateOpen = TextBox4.Value.

    Then have the code for the database to open be C:\Test\TemplateOpen\TemplateOpen.mdb

    Then I could input the actual query Name from within the TemplateOpen database

  17. #17
    VBAX Guru Kenneth Hobs's Avatar
    Joined
    Nov 2005
    Location
    Tecumseh, OK
    Posts
    4,956
    Location
    The parameter inputs for MergeRunMDB() can be anything you want. That is why I do modular code. If you are going to use a query string already in the database, you will have to submit that SQL string to MergeRunMDB adapted to MSWord's syntax. It should be similar but it will be different.

    You can use Access's existing SQL using Excel's QueryTables method to import that data to Excel. One could then use the Excel data as the data source but that involves another type of MergeRun routine.

    Here is how to import the data to Excel using an existing Access stored SQL with some thread links for more info. Obviously, you can use the same nwind.mdb file. Just replace the path and name of the MDB file accordingly.
    [vba]'http://www.vbaexpress.com/forum/showthread.php?t=24118
    'http://www.vbaexpress.com/forum/showthread.php?t=24575
    'http://www.vbaexpress.com/forum/showthread.php?t=23783
    'http://www.vbaexpress.com/forum/showthread.php?t=26145
    Sub Test()
    Dim mdbPath As String, dbName As String, cmdText As String
    Dim rngDestination As String
    'mdbPath = "E:\ADO\NWind2003.mdb" 'change the path here to suit your needs
    'mdbPath = "c:\myfiles\edrive\excel\ado\NWind2003.mdb"
    mdbPath = "//matpc10/ExcelVBAExamples/ado/NWind2003.mdb"
    dbName = "NWind2003_1" 'change the database name here to suit your needs
    cmdText = "Aug94" 'change the stored SQL here to suit your needs
    rngDestination = "A1" 'change the destination range here to suit your needs

    'Clear previous data
    Cells.Delete

    InsertTableWithStoredSQL mdbPath, dbName, cmdText, rngDestination

    'Insert other data to the right of A1 with a blank column separating the two
    rngDestination = Cells(1, Columns.Count).End(xlToLeft).Offset(0, 2).Address
    cmdText = "Sales by Category"
    InsertTableWithStoredSQL mdbPath, dbName, cmdText, rngDestination
    End Sub

    Sub InsertTableWithStoredSQL(mdbPath As String, dbName As String, _
    cmdText As String, rngDestination As String, _
    Optional bFieldNames = True)

    With ActiveSheet.QueryTables.Add(Connection:=Array( _
    "OLEDB;Provider=Microsoft.Jet.OLEDB.4.0;Password="""";User ID=Admin;Data Source=" & mdbPath & ";Mode=ReadWrite;Extended Properties=""" _
    , """;Jet OLEDB:System database="""";Jet OLEDB:Registry Path="""";Jet OLEDBatabase Password="""";Jet OLEDB:Engine Type=5;Jet OLEDBatab" _
    , "ase Locking Mode=1;Jet OLEDB:Global Partial Bulk Ops=2;Jet OLEDB:Global Bulk Transactions=1;Jet OLEDB:New Database Password="""";J" _
    , "et OLEDB:Create System Database=False;Jet OLEDB:Encrypt Database=False;Jet OLEDBon't Copy Locale on Compact=False;Jet OLEDB:Co" _
    , "mpact Without Replica Repair=False;Jet OLEDB:SFP=False"), Destination:=Range("" & rngDestination & ""))
    .CommandType = xlCmdTable
    .CommandText = Array(cmdText)
    .Name = dbName
    .FieldNames = bFieldNames
    .RowNumbers = False
    .FillAdjacentFormulas = False
    .PreserveFormatting = True
    .RefreshOnFileOpen = False
    .BackgroundQuery = True
    .RefreshStyle = xlInsertDeleteCells
    .SavePassword = False
    .SaveData = True
    .AdjustColumnWidth = True
    .RefreshPeriod = 0
    .PreserveColumnInfo = True
    .SourceDataFile = mdbPath
    .Refresh BackgroundQuery:=False
    End With
    End Sub

    [/vba]
    Last edited by Kenneth Hobs; 10-28-2011 at 07:32 AM.

  18. #18
    VBAX Tutor jo15765's Avatar
    Joined
    Oct 2011
    Posts
    281
    Location
    Oh Boy, this is far more advanced than I thought it was going to be!

  19. #19
    VBAX Guru Kenneth Hobs's Avatar
    Joined
    Nov 2005
    Location
    Tecumseh, OK
    Posts
    4,956
    Location
    Regarding your Excel file, I recommend that you make the two top textboxes as Read Only or as Label controls.

    If you want to just let the user enter what they think the userid or name might be, that is fine. Your SQL string can be constructed according to their userid first and if blank, then use the name. Obviously, your users must enter the correct information. This is why I used ADO to help the user pick the correct data to construct the SQL string. IF you let the user enter the values then you may want to add some code to my routine to exit if the recordcount is 0.

    The stored SQL method may not be what you were talking about. I thought that you now want to use a stored SQL. If that is not the case, it is not all that complicated now that you have my latest MergeRunMDB routine.

  20. #20
    VBAX Tutor jo15765's Avatar
    Joined
    Oct 2011
    Posts
    281
    Location
    Maybe my best bet isn't to try to go from Access to Excel to Word. I think I am going to look into going directly from Access to Word by using C# coding instead of my beginner knowledge of VBA.

    Or I may end up with a dead end there, and find out that you have to do the same thing with C#

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •