Category Archives: MS Access – Excel Automation

Using VBA to List Active Processes

Because of some recent work I’ve been doing trying to embed applications within an Access form (so far I’ve managed to embed Brave, Edge, PowerShell ISE, Excel, Word, …) I’ve been working with listing the active computer processes. So I thought I’d share a few procedures I’ve developed to aid me with that task.

I tried a couple different approaches to get the process listing.

Initially, I was using the cmd:

tasklist /fo csv /nh

and although it did work, it was slow and created unnecessary lag in my process (no pun intended). Eventually I turned to my tried, tested and true friend WMI!
 
Continue reading

VBA – Close an Excel WorkBook

Ever needed to close a specific Excel Workbook, nothing could be easier. Below is the code I came up with to help out a user in an Access forum.

'---------------------------------------------------------------------------------------
' Procedure : XL_CloseWrkBk
' Author    : Daniel Pineault, CARDA Consultants Inc.
' Website   : http://www.cardaconsultants.com
' Purpose   : Close a specifc Excel WorkBook
' 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: Uses Late Binding, so none required
'
' Input Variables:
' ~~~~~~~~~~~~~~~~
' sFileName : Filename (w ext) of the Excel WorkBook to close
'
' Usage:
' ~~~~~~
' Call XL_CloseWrkBk("Accounts.xlsx")
' Call XL_CloseWrkBk("Accounts.xlsx", True)
'
' Revision History:
' Rev       Date(yyyy/mm/dd)        Description
' **************************************************************************************
' 1         2018-11-30              Initial Release (Forum help)
'---------------------------------------------------------------------------------------
Public Sub XL_CloseWrkBk(sFileName As String, Optional bSaveChanges As Boolean = False)
    Dim oExcel                As Object
    Dim oWrkBk                As Object

    On Error Resume Next
    Set oExcel = GetObject(, "Excel.Application")    'Bind to existing instance of Excel
    If Err.Number <> 0 Then    'Excel isn't running
        Err.Clear
        GoTo Error_Handler_Exit
    End If

    On Error GoTo Error_Handler
    '    oExcel.WorkBooks(sFileName).Close
    'Iterate through the open workbooks
    For Each oWrkBk In oExcel.WorkBooks
        If oWrkBk.Name = sFileName Then
            oWrkBk.Close SaveChanges:=bSaveChanges    'Adjust the SaveChanges as suits your needs
        End If
    Next oWrkBk

    'Close Excel if no other WorkBooks are open
    If oExcel.WorkBooks.Count = 0 Then oExcel.Quit

Error_Handler_Exit:
    On Error Resume Next
    If Not oWrkBk Is Nothing Then Set oWrkBk = Nothing
    If Not oExcel Is Nothing Then Set oExcel = Nothing
    Exit Sub

Error_Handler:
    MsgBox "The following error has occurred" & vbCrLf & vbCrLf & _
           "Error Number: " & Err.Number & vbCrLf & _
           "Error Source: XL_CloseWrkBk" & 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 Sub

Hopefully, this will be useful for others as well.

VBA – Forcing Applications to Close

The Headache

I’ve been experiencing issues with longstanding code that opens other Office applications (Excel, PowerPoint, Word) are not managing to close the applications even though the code used to work just fine. This is especially true of PowerPoint! So you end up with hidden processes running in the background and this can lock files and cause all sorts of headaches.

Now, I can’t say why this is now happening, when the .Quit command used to work beautifully, but I had to come up with a way to insure that I didn’t leave such processes, below is my solution.

Continue reading

VBA – Automating Excel – Part 2

After making my original post VBA – Automating Excel I received a few e-mails and comments asking for some more in depth examples of how this approach can be extended further to make one life easier.

So, I thought I’d demonstrate a couple more functions that can be used/adapted. The entire idea is that you can create reusable functions for coding that you need to perform regularily.

Table Border Formatting

A concrete example, when coding Excel, is that I often need to add borders around a range to format it all pretty. So you could create a function such as the one provided below and then whenever you need to apply borders to a range, you can perform the formatting by calling a single line of code.

Sub Rng_ApplyBorder(Rng As Object, RngHeader As Object)
    On Error GoTo Error_Handler

    With RngHeader.Interior
        .Pattern = xlSolid
        .PatternColorIndex = xlAutomatic
        .Color = 192
        .TintAndShade = 0
        .PatternTintAndShade = 0
    End With
    With RngHeader.Font
        .ThemeColor = xlThemeColorDark1
        .TintAndShade = 0
    End With
    With Rng.Borders(xlEdgeLeft)
        .LineStyle = xlContinuous
        .ColorIndex = 0
        .TintAndShade = 0
        .Weight = xlThin
    End With
    With Rng.Borders(xlEdgeTop)
        .LineStyle = xlContinuous
        .ColorIndex = 0
        .TintAndShade = 0
        .Weight = xlThin
    End With
    With Rng.Borders(xlEdgeBottom)
        .LineStyle = xlContinuous
        .ColorIndex = 0
        .TintAndShade = 0
        .Weight = xlThin
    End With
    With Rng.Borders(xlEdgeRight)
        .LineStyle = xlContinuous
        .ColorIndex = 0
        .TintAndShade = 0
        .Weight = xlThin
    End With
    With Rng.Borders(xlInsideVertical)
        .LineStyle = xlContinuous
        .ColorIndex = 0
        .TintAndShade = 0
        .Weight = xlThin
    End With
    With Rng.Borders(xlInsideHorizontal)
        .LineStyle = xlContinuous
        .ColorIndex = 0
        .TintAndShade = 0
        .Weight = xlThin
    End With

    ' Auto-fit the column widths and row heights
    oExcel.Selection.CurrentRegion.Columns.AutoFit
    'Freeze the first row
    oExcelWrSht.Rows("2:2").Select
    oExcel.ActiveWindow.FreezePanes = True
    oExcelWrSht.Range("A1").Select  'Return to the top of the page

Error_Handler_Exit:
    On Error Resume Next
    Exit Sub

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

Calling the function then is no harder than

Call Rng_ApplyBorder(oExcelWrSht.Range("A1:F326"), oExcelWrSht.Range("A1:F1"))

or here is a slightly streamlined version of the Rng_ApplyBorder procedure:

Sub Rng_ApplyBorder2(Rng As Object, RngHeader As Object)
On Error GoTo Error_Handler
    Dim aOutsideBorders(3)    As Long
    Dim aInsideBorders(1)     As Long
    Dim i                     As Byte

    aOutsideBorders(0) = xlEdgeLeft
    aOutsideBorders(1) = xlEdgeRight
    aOutsideBorders(2) = xlEdgeTop
    aOutsideBorders(3) = xlEdgeBottom

    aInsideBorders(0) = xlInsideVertical
    aInsideBorders(1) = xlInsideHorizontal

    With RngHeader.Interior
        .Pattern = xlSolid
        .PatternColorIndex = xlAutomatic
        .Color = 192
        .TintAndShade = 0
        .PatternTintAndShade = 0
    End With
    With RngHeader.Font
        .ThemeColor = xlThemeColorDark1
        .TintAndShade = 0
    End With
    'Set the Outside Borders
    For i = 0 To UBound(aOutsideBorders)
        With Rng.Borders(aOutsideBorders(i))
            .LineStyle = xlContinuous
            .ColorIndex = 0
            .TintAndShade = 0
            .Weight = xlThick
        End With
    Next i
    'Set the Inside Borders
    For i = 0 To UBound(aInsideBorders)
        With Rng.Borders(aInsideBorders(i))
            .LineStyle = xlContinuous
            .ColorIndex = 0
            .TintAndShade = 0
            .Weight = xlThin
        End With
    Next i

    ' Auto-fit the column widths and row heights
    oExcel.Selection.CurrentRegion.Columns.AutoFit
    'Freeze the first row
    oExcelWrSht.Rows("2:2").Select
    oExcel.ActiveWindow.FreezePanes = True
    oExcelWrSht.Range("A1").Select  'Return to the top of the page

Error_Handler_Exit:
    On Error Resume Next
    Exit Sub

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

Calling the function then is no harder than

Call Rng_ApplyBorder2(oExcelWrSht.Range("A1:F326"), oExcelWrSht.Range("A1:F1"))

PageSetup

Another concrete example, setting the various page setup settings for printing purposes. Once again, a very simple function like the one below can be created.

Sub WrkSht_SetupPage(Rng As Object)
    On Error GoTo Error_Handler
    
    With oExcelWrSht.PageSetup
        .PrintTitleRows = "$1:$1"
        .zoom = False
        .FitToPagesWide = 1
        .FitToPagesTall = False
        .PrintArea = Rng.Address
        .LeftHeader = ""
        .CenterHeader = ""
        .RightHeader = ""
        .LeftFooter = Format(Now, "yyyy-mmm-dd h:nn")
        .CenterFooter = "Page &P de &N"
        .RightFooter = ""
    End With

Error_Handler_Exit:
    On Error Resume Next
    Exit Sub

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

And again a single line of code now applies your preferred settings:

Call WrkSht_SetupPage(oExcelWrSht.Range("A1:F326"))

Charting

Another common need for automation in Excel is creating charts. Below is another example of how such a task can be automated and transformed into a reusable procedure.

Sub GenColumnChart(Rng As Object, RngChartLoc As Object, sTitle As String, sXAxisTitle As String, sYAxisTitle As String)
    On Error GoTo Error_Handler
    Dim oChart                As Object

    oExcelWrSht.Shapes.AddChart2(286, xl3DColumnClustered).Select
    'Position and size the Chart on the current page
    Set oChart = oExcel.ActiveChart.Parent
    oChart.Height = RngChartLoc.Height
    oChart.Width = RngChartLoc.Width
    oChart.Top = RngChartLoc.Top
    oChart.Left = RngChartLoc.Left
    'Format the Chart (Title, Axis Titles, remove legend)
    With oExcel.ActiveChart
        .HasLegend = False 'Remove the Legend
        .ChartType = xl3DColumnClustered 'Specify the chart type to create
        .SetSourceData Source:=Rng 'Specify the data series
        .HasTitle = True
        .ChartTitle.Characters.Text = sTitle 'Set the Chart Title
        .Axes(xlCategory, xlPrimary).HasTitle = True
        .Axes(xlCategory, xlPrimary).AxisTitle.Characters.Text = sXAxisTitle 'Set the X Axis Title
        .Axes(xlValue, xlPrimary).HasTitle = True
        .Axes(xlValue, xlPrimary).AxisTitle.Characters.Text = sYAxisTitle 'Set the Y Axis Title
    End With

Error_Handler_Exit:
    On Error Resume Next
    Set oChart = Nothing
    Exit Sub

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

Then you’d call such a function like:

Call GenColumnChart(oExcelWrSht.Range("A1:F326"), _
                    oExcelWrSht.Range("H5:M35"), _
                    "Population by City", _
                    "City", _
                    "Population")

Taking it Further

The procedures given above are very simple procedures that I created for illustrative purposes. Obviously, you could make them much more versatile by adding more input variables and linking them to the various properties.

For instance:

  • the Rng_ApplyBorder Sub could include a variable for the color to apply.
  • the WrkSht_SetupPage Sub could include variables for the Number of page wide or tall, or the various headers/footers, etc…
  • the GenColumnChart sub could include variables to include or not the legend, specify the chart type to create, …

by doing so you will end up with extremely flexible reusable procedures that will work for any and all scenarios and that it were lies the true strength of such an approach!

What are the Benefits

So what are the benefits to such an approach you are probably asking yourself! I can simply create a single procedure which contains all the code and it will work just fine, no?!

Yes, this is true and in a one off situation one may not see the benefit to such an approach, but there are several.

  • One benefit is by breaking down big procedures into components is that troubleshooting becomes easier and error reporting can become clearer.
  • But the biggest benefit is that by creating a series of smaller procedures, you build yourself a library of reusable code that you can call whenever need be. You can now create an Excel VBA module, Word VBA module, … and quickly be able to import them into any new project you undertake and have all the functionality you need without having to dissect procedures scattered throughout other projects.
  • Lastly, by using reusable procedures, you minimize the amount of code you have to write.

And don’t forget that when trying to create your own procedure in Word, Excel, … the Macro recorder is one of your best friends to get the basic code. That said, often the macro recorder adds a lot of useless code so you always need to go through it and try and remove anything that is redundant or useless.

I hope this helps illustrate the principle a little bit more.

VBA – Automating Excel

One thing that any experienced Access developer will learn is that Automating Excel is an essential part of providing good reporting in Access. Although Access has great reporting tools for grouping/organizing data, it is horrible when it comes to charting when compared to Excel (there is simply no comparison). Throw into the mix that there are numerous cases where end-user would like to be able to perform filters … and you don’t want them playing around with the raw data, so exporting it to Excel makes everyone happy.

What one will also learn is that Access does provide a few techniques/tools to export tables/queries to Excel, but once again they are very primitive and lack some serious refinement.

So what can you do to Export data to Excel while enabling you, the developer, better control over the process and final output? It’s simple, automate the process yourself instead of relying on Access to do it for you using Excel Automation.

Below I will elaborate a basic framework of reusable functions that can simplify Excel automation and then I will give you a concrete example of its usage.

Typically, I create 2 standard modules: (i) Constants Declarations, (ii) framework of reusable functions, but nothing stops you from putting them all together in one module if you prefer.

The Constants Declaration

Obviously, you can add/remove constants as required by your specific needs, this is just an example of some of the common constants used.

Option Compare Database
Option Explicit

'Excel Constants used in various Excel functions, ...
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Public Const xlAutomatic = -4105
Public Const xlDiagonalDown = 5
Public Const xlDiagonalUp = 6
Public Const xlEdgeBottom = 9
Public Const xlEdgeLeft = 7
Public Const xlEdgeRight = 10
Public Const xlEdgeTop = 8
Public Const xlInsideHorizontal = 12
Public Const xlInsideVertical = 11
Public Const xlNone = -4142
Public Const xlContinuous = 1
Public Const xlDouble = -4119
Public Const xlExpression = 2
Public Const xlSolid = 1
Public Const xlThick = 4
Public Const xlThin = 2
Public Const xlUp = -4162
Public Const xlThemeColorDark1 = 1
Public Const xlThemeColorDark2 = 3
Public Const xlSortOnValues = 0
Public Const xlAscending = 1
Public Const xlSortNormal = 0
Public Const xlYes = 1
Public Const xlTopToBottom = 1
Public Const xlPinYin = 1
Public Const xlThemeFontMinor = 2
Public Const xlLandscape = 2
Public Const xlPortrait = 1
Public Const xlValues = -4163
Public Const xlPart = 2
Public Const xlByRows = 1
Public Const xlByColumns = 2
Public Const xlNext = 1
Public Const xlPrevious = 2
Public Const xlPie = 5
Public Const xlUnderlineStyleSingle = 2
Public Const xlUnderlineStyleNone = -4142
Public Const xlCenter = -4108
Public Const xlBottom = -4107
Public Const xlTop = -4160
Public Const xlContext = -5002

The basic framework of reusable functions

Option Compare Database
Option Explicit

Private Const sModName = "mod_MSExcel" 'For Error Handling

Public oExcel           As Object    'Excel Application Object
Public oExcelWrkBk      As Object    'Excel Workbook Object
Public oExcelWrSht      As Object    'ExcelWorksheet Object
Public bExcelOpened     As Boolean    'Was Excel already open or not


Public Sub LaunchExcel(Optional bVisible As Boolean = True)
On Error Resume Next
    Set oExcel = GetObject(, "Excel.Application") 'Bind to existing instance of Excel
    
    If Err.Number <> 0 Then 'Could not get instance of Excel, so create a new one
        Err.Clear
        On Error GoTo Error_Handler
        Set oExcel = CreateObject("Excel.Application")
        bExcelOpened = False
    Else    'Excel was already running
        bExcelOpened = True
    End If

On Error GoTo Error_Handler
    oExcel.Visible = bVisible

Error_Handler_Exit:
    On Error Resume Next
    Exit Sub

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

Sub AddExcelWrkBk(Optional ByVal sTmplt As String = "")
'Create a new workbook based on a template file
    On Error GoTo Error_Handler

    If sTmplt = "" Then
        Set oExcelWrkBk = oExcel.Workbooks.Add()
    Else
        'Technically should test for the existance of the file before trying to use it
        Set oExcelWrkBk = oExcel.Workbooks.Add(sTmplt)
    End If

Error_Handler_Exit:
    On Error Resume Next
    Exit Sub

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

Sub OpenExcelWrkBk(ByVal sWrkBk As String, Optional sPwd As Variant)
'Open an existing Excel Workbook
    On Error GoTo Error_Handler

    If IsMissing(sPwd) Then
        Set oExcelWrkBk = oExcel.Workbooks.Open(sWrkBk)
    Else
        Set oExcelWrkBk = oExcel.Workbooks.Open(sWrkBk, , , , sPwd)
    End If

Error_Handler_Exit:
    On Error Resume Next
    Exit Sub

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

Sub CloseExcel(Optional bCleanupOnly As Boolean = True)
On Error GoTo Error_Handler
    
    If bCleanupOnly = False And bExcelOpened = False Then
        'oExcelWrSht.Close False
        'oExcel.ActiveWorkbook.Close False
        oExcel.Quit
    End If

Error_Handler_Exit:
    On Error Resume Next
    Set oExcelWrSht = Nothing
    Set oExcelWrkBk = Nothing
    Set oExcel = Nothing
    Exit Sub

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

Demo

Now let put it all together for a moment to see how it all works in one function to export a query. So let Rewrite my Export Records to Excel post using this reusable framework.

Function Export2Excel(ByVal sQuery As String)
    On Error GoTo Error_Handler
    Dim db              As DAO.Database
    Dim rs              As DAO.Recordset
    Dim iCols           As Integer
    Dim iRows           As Integer
 
    Call LaunchExcel 'Start Excel
    oExcel.ScreenUpdating = False
    oExcel.Visible = False   'Keep Excel hidden until we are done with our manipulation
    Call AddExcelWrkBk    'Start a new workbook
    Set oExcelWrSht = oExcelWrkBk.Sheets(1)
 
    'Open our SQL Statement, Table, Query
    Set db = CurrentDb
    Set rs = db.OpenRecordset(sQuery, dbOpenSnapshot)
    With rs
        If .RecordCount <> 0 Then
            'Get a proper record count
            .MoveLast
            iRows = .RecordCount
            .MoveFirst
            'Build our Header
            For iCols = 0 To rs.Fields.Count - 1
                oExcelWrSht.Cells(1, iCols + 1).Value = rs.Fields(iCols).Name
            Next
            'Do some basic formatting
            With oExcelWrSht.Range(oExcelWrSht.Cells(1, 1), _
                                   oExcelWrSht.Cells(1, rs.Fields.Count))
                .Font.Bold = True
                .Font.ColorIndex = 2
                .Interior.ColorIndex = 1
                .horizontalAlignment = xlCenter
            End With
            oExcelWrSht.Range("A2").CopyFromRecordset rs 'Copy the data from our query into Excel
            oExcelWrSht.Range(oExcelWrSht.Cells(1, 1), _
                              oExcelWrSht.Cells(iRows, rs.Fields.Count)).Columns.AutoFit    'Resize our Columns
            oExcelWrSht.Range("A1").Select  'Return to the top of the page
        Else
            MsgBox "There are no records returned by the specified queries/SQL statement.", vbCritical + vbOKOnly, "No data to generate an Excel spreadsheet with"
            GoTo Error_Handler_Exit
        End If
    End With
    
    'At this point you could save it and close it, or in this instance we're going to leave it open for our users to interact with it.

Error_Handler_Exit:
    On Error Resume Next
    rs.Close
    Set rs = Nothing
    Set db = Nothing
    oExcel.Visible = True   'Make excel visible to the user
    oExcel.ScreenUpdating = True
    Call CloseExcel
    Exit Function
 
Error_Handler:
    MsgBox "The following error has occurred" & vbCrLf & vbCrLf & _
           "Error Number: " & Err.Number & vbCrLf & _
           "Error Source: Export2Excel" & vbCrLf & _
           "Error Description: " & Err.Description _
           , vbOKOnly + vbCritical, "An Error has Occurred!"
    Resume Error_Handler_Exit
End Function

What else can be done

Pretty much anything.

Above is a simplistic example. I have reusable functions to apply borders the same way, I have reusable function to create charts, … this way with a single call I can automate complex tasks and simplify my overall code and provide me with just one location to edit should the need arise.

MS Access Sample- Export Data to Excel and/or Word

Over the years, I have answered numerous questions regarding how to export a records, or records to either MS Excel or MS Word. I already have 2 posts on the subject:

but thought a concrete example would help illustrate things even further.

Here are a few screenshots of the sample.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Now in this sample I am covering Excel and Word automation, not built-in commands, such as:

  • DoCmd.TransferSpreadsheet
  • DoCmd.TransferText
  • DoCmd.OutputTo
  • DoCmd.RunCommand acCmdExportRTF

These are well documented, and plenty of examples can be found online.  Instead, I concentrate on demonstrating a few possible ways to export using late binding and word and excel automation, permitting much more control on the final product (font, colors, layout, page orientation and so much more) and no need for any external reference libraries.

Note: for this sample to work, all the supporting files (excel and word) must be in the same folder as the database itself (although this very easy to change in the VBA code provided).

Fill In Excel Or Word Access Demo

MS Access – VBA – Convert Excel XLS to CSV

I was asked in a support forum how to convert an Excel *.xls, *.xlsx file to *.csv format. I didn’t readily have an answer so I created a custom function to help the user out. So here are the fruits on my labors should it help someone else out. What is also nice about the way it is written, is that it will run in any MS Office application (MS Access, MS Word, MS PowerPoint, MS Outlook, …) without requiring any modifications (copy & paste, that’s it)!

'---------------------------------------------------------------------------------------
' Procedure : ConvertXls2CSV
' Author    : Daniel Pineault, CARDA Consultants Inc.
' Website   : http://www.cardaconsultants.com
' Purpose   : Converts a standard Excel file to csv format
' Requirements: Requires MS Excel be installed
'               Uses late binding, so no libraries need be declared
' 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:
' ~~~~~~~~~~~~~~~~
' sXlsFile  : Fully qualified path and filename with extension of the Excel workbook
'
' Usage:
' ~~~~~~
' ConvertXls2CSV "C:\Users\Daniel\Desktop\Contact_E-mail listing.xls"
'       Will output a file C:\Users\Daniel\Desktop\Contact_E-mail listing.csv
'
' Revision History:
' Rev       Date(yyyy/mm/dd)        Description
' **************************************************************************************
' 1         2012-May-11             Initial Release - Answer to forum question
'---------------------------------------------------------------------------------------
Function ConvertXls2CSV(sXlsFile As String)
    On Error Resume Next
    Dim oExcel          As Object
    Dim oExcelWrkBk     As Object
    Dim bExcelOpened    As Boolean    'Was Excel already open or not
    'Review 'XlFileFormat Enumeration' for more formats
    Const xlCSVWindows = 23 'Windows CSV Format
    Const xlCSV = 6 'CSV
    Const xlCSVMac = 22 'Macintosh CSV
    Const xlCSVMSDOS = 24 'MSDOS CSV

    Set oExcel = GetObject(, "Excel.Application")    'Bind to existing instance of Excel

    If Err.Number <> 0 Then    'Could not get instance of Excel, so create a new one
        Err.Clear
        On Error GoTo Error_Handler
        Set oExcel = CreateObject("excel.application")
        bExcelOpened = False
    Else    'Excel was already running
        bExcelOpened = True
    End If

    On Error GoTo Error_Handler
    oExcel.ScreenUpdating = False
    oExcel.Visible = False   'Keep Excel hidden from the user
    oExcel.Application.DisplayAlerts = False

    Set oExcelWrkBk = oExcel.Workbooks.Open(sXlsFile)
    'Note: you may wish to change the file format constant for another type declared
    '      above based on your usage/needs in the following line.
    oExcelWrkBk.SaveAs Left(sXlsFile, InStrRev(sXlsFile, ".")) & "csv", xlCSVWindows
    oExcelWrkBk.Close False

    If bExcelOpened = False Then
        oExcel.Quit
    End If

Error_Handler_Exit:
    On Error Resume Next
    Set oExcelWrkBk = Nothing
    Set oExcel = Nothing
    Exit Function

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

Now this could be further improved by extending the error handling further to trap specific errors such as 1004 – file not found, etc… but it definitely illustrates the basic principle in using late binding to utilize Excel to open the file and convert it to *.csv format.

I hope this helps.

MS Access – VBA – Export Records to Excel

Although there are a couple buit-in technique for exporting table & query records to Excel, mainly , if one wants to control the process a little more (edit fonts, print areas, etc) you need to create your own custom procedure to do so.  Below is a simple example to get you started in the right direction. This example uses late binding techniques and thus does not require any libraries to work!

'---------------------------------------------------------------------------------------
' Procedure : Export2XLS
' Author    : Daniel Pineault, CARDA Consultants Inc.
' Website   : http://www.cardaconsultants.com
' Purpose   : Export recordset to Excel
' 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:
' ~~~~~~~~~~~~~~~~
' sQuery    : Name of the table, or SQL Statement to be used to export the records
'             to Excel
'
' Usage:
' ~~~~~~
' Export2XLS "qryCustomers"
' Call Export2XLS("qryCustomers")
'
' Revision History:
' Rev       Date(yyyy/mm/dd)        Description
' **************************************************************************************
' 1         2012-Apr-18                 Initial Release
' 2         2015-May-01                 Header Clarifications
'---------------------------------------------------------------------------------------
Function Export2XLS(ByVal sQuery As String)
    Dim oExcel          As Object
    Dim oExcelWrkBk     As Object
    Dim oExcelWrSht     As Object
    Dim bExcelOpened    As Boolean
    Dim db              As DAO.Database
    Dim rs              As DAO.Recordset
    Dim iCols           As Integer
    Const xlCenter = -4108

    'Start Excel
    On Error Resume Next
    Set oExcel = GetObject(, "Excel.Application")    'Bind to existing instance of Excel

    If Err.Number <> 0 Then    'Could not get instance of Excel, so create a new one
        Err.Clear
        On Error GoTo Error_Handler
        Set oExcel = CreateObject("Excel.Application")
        bExcelOpened = False
    Else    'Excel was already running
        bExcelOpened = True
    End If
    On Error GoTo Error_Handler
    oExcel.ScreenUpdating = False
    oExcel.Visible = False   'Keep Excel hidden until we are done with our manipulation
    Set oExcelWrkBk = oExcel.Workbooks.Add()    'Start a new workbook
    Set oExcelWrSht = oExcelWrkBk.Sheets(1)

    'Open our SQL Statement, Table, Query
    Set db = CurrentDb
    Set rs = db.OpenRecordset(sQuery, dbOpenSnapshot)
    With rs
        If .RecordCount <> 0 Then
            'Build our Header
            For iCols = 0 To rs.Fields.Count - 1
                oExcelWrSht.Cells(1, iCols + 1).Value = rs.Fields(iCols).Name
            Next
            With oExcelWrSht.Range(oExcelWrSht.Cells(1, 1), _
                                   oExcelWrSht.Cells(1, rs.Fields.Count))
                .Font.Bold = True
                .Font.ColorIndex = 2
                .Interior.ColorIndex = 1
                .HorizontalAlignment = xlCenter
            End With
            'Copy the data from our query into Excel
            oExcelWrSht.Range("A2").CopyFromRecordset rs
            oExcelWrSht.Range(oExcelWrSht.Cells(1, 1), _
                              oExcelWrSht.Cells(1, rs.Fields.Count)).Columns.AutoFit    'Resize our Columns based on the headings
            oExcelWrSht.Range("A1").Select  'Return to the top of the page
        Else
            MsgBox "There are no records returned by the specified queries/SQL statement.", vbCritical + vbOKOnly, "No data to generate an Excel spreadsheet with"
            GoTo Error_Handler_Exit
        End If
    End With

    '    oExcelWrkBk.Close True, sFileName 'Save and close the generated workbook

    '    'Close excel if is wasn't originally running
    '    If bExcelOpened = False Then
    '        oExcel.Quit
    '    End If

Error_Handler_Exit:
    On Error Resume Next
    oExcel.Visible = True   'Make excel visible to the user
    rs.Close
    Set rs = Nothing
    Set db = Nothing
    Set oExcelWrSht = Nothing
    Set oExcelWrkBk = Nothing
    oExcel.ScreenUpdating = True
    Set oExcel = Nothing
    Exit Function

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

You may also wish to review my MS Access Sample- Export Data to Excel and/or Word

VBA – Open a Password Protected Excel WorkBook

I recently helped an individual in an Access Forum who wanted to know how to open a password protected Excel workbook/spreadsheet. Although the question was Access specific, the code can easily be used in Word, PowerPoint,…

'---------------------------------------------------------------------------------------
' Procedure : OpenPwdXLS
' Author    : Daniel Pineault, CARDA Consultants Inc.
' Website   : http://www.cardaconsultants.com
' Purpose   : Open a password protected Excel 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).
'
' Input Variables:
' ~~~~~~~~~~~~~~~~
' strWrkBk  : Full path and Filename of the Excel Workbook to open
' sPwd      : Password to unlock/open the Workbook in question
'
' Usage:
' ~~~~~~
' OpenPwdXLS "C:\Testing\book1.xls", "MyPassword"
'
' Revision History:
' Rev       Date(yyyy/mm/dd)        Description
' **************************************************************************************
' 1         2009-Jun-11             Initial Release
'---------------------------------------------------------------------------------------
Function OpenPwdXLS(strWrkBk As String, sPwd As String)
'Use late binding so no reference libraries are required
On Error GoTo Error_Handler
    Dim xlApp       As Object
    Dim xlWrkBk     As Object

    On Error Resume Next
    Set xlApp = GetObject(, "Excel.Application") 'Bind to existing instance of Excel
    
    If Err.Number <> 0 Then
        'Could not get instance of Excel, so create a new one
        Err.Clear
        On Error GoTo Error_Handler
        Set xlApp = CreateObject("excel.application")
    Else
        On Error GoTo Error_Handler
    End If

    xlApp.Visible = True 'make excel visible to the user
    Set xlWrkBk = xlApp.Workbooks.Open(strWrkBk, , , , sPwd)
    
    '... the rest of your code goes here
    
Error_Handler_Exit:
   On Error Resume Next
   Set xlWrkBk = Nothing
   Set xlApp = Nothing
   Exit Function

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