MS Access – VBA – Change Database Password

Ever wanted to change the password of a Microsoft Access database with just a click of a button, rather than manually opening the file and navigating through menus? Or perhaps you wish to create/use your own database Form to allow users to update the database password with ease through your application.

It’s not only possible, but can be implemented quite easily in Access!
 
Continue reading

MS Access – VBA – Rename attachment in SendObect Method

Everyone knows that the quickest and easiest method for sending an e-mail in MS Access is to use the SendObject method

DoCmd.SendObject acSendReport, "YourReportName", , "Someone@somewhere.com", _
                     , , "Subject", "E-mail Body"

This is all find an dandy, but there is one flaw, it uses the name of your MS Access report: “rpt_SalesForecast” or “rpt_SalesByRegion” access as the attachment name.  This simply is not acceptable for most purposes.  We want to have a name that reflects better what the report is about: “Sales forecast 2012”, “Average Sale for Montreal in July”.

I recently was in a discussion and theDBguy was kind enough to share a little trick to do exactly this without requiring a whole lot of extra coding and automation.  I thought I’d share it for everyone to benefit from. Below is the code in question:

    Dim sExistingReportName As String
    Dim sAttachmentName As String

    'Input variables
    sExistingReportName = "YourMSAccessReportName"    'Name of the Access report Object to send
    sAttachmentName = "AttachmentNameToBeUsedInTheEmail"    'Name to be used for the attachment in the e-mail

    'The code to make it happen
    DoCmd.OpenReport sExistingReportName, acViewPreview, , , acHidden
    Reports(sExistingReportName).Caption = sAttachmentName    'by changing the report caption
                                                        'you effectively change the name
                                                        'used for the attachment in the
                                                        '.SendObject method
    DoCmd.SendObject acSendReport, sExistingReportName, , "Someone@somewhere.com", _
                     , , "Subject", "E-mail Body"
    DoCmd.Close acReport, sExistingReportName

Short, sweet and simple! Thank you theDBguy!

MS Access, WANs, Wireless Networks and the Internet

A common question, and increasingly so, is relating to using MS Access over WANs (Wide Area Networks – which the Internet qualifies as).

The short answer:  Keeping in mind the fact that MS Access uses the Jet/Ace database engine, MS Access simply does not, should not be used in any manner over WANs, wireless networks and/or the Internet.

The longer answer:  As with most things in life, there are always ways to bend the rules…  As such, there are techniques that permit one to use a database over WANs: the use of Terminal services, CITRIX, which the newer version of MS Access (2010 especially) developing your database as a Web database and publishing it to Office365.com, utilizing SharePoint services.  Albert Kallal, an MS Access MVP, has a very detailed post about MS Access and WANs which covers much more in detail the subject, especially the technical reasons: http://www.kallal.ca/Wan/Wans.html.

That all said, even though there are certain work arounds (each having their own set of pros and cons), I always ask my clients the same basic question: “What is the purpose of the database you are creating?”.  If it is an internal business tools (used over a wired LAN network), then MS Access is definitely worth exploring further.  If on the other hand, it is to be shared, over the Internet or corporate WAN, with lots of users/clients, etc.  then it is time to look at web databases (which Access simply is not – at least not in the standard sense of the term).  This is when you have to truly start looking into databases such as: MySQL (very common and cheap hosting is easy to find), PostgreSQL, SQL Server (harder to find host and more costly typically) and development languages such as: PHP, .Net, JAVA, and a multitude of others.

In summary:
In-house application used over a wired LAN connection-> MS Access is the apex in development tools!  It is the fastest and probably easiest development tool used by millions, upon millions of users around the world!!!
An application to be run over a WAN, Wireless Network and/or the Internet -> Turn to more professional web application and development tools.

VBA – List of files in a specified Folder or Directory

Ever needed to extract a list of files within a folder/directory? Ever needed to iterate through the files within a given folder/ directory? Below is a simple illustration of how you can do it using the Dir() function. Many examples commonly utilize the File System Object (FSO), when in reality there is no need to use an external library to do this simple task! As they say Keep It Simple Stupid (the KISS philosophy).

You only truly need to consider FSO if you need a recursive function to list all the files within a directory, and, all of its sub-directories as well.
 

Basic Concept Of Using Dir To Get A File Listing

The basic concept, using the Dir() function is:

    Dim sFile as String
    Const sPath = "C:\Users\Daniel\Documents\"

    sFile = Dir(sPath & "*")
    Do While sFile <> vbNullString
        If sFile <> "." And sFile <> ".." Then
            Debug.Print sFile 'Return just the filename
            'Debug.Print sPath & sFile 'Return a fully qualified path and filename
        End If
        sFile = Dir     'Loop through the next file that was found
    Loop

 
Continue reading

VBA- Determine Executable Path for Given Application

Have you been trying to develop a flexible method of determining the path to launch an application. You quickly learn that software developers, in some instances, make it indredibly difficult for us to create a simple static path for the executable directory.

For instance, say you create a database and then deploy it, you can’t just use a static path to launch it, like:

C:\Program Files\Microsoft Office\OFFICE 11\MSACCESS.EXE

because this will work only with Office 2003. What happens if your user is using 2007, 2010, 2000, …???

So what can one do? Well, it is possible to create a series of if statements, to check and see if a 2010 folder exists, if not, then check for 2007, and so on, but this once again rellies on a series of static enties that you make as a developer. For typical installation this would work, but what about that special user that didn’t install Office in the typical location? Your script will fail, no and if or about it!

So What Can One Do?! Actually, the solution is quite straight foward and works for most every program. All we need to do is check with the registry as to where the program was installed/configured! That’s right, let’s just ask the computer, “where did you put the application”? The beauty is in its simplicity.

For MS access, we only need to do the following

Dim WSHShell
Set WSHShell = CreateObject("WScript.Shell")
MsgBox WSHShell.RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\MSACCESS.EXE\")

Obviously, instead of sending the result to a msgbox we could assign it to a variable and use it to actually launch a database.

What other programs can we use this technique with? You name it: Excel, Groove, Internet Explorer, FireFox, Info Path, MS Access, One Note, Outlook, Power Point, Word, … and the list goes on. Below is but a few examples of other programs.

Dim WSHShell
Set WSHShell = CreateObject("WScript.Shell")
'MS Excel
MsgBox WSHShell.RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\excel.exe\")
'Groove
MsgBox WSHShell.RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\GROOVE.EXE\")
'Internet Explore
MsgBox WSHShell.RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\IEXPLORE.EXE\")
'Info Path
MsgBox WSHShell.RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\infopath.exe\")
'MS Access
MsgBox WSHShell.RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\MSACCESS.EXE\")
'MS One Note
MsgBox WSHShell.RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\OneNote.exe\")
'MS Outlook
MsgBox WSHShell.RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\OUTLOOK.EXE\")
'PowerPoint
MsgBox WSHShell.RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\powerpnt.exe\")
'MS Word
MsgBox WSHShell.RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\Winword.exe\")
'WordPad
MsgBox WSHShell.RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\WORDPAD.EXE\")
'Write
MsgBox WSHShell.RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\WRITE.EXE\")

So you can simply test out other application by using the appropriate executable or use regedit navigate to the “HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths” key and review the list of application present on your system.

But as you can see, with but 3 little lines, we can have a flexible way to get the path to our executable. No more guessing, no more messing!

Looking for a way to do the same thing in a bat file?!

Don’t worry, you can do the same thing using a bat file, below is an example

@echo off
REM Great reference on REG QUERY
REM 	https://www.robvanderwoude.com/regsearch.php
REM 	OR run reg query /? in a cmd window

set APPEXE=MSACCESS.EXE
set KEY_NAME=HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\
set FULL_KEY="%KEY_NAME%%APPEXE%"

FOR /F "skip=2 tokens=2,*" %%A IN ('REG QUERY %FULL_KEY% /ve') DO set "exePath=%%B"
ECHO %exePath%

VBA – Export to Text File

Below is a similar function to my AppendTxt function, expect this one overwrites any existing data in the destination text file instead of appending it like in the AppendTxt function.

'---------------------------------------------------------------------------------------
' Procedure : OverwriteTxt
' Author    : Daniel Pineault, CARDA Consultants Inc.
' Website   : http://www.cardaconsultants.com
' Purpose   : Output Data to an external file (*.txt or other format)
'             ***Do not forget about access' DoCmd.OutputTo Method for
'             exporting objects (queries, report,...)***
'             Will overwirte any data if the file already exists
' 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:
' ~~~~~~~~~~~~~~~~
' sFile - name of the file that the text is to be output to including the full path
' sText - text to be output to the file
'
' Usage:
' ~~~~~~
' Call OverwriteTxt("C:\Users\Vance\Documents\EmailExp2.txt", "Text2Export")
'
' Revision History:
' Rev       Date(yyyy/mm/dd)        Description
' **************************************************************************************
' 1         2012-Jul-06                 Initial Release
'---------------------------------------------------------------------------------------
Function OverwriteTxt(sFile As String, sText As String)
On Error GoTo Err_Handler
    Dim FileNumber As Integer
 
    FileNumber = FreeFile                   ' Get unused file number
    Open sFile For Output As #FileNumber    ' Connect to the file
    Print #FileNumber, sText                ' Append our string
    Close #FileNumber                       ' Close the file

Exit_Err_Handler:
    Exit Function
 
Err_Handler:
    MsgBox "The following error has occurred" & vbCrLf & vbCrLf & _
           "Error Number: " & Err.Number & vbCrLf & _
           "Error Source: OverwriteTxt" & vbCrLf & _
           "Error Description: " & Err.Description, vbCritical, "An Error has Occurred!"
    GoTo Exit_Err_Handler
End Function

VBA – Count files in Folder/Directory

Below is a simple function that will return the count (number) of files contained within a supplied folder path.

'---------------------------------------------------------------------------------------
' Procedure : FlrFileCount
' Author    : Daniel Pineault, CARDA Consultants Inc.
' Website   : http://www.cardaconsultants.com
' Purpose   : Return a count of the number of files in a specified folder/directory
' 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:
' ~~~~~~~~~~~~~~~~
' sFileFlr  : Full path of the folder to count the number files within
'
' Usage:
' ~~~~~~
' FlrFileCount("C:\Users\Esther\Documents\cdo")  ::  Will return a numeric value
'
' Revision History:
' Rev       Date(yyyy/mm/dd)        Description
' **************************************************************************************
' 1         2010-Jan-11             Initial Release
'---------------------------------------------------------------------------------------
Function FlrFileCount(sFileFlr As String) As Long
On Error GoTo Error_Handler
    Dim fso As Object
    Dim flr As Object
    
    Set fso = CreateObject("Scripting.FileSystemObject")
    Set flr = fso.GetFolder(sFileFlr)
    
    FlrFileCount = flr.Files.Count

Error_Handler_Exit:
    On Error Resume Next
    Set flr = Nothing
    Set fso = Nothing
    Exit Function

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

MS Access – VBA – Create a Query

The code below allows you to supply a query name and an SQL statement, and it will create the query for you.

'---------------------------------------------------------------------------------------
' Procedure : CreateQry
' Author    : CARDA Consultants Inc.
' Website   : http://www.cardaconsultants.com
' Purpose   : Create a new query in the current database
' 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:
' ~~~~~~~~~~~~~~~~
' sQryName - Name of the query to create
' sSQL - SQL to use
'
' Usage Example:
' ~~~~~~~~~~~~~~~~
' CreateQry "qry_ClientList", "SELECT * FROM Clients ORDER BY ClientName"
'
' Revision History:
' Rev       Date(yyyy/mm/dd)        Description
' **************************************************************************************
' 1         2009-Nov-07                 Initial Release
' 2         2022-11-18              Fixed Error Handler Issue
'---------------------------------------------------------------------------------------
Sub CreateQry(sQryName As String, sSQL As String)
    On Error Resume Next
    Dim db               As DAO.Database
    Dim qdf              As DAO.QueryDef

    Set db = CurrentDb

    With db
        'In the next line we try and delete the query
        'If it exist it will be deleted, otherwise it will raise an error but since
        'we set our error handler to resume next it will skip over it and continue
        'with the creation of the query.
        .QueryDefs.Delete (sQryName)                'Delete the query if it exists
        On Error GoTo Error_Handler             'Reinitiate our standard error handler
        Set qdf = .CreateQueryDef(sQryName, sSQL)   'Create the query
    End With

    db.QueryDefs.Refresh  'Refresh the query list to display the newly created query

Error_Handler_Exit:
    On Error Resume Next
    Set qdf = Nothing
    Set db = Nothing
    Exit Sub

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

MS Access – VBA – Convert Form SQL into Queries Automatically

When I develop, I always, initially, build my SQL statements directly within my form’s Record Source. Now, it is a best practice to always create an independent query and base form’s off of the query rather than use an embedded SQL Statement. This is all fine a dandy when your db has 5-10 forms, but when you are working on databases with 10s or 100s of forms, this can become quite a tedious task to convert all of the SQL statements into queries and then reassign the newly created queries to their respective forms. So, I thought about it for a couple minutes and quickly realized that this could actually all be automated quite easily. As such, I developed the following procedure.

'---------------------------------------------------------------------------------------
' Procedure : ConvertSQL2QRY
' Author    : Daniel Pineault, CARDA Consultants Inc.
' Website   : http://www.cardaconsultants.com
' Purpose   : Save recordsource to queries and update recordsource to use the query
' 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).
' Dependencies: CreateQry()
'
' Revision History:
' Rev       Date(yyyy/mm/dd)        Description
' **************************************************************************************
' 1         2011-04-30              Initial Release
' 2         2022-11-18              Fixed Error Handler Issue
'---------------------------------------------------------------------------------------
Sub ConvertSQL2QRY()
On Error GoTo Error_Handler
    Dim db               As DAO.Database
    Dim qdf              As DAO.QueryDef
'    Dim sSQL             As String
    Dim ctl              As Control
    Dim frm              As AccessObject
    Dim dbo              As AccessObject
    Dim dbp              As Object
    Dim sFrmName         As String
    Dim sFrmRS           As String
    Dim sQryRS As String

    Set db = CurrentDb
    Debug.Print "ConvertSQL2QRY Begin"
    Debug.Print "================================================================================"

    'Check Forms
    For Each frm In CurrentProject.AllForms
        sFrmName = frm.Name
        DoCmd.OpenForm sFrmName, acDesign
        sFrmRS = Forms(sFrmName).RecordSource
        Debug.Print "Processing Form: " & sFrmName
        If Len(sFrmRS) > 0 And Left(sFrmRS, 4) <> "qry_" Then
            Debug.Print "   Converting Form: " & sFrmName
            If Left(sFrmRS, 7) = "SELECT " Then
                sQryRS = sFrmRS
            Else
                sQryRS = "SELECT [" & sFrmRS & "].* FROM [" & sFrmRS & "];"
            End If
            'Create a query based on the active RS and name it based on the form name for
            '   traceability
            CreateQry "qry_" & sFrmName, sQryRS
            'Change the form RS to use the newly created query
            Forms(sFrmName).RecordSource = "qry_" & sFrmName
        End If
        DoCmd.Close acForm, frm.Name, acSaveYes
    Next frm

    Debug.Print "================================================================================"
    Debug.Print "ConvertSQL2QRY End"

Error_Handler_Exit:
    On Error Resume Next
    Set qdf = Nothing
    Set db = Nothing
    Set ctl = Nothing
    Set frm = Nothing
    Set dbp = Nothing
    Set dbo = Nothing
    Exit Sub

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

What does this procedure do? Well, it will go through all the forms in your database and create a query using the current record source and then reassign the newly created query as the form’s record source. I run this query just before deploying a database. It is also intelligent enough to only process those forms that don’t already have a query created, so it can be rerun whenever needed should I add new forms, etc…

Please note this procedure is dependent on my CreateQry procedure, so be sure to get it as well!

Access Solutions: Tips, Tricks, and Secrets from Microsoft Access MVPs Review

Access Solutions: Tips, Tricks and Secrets from Microsoft Access MVPsI have one thought for you; If you are looking for a good book to learn from about common database developer needs, then this is a MUST buy! Truly, I wish this book had been out 10-15 years ago when I was learning and developing my first databases.

The subjects covered are corner stones of almost any database and any developer will find useful knowledge and techniques. Furthermore, coming from 2 of the best Access developers (Douglas Steele and Arvin Meyer), you know that the information is right on the money!

The approach is very unique, in that the book is divided into Tips and then each tip is subdivided into Objective; Scenario, Tables, Queries, Forms, Reports, Macros, Modules, Using This Tip & Additional Information. So they explain every aspect of what they are doing, why they are doing it and what needs to be done to make it all work. It is a simple step by step guide.

This book is not so much about how to use Access, but rather how to develop a database. Arvin and Douglas share their solutions on how to tackle common issues from start to finish. These are real-life issues that we all have to deal with and with complete solutions. Subjects such as Cascading Combo Boxes, Treeview & Listview controls, Drag and Drop, Tab Controls, Relinking your Back-End, and so much more…

Furthermore, unlike numerous other books currently collecting dust on my shelves in which a few chapters are useful but the bulk are not, Access Solutions: Tips, Tricks, and Secrets from Microsoft Access MVPs Review is good from cover to cover. Every tip is useful. Clearly written, easy to follow along, you can tell that Doug and Arvin have invested a lot of time and energy developing the content within.

The table of contents is:

Part I Tables 1.
Tip 1 Creating Tables for Web Applications.
Tip 2 Alternative to the Hyperlink Data Type.
Tip 3 Fill a Table with Numbers.

Part II Queries.
Tip 4 A Single Query to Do Both Updates and Insertions.
Tip 5 Using a Cartesian Product to Generate a Calendar.
Tip 6 Using a Multiselect List Box as a Query Parameter.

Part III Forms.
Tip 7 Cascading Combo Boxes.
Tip 8 Cascading Combo Boxes on Continuous Forms.
Tip 9 Paired List Boxes.
Tip 10 Marquees, Scrolling Messages, and Flashing Labels.
Tip 11 Custom Tab Controls.
Tip 12 Simulating Web-Style “Hover” Buttons.
Tip 13 Custom Form Navigation Controls.
Tip 14 Calendar Form.
Tip 15 Simulating Drag-and-Drop in Access Forms.
Tip 16 Providing Visual Feedback for Drag-and-Drop.
Tip 17 Control List Boxes with Drag-and-Drop.

Part IV Taking Advantage of Report Capabilities.
Tip 18 Page 1 of N for Groups.
Tip 19 Always Starting a Group on an Odd Page for Duplex Printing.
Tip 20 Dynamically Changing the Sort Order of a Report.
Tip 21 Week-at-a-Glance–Type Report.
Tip 22 Day-at-a-Glance-Type Report.

Part V Using VBA.
Tip 23 Useful String Functions.
Tip 24 Useful Functions.
Tip 25 Relinking Front-End Databases to Back-End Databases in the Same Folder.
Tip 26 SaveAsText and LoadFromText: Undocumented Backup and Anti-Corruption Tricks.
Tip 27 Reminders—Building Tickler Forms and Utilities.
Tip 28 Using Disconnected Recordsets.
Tip 29 Implementing Soundex.

Part VI Automating Applications and ActiveX Controls.
Tip 30 Charting Using Excel.
Tip 31 Using the TreeView Control.
Tip 32 Using the ListView Control.
Tip 33 Adding Images to the TreeView Control.
Tip 34 Using the TreeView and ListView Controls Together.

Part VII Access and the Web.
Tip 35 Building an Access Web Application.
Tip 36 Embedding a Web Control in a Form.
Tip 37 Building a Time Picker in a Web Form: An Introduction to Web Macros.
Tip 38 RSS Feeds.
Tip 39 Detecting Whether You’ve Got Internet Connectivity.

Part VIII Utilities.
Tip 40 Drilling Down to Data.
Tip 41 Utility for Renaming a Form’s Controls.
Tip 42 Document Management Using Access.
Tip 43 Ultra-Fast Searching.

At the end of the day, even an experienced developer such as myself has taken ALOT away from this book!  I would recommend it to anyone, especially anyone starting out.  It will make a great addition to my existing library.  Well worth every penny!!!

To learn more or purchase the book, see:
wiley.com
amazon.ca
amazon.com