VBA – Word – Enumerate/List All the Document Bookmarks

Similarily to my previous post entitled VBA – Word – Enumerate/List All Form Fields you can just as easily produce a listing of all the Bookmarks of a Word document. The following procedure does exactly that.

'---------------------------------------------------------------------------------------
' Procedure : EnumerateDocBkMrks
' Author    : CARDA Consultants Inc.
' Website   : http://www.cardaconsultants.com
' Purpose   : Generate a listing of all the Bookmarks containing within the
'             specified word document and print them to the immediate window.
' Copyright : The following may be altered and reused as you wish so long as the
'             copyright notice is left unchanged (including Author, Website and
'             Copyright).  It may not be sold/resold or reposted on other sites (links
'             back to this site are allowed).
'
' Revision History:
' Rev       Date(yyyy/mm/dd)        Description
' **************************************************************************************
' 1         2010-Sep-10                 Initial Release
'---------------------------------------------------------------------------------------
Function EnumerateDocBkMrks(sFileName As String)
On Error GoTo Error_Handler
'Requires a reference to the Word object library
Dim oApp                As Word.application
Dim oDoc                As Word.Document
Dim dBkMrk              As Bookmark

On Error Resume Next
    Set oApp = GetObject(, "Word.Application")
    If Err.Number <> 0 Then 'Word isn't running so start it
        Set oApp = CreateObject("Word.Application")
    End If
On Error GoTo 0
 
    Set oDoc = oApp.Documents.Open(sFileName)
    oApp.Visible = False 'Control whether or not Word becomes
                         'visible to the user
    
    'Loop through each form field
    For Each dBkMrk In oDoc.Range.Bookmarks
        Debug.Print dBkMrk.Name
    Next
    
Error_Handler_Exit:
    On Error Resume Next
    oDoc.Close False
    oApp.Quit
    Set oDoc = Nothing
    Set oApp = Nothing
    Exit Function
 
Error_Handler:
    MsgBox "The following error has occurred." & vbCrLf & vbCrLf & _
            "     Error Number: " & Err.Number & vbCrLf & _
            "     Error Source: EnumerateDocBkMrks" & vbCrLf & _
            "     Error Description: " & Err.Description, _
            vbCritical, "An Error has Occurred!"
    Resume Error_Handler_Exit
End Function

VBA – Word – Enumerate/List All the Document Form Fields

Have you ever started coding some vba to manipulate a Word document’s form fields and started going back and forth between the word document and the VBE. This can work if you have a few form fields, but becomes very tiresome when dealing with large form. As such, I created a very simple procedure to extract a list of the form fields in one shot and then I could continue my work in peace. I hope the following saves you some time and frustrations too.
Continue reading

VBA – Word – Open a Word Document

If you have ever needed to open a Word document and are looking for an alternative method to the Application.FollowHyperlink method, then the following procedure using Word automation should do the trick.

'---------------------------------------------------------------------------------------
' Procedure : MSWord_OpenDoc
' Author    : Daniel Pineault, CARDA Consultants Inc.
' Website   : http://www.cardaconsultants.com
' Purpose   : Open a Word document using Word automation
'               Don't forget about Application.FollowHyperlink
' Copyright : The following is release as Attribution-ShareAlike 4.0 International
'             (CC BY-SA 4.0) - https://creativecommons.org/licenses/by-sa/4.0/
' Req'd Refs: This code can be configured to use Early or Late Binding (none required)
'               So the choice is yours, if you use Early Binding then obviously you
'               need to set a reference to 'Microsoft Word XX.X Object Library'
'
' Input Variables:
' ~~~~~~~~~~~~~~~~
' sFile     : Fully qualified path and filename of the document to open in Word
'
' Usage:
' ~~~~~~
' Call MSWord_OpenDoc("C:\Users\Monkey\Documents\EatingBananas.docx")
'
' Revision History:
' Rev       Date(yyyy/mm/dd)        Description
' **************************************************************************************
' 1         2010-09-09              Initial Release
' 2         2018-05-28              Added flexibility btw Early/Late Binding
'                                   Copyright change
'                                   Updated error handler
'---------------------------------------------------------------------------------------
Function MSWord_OpenDoc(ByVal sFile As String)
    On Error GoTo Error_Handler
    #Const EarlyBind = False        'True->Early Binding,
                                    'False->Late Binding (No references required)
    #If EarlyBind = True Then
        Dim oApp              As Word.Application
        Dim oDoc              As Word.Document
    #Else
        Dim oApp              As Object
        Dim oDoc              As Object
    #End If

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

    Set oDoc = oApp.Documents.Open(sFile)
    oApp.Visible = True

Error_Handler_Exit:
    On Error Resume Next
    If Not oDoc Is Nothing Then Set oDoc = Nothing
    If Not oApp Is Nothing Then Set oApp = Nothing
    Exit Function

Error_Handler:
    MsgBox "The following error has occurred" & vbCrLf & vbCrLf & _
           "Error Number: " & Err.Number & vbCrLf & _
           "Error Source: MSWord_OpenDoc" & vbCrLf & _
           "Error Description: " & Err.Description & _
           Switch(Erl = 0, "", Erl <> 0, vbCrLf & "Line No: " & Erl) _
           , vbOKOnly + vbCritical, "An Error has Occurred!"
    Resume Error_Handler_Exit
End Function

The beauty of using Word automation is that, once the file is opened, you can litteraly do anything a user can do manually, so you can interact with the file, add text, insert images/tables, … perform searches, mail merges, … the sky is the limit.

VBA – Excel – Run an Excel Macro

Have you ever had the need to run an Excel workbook macro from another application, whether it be Word, Access,… I did, so I develop the following simple little procedure to do exactly that.

'---------------------------------------------------------------------------------------
' Procedure : RunXLSMacro
' Author    : CARDA Consultants Inc.
' Website   : http://www.cardaconsultants.com
' Purpose   : Open the specifed Excel workbook and run the specified macro and then
'             close the workbook.
' Copyright : The following may be altered and reused as you wish so long as the
'             copyright notice is left unchanged (including Author, Website and
'             Copyright).  It may not be sold/resold or reposted on other sites (links
'             back to this site are allowed).
'
' Revision History:
' Rev       Date(yyyy/mm/dd)        Description
' **************************************************************************************
' 1         2010-Sep-09                 Initial Release
'---------------------------------------------------------------------------------------
Function RunXLSMacro(sFile As String, sMacroName As String) As String
'Requires a reference to the Microsoft Excel xx.0 Object Library
On Error GoTo Error_Handler
    Dim xlApp       As Object
    Dim xlWb        As Object
    Dim sFileName   As String
    
    Set xlApp = CreateObject("Excel.Application") 'Create an Excel instance
    Set xlWb = xlApp.Workbooks.Open(sFile, True)  'Open the specified workbook
    xlApp.Visible = True                          'Control whether or not to show Excel
                                                    'to your user
    
    sFileName = Right(sFile, Len(sFile) - InStrRev(sFile, "\"))

    xlApp.Run sFileName & "!" & sMacroName         'Execute the specified macro

Error_Handler_Exit:
    On Error Resume Next
    xlWb.Close (True)                             'Save the excel workbook
    xlApp.Quit                                    'Close/Quit Excel
    Set xlWb = Nothing
    Set xlApp = Nothing
    Exit Function

Error_Handler:
    MsgBox "The following error has occurred." & vbCrLf & vbCrLf & _
            "Error Number: " & Err.Number & vbCrLf & _
            "Error Source: RunXLSMacro" & vbCrLf & _
            "Error Description: " & Err.Description, _
            vbCritical, "An Error has Occurred!"
    Resume Error_Handler_Exit
End Function

MS Access – VBA – Calculate the Number of Years

The following function accepts two dates as input variables and will return the number of years between those two dates. If you are looking to get a greater level of precision (months, days) then take a look at my post entitled MS Access – Calculate the Age

'---------------------------------------------------------------------------------------
' Procedure : NoYrs
' Author    : CARDA Consultants Inc.
' Website   : http://www.cardaconsultants.com
' Purpose   : Calculate the number of Years between two dates
' Copyright : The following may be altered and reused as you wish so long as the
'             copyright notice is left unchanged (including Author, Website and
'             Copyright).  It may not be sold/resold or reposted on other sites (links
'             back to this site are allowed).
'
' Revision History:
' Rev       Date(yyyy/mm/dd)        Description
' **************************************************************************************
' 1         2010-Sep-09                 Initial Release
'---------------------------------------------------------------------------------------
Function NoYrs(Date1 As Date, Date2 As Date) As Integer
On Error GoTo Error_Handler
    Dim Y       As Integer
    Dim Temp1   As Date
    
    Temp1 = DateSerial(Year(Date2), Month(Date1), Day(Date1))
    Y = Year(Date2) - Year(Date1) + (Temp1 > Date2)
    NoYrs = Y

Error_Handler_Exit:
    On Error Resume Next
    Exit Function

Error_Handler:
    MsgBox "The following error has occurred." & vbCrLf & vbCrLf & _
            "Error Number: " & Err.Number & vbCrLf & _
            "Error Source: NoYrs" & vbCrLf & _
            "Error Description: " & Err.Description, _
            vbCritical, "An Error has Occurred!"
    Resume Error_Handler_Exit
End Function

MS Access – VBA – ADO vs. DAO

A common question asked in numerous forums and discussion groups is:

  • Which is better: ADO or DAO?
  • Should I be using ADO or DAO in my code?

Thruthfully, there is no answer that applies for everyone. It all depends on what you are doing!

Some people argue back and forth that ADO or DAO is easier to code, or more powerful…  I’m not even going to tackle this subject as a lot of it is subjective and dependent on what you are doing.   They each offer pros and cons to the developper. That said;

If you are developing an MS Access database (back-end) then DAO is probably your best bet as it is optimized for Jet/ACE.  It should also be noted, from what I have read, that Microsoft recommends DAO for Jet data and as such is typically faster than ADO in this scenario.

On the other hand, if you are developing an Access Data Project (.adp) in conjunction with an SQL Server database (back-end), it is normally recommended that you use ADO. 

So based on this it become apparent that, it’s not a matter of whether it’s an ADP or an MDB/ACCDB, but rather where your data is stored and whether or not you will be using the Jet/ACE database engine or not.  If you are utilizing the default Jet/ACE database engine then DAO is typically the best route to go.  If not, then ADO is best.

VBA – Sending Faxes VBA

Sending Faxes of a Document using VBA (Microsoft Shared Fax Driver)

I had a requirement for a database to be able to send faxes directly from within the database. At the time, I looked high and low and couldn’t find anything on the subject using the Microsoft Shared Fax Driver (Fax printer). It is only recently that I came across a website that covered the subject very well (Murphy’s Law!).

MSDN Article – Visual Basic Fax Administration Scenarios

The following is a slightly modified version of the code found in the MSDN Article. I use a temporary table to populate the recipient of my broadcast (multiple recipient fax).

'---------------------------------------------------------------------------------------
' Procedure  : SendBroadCast
' Author     : CARDA Consultants Inc.
' Website    : http://www.cardaconsultants.com
' Code Source: http://msdn2.microsoft.com/en-us/library/ms693479.aspx
' Purpose    : Send Broadcast fax (send fax to multiple recipients)
' References : requires 'Microsoft Fax Service Extended COM Type Library'
' Copyright : The following may be altered and reused as you wish so long as the
'             copyright notice is left unchanged (including Author, Website and 
'             Copyright).  It may not be sold/resold or reposted on other sites (links
'             back to this site are allowed).
'
' Input Variables:
' ~~~~~~~~~~~~~~~~
' strDoc - path and filname of the document to be faxed
'---------------------------------------------------------------------------------------
'
Function SendBroadCast(strDoc As String)

Dim objFaxDocument As New FAXCOMEXLib.FaxDocument
Dim collFaxRecipients As FaxRecipients
Dim JobId As Variant
Dim strMsg As String

'Error handling
On Error GoTo Error_Handler

'Set the fax body
objFaxDocument.Body = strDoc

'Name the document
objFaxDocument.DocumentName = "Database Fax"

'Get the recipients collection
Set collFaxRecipients = objFaxDocument.Recipients

'Update the table from which the info is pull to generate the fax recipient list
DoCmd.SetWarnings False 'Turn off warning messages so it is transparent to the user
DoCmd.OpenQuery "Qry_Need To Be Faxed", acViewNormal
DoCmd.SetWarnings True 'Turn back on warning messages

'Add the recipients
With collFaxRecipients
    'Using the table created by the above run query loop through the record
    'To populate the fax recipient list
    Dim rst As DAO.Recordset
    Set rst = CurrentDb.OpenRecordset("Temp01")
    If rst.RecordCount > 0 Then 'ensure there is data
        rst.MoveLast  'goto the last recordset
        Do Until rst.BOF  'beginning of file
           'perform a desired action
           .Add rst![Fax], rst![Company]
           rst.MovePrevious
        Loop
    Else
        MsgBox "There are no faxes to be sent at this time!", vbInformation
    End If

End With

'Display number of recipients
strMsg = "Total Number of Recipients: " & collFaxRecipients.Count & vbCrLf

'Display recipient information
Dim i As Long
For i = 1 To collFaxRecipients.Count
    strMsg = strMsg & "Recipient number " & i & ": " & collFaxRecipients.Item(i).Name & _
             ", " & collFaxRecipients.Item(i).FaxNumber & vbCrLf
Next
MsgBox strMsg, vbInformation, "The following faxes are being processed."

'Load the default sender
objFaxDocument.Sender.LoadDefaultSender

'Group the broadcast receipts
objFaxDocument.GroupBroadcastReceipts = True

'Connect to the fax server, submit the document, and get back the
'job ID array. "" indicates the local server.
JobId = objFaxDocument.Submit("")

'UBound finds the size of the array
'Display jobIDs for each of the fax jobs
'For n = 0 To UBound(JobId)
'    MsgBox "The Job ID is " & JobId(n)
'Next

'Remove the recipients from the collection. If you don't take this step,
'and run this code again without closing the program, the recipients
'collection will retain the recipients and keep adding more recipients.
'The count and item numbering will change as you remove the items, so
'just remove item (1) Count times
Dim lCount As Long
lCount = collFaxRecipients.Count
For i = 1 To lCount
    collFaxRecipients.Remove (1)
Next
Exit Function

Error_Handler:
    'Implement error handling at the end of your subroutine. This
    'implementation is for demonstration purposes
    If Err.Number = -2147024864 Then
        MsgBox "You currently have the document to be faxed open and are therefore" & _
               " stopping the fax from being sent.  Please close the document in " & _
               "question and then try again.", vbInformation, "Your Fax cannot be " & _
               "sent at this time"
    Else
        MsgBox "Error number: " & Err.Number & ", " & Err.Description
    End If
End Function

Word – VBA – Print a Word Document

The following code will print out a word document.

'---------------------------------------------------------------------------------------
' Procedure : PrintDoc
' Author    : CARDA Consultants Inc.
' Website   : http://www.cardaconsultants.com
' Purpose   : Print a Word Document
' Copyright : The following may be altered and reused as you wish so long as the
'             copyright notice is left unchanged (including Author, Website and 
'             Copyright).  It may not be sold/resold or reposted on other sites (links
'             back to this site are allowed).
'
' Input Variables:
' ~~~~~~~~~~~~~~~~
' strDoc - The path and filename of the document to be printed
' intCopies - The number of copies to be printed
'
' Usage:
' ~~~~~~~~~~~~~~~~
' PrintDoc("c:\management\evaluation.doc",1)
'---------------------------------------------------------------------------------------
Function PrintDoc(strDoc As String, intCopies As Integer)
   Dim WordObj As Object

   Set WordObj = CreateObject("Word.Application")

   WordObj.Documents.Open strDoc
   WordObj.PrintOut Background:=False, Copies:=intCopies
   WordObj.Documents.Close SaveChanges:=wdDoNotSaveChanges
   WordObj.Quit

   Set WordObj = Nothing
 End Function

VBA – Word – Open Word using Late Binding

The following procedure will launch MS Word. The beauty is it uses late binding so you do not need to use reference libraries and as such avoid/minimize versioning issues. This same procedure can easily be modified to launch just about any MS Office application by simply changing the “Word.Application” portions of the code to correspond with the application you are trying to automate.

A few other strings used for common MS Office application are:

  • Excel – “Excel.Application”
  • Access – “Access.Application”
  • Publisher – “Publisher.Application”
  • PowerPoint – “PowerPoint.Application”
Sub LaunchWord()
Dim objApp As Object

    'See if Word is already running
    On Error Resume Next
    Set objApp = GetObject(, "Word.Application")
    
    If Err.Number <> 0 Then
        'Launch a new instance of Word
        Err.Clear
        On Error GoTo Error_Handler
        Set objApp = CreateObject("Word.Application")
        objApp.Visible = True 'Make the application visible to the user (if wanted)
    End If

Exit Sub

Error_Handler:
    MsgBox "MS Access has generated the following error" & vbCrLf & vbCrLf & "Error Number: " & _
    Err.Number & vbCrLf & "Error Source: LaunchWord" & vbCrLf & "Error Description: " & _
    Err.Description, vbCritical, "An Error has Occurred!"
    Exit Sub
End Sub