MS Access: checking network paths without freezing your application
Access programming is inherently single-threaded. That’s usually OK as most operations are sequential anyway and it keeps things simple at the programming level.
There are times though where the lack of ability to run code on another thread is sorely missing: anything that takes a long time to run will just freeze the application, making it unresponsive and appearing to be locked and about to crash to the user.
Checking for the existence of network paths
Checking for the existence of network paths (directories or files) is one of these issues that can freeze an application for 30 seconds or more if the folder is not accessible.
This is a type of problem that benefits greatly from running in a separate thread: it can take such a long time that the best way to check for these remote paths is to launch the verification for their existence outside of Access and somehow get the result back and cache it for the current session so we don’t have to suffer these delays again every time we check for that path’s existence.
One easy way to do achieve that goal is to create plain DOS batch files that execute hidden from view, create a result file when they complete their task and delete themselves automatically when they are finished.
How to use it
Download the sample database below then just add the FileUtilities
, HashTable
and MD5
modules to your project and you can use the code as such:
Dim status As AsyncDirectoryStatus status = FileUtilities.PathExistAsync("\\123.45.67.89\shared folder")
The status
variable will return either of the following values:
AsyncDirectoryStatus.OK
if the path was found.AsyncDirectoryStatus.NotFound
if the path was not found (either because it doesn’t exist or you don’t have the rights to access it).AsyncDirectoryStatus.Checking
if the verification is in progress and we haven’t received a definite answer yet.
It’s up to you to decide how you want to handle that case. You could periodically check it, like I did in the example database, or you could disable the controls until you’re getting a confirmed result (by checking every time the user performs some action, like moving from record to record in a datasheet for instance).
You can call PathExistAsync
as often as you want to check the status: it will not slow down your application (read the optional arguments section below though).
The result of the verification is cached, so querying the existence of the path is actually only done once; the result of subsequent queries for the same path is just instantly retrieved from memory.
Optional arguments
If you want to force the actual re-checking of a path without using the cached value, you can simply pass the ForceCheck
optional parameter:
Dim status As AsyncDirectoryStatus status = FileUtilities.PathExistAsync("\\123.45.67.89\shared folder", ForceCheck:=true)
The first time you query for a path (or force it to be rechecked) there will be a short 150ms delay to give a chance to the function to return its result straight away (in case the path can be resolved quickly).
This may not be desirable if you’re checking a bunch of directories at a time. For instance, this is what I do when my application launches:
' Check a bunch of paths in parallel PathExistAsync strPathToQualityDocuments, NoDelay:=true PathExistAsync strPathToFinancialDocuments, NoDelay:=true PathExistAsync strPathToShippingDocuments, NoDelay:=true PathExistAsync strPathToPurchasingDocuments, NoDelay:=true
By querying the existence of all these paths as soon as my application launches, I am starting the verification process without introducing delays in the application itself: each verification will start in its own process, in parallel to the main application.
Later in the application, when I need to actually use these paths, their result is likely to be known.
How it works
The FileUtilities
module contains the main code.
In it, the PathExistAsync
function works in slightly different ways depending on whether it’s the first time it is being called for a particular path or not.
The first time
The first time the function is called for a given path, we create in the user’s temporary folder the small batch file whose name is simply a MD5 hash (see below) of the path with .bat
appended to it.
This batch file simply checks for the existence of the path and will create a small file (whose name is the MD5 hash of the path) with either 0
or 1
in it depending on the result of the verification.
We initially cache the status of the verification for the Path into the AsyncDirectories
hashtable (see below) as Checking
.
Example of batch file automatically created to verify a path:
IF NOT EXIST "\\123.56.78.9\going nowhere" GOTO NOTEXIST echo 1 > "C:\DOCUME~1\Renaud\LOCALS~1\Temp\463C7367D8329BD6209A65A70A7DA08C" GOTO END :NOTEXIST echo 0 > "C:\DOCUME~1\Renaud\LOCALS~1\Temp\463C7367D8329BD6209A65A70A7DA08C" :END DEL %0
The Batch file name is 463C7367D8329BD6209A65A70A7DA08C.bat
where the long number is actually the MD5 hash of the path we’re checking \\123.56.78.9\going nowhere
.
Getting back the result
Whenever the PathExistAsync
function is called, we check the currently cached result from the AsyncDirectories
hastable.
If it is still Checking
then we try to verify if we the result file has been created from the running batch. If not, we just return the same status, if yes, we read the result from the file, save it in the hashtable and delete the result file.
Useful libraries
The code makes use of 2 extremely useful libraries that I end up using quite often:
a HashTable implementation.
It makes it easy to create hashtable objects (otherwise known as Associative Arrays) to store and retrieve key/value pairs quickly.
Hashtables are often used to cache data and can be thought of arrays where the index is a string value instead of an number.
Here I use a hashtable to keep track of the paths we’ve checked and their result.a MD5 hash implementation.
MD5 is a way to get a somewhat unique fixed-length value from a chunk of data.
It’s a mathematical function that guarantees that a small change in input (say a single bit in the input data) has a large effect on the output value (a totally different number will be generated) and that you can’t reverse the function (you can’t obtain the input just by looking at the output).
It is often used in applications to transform sensitive data like passwords into unique values that can be (somewhat) safely stored because you can’t easily reverse a md5.
Well, MD5 are not secure any longer but here we just use their ability to transform our path into a unique number that we can easily use as a filename and a key for our hash to retrieve the current status of the path being checked.
Sample database
Download the PathExistAsync01.zip (67KB) containing the Access 2007 ACCDB database.
Download the PathExistAsync02b.zip (121KB) containing the MDB database1 (untested as I only have Access 2007).

License
Please refer to the source code in the database for the exact licensing terms.
Note that the license only refers to code by me. When code from other sources is used, you will have to conform to their own licensing terms.
This work is licensed under a Creative Commons Attribution 3.0 Unported License.
References
- Hashtable implementation in VB
- Cryptography Software Code (for the MD5 hash implementation in VB)
-
A specific version for Access 2000 now included in the archive (updated 25JUL2008). ↩
7 comments June 20th, 2008