Using Database Library Files in Your Access Application
By Andrew Wrigley (based in Argentina and the UK)
Intro
You split your apps into Front-Ends and Back Ends, but
time and again you’ll find yourself importing generic code modules, forms,
reports, queries and tables from other applications. If you think ‘there must be
a better way’, then read on.
I will show how to use Access .mdb / .mde files as Libraries that you can reuse
with any of your Front-Ends. This allows you to split your Development efforts
into application specific functionality and reusable utilities.
You are also able to sell such Libraries or purchase one from a third party. We
have various Libraries that we will launch soon (for more details go to
http://www.wingspan.info/Products),
to provide sophisticated ‘out of the box’ utilities and functionality to Access
Developers.
<< Click image to expand
Fig 1: Setting a reference to a Library File
But you don’t need to go that far to find uses for Libraries:
you can use them to protect your Intellectual Property, as you can pack all your
hard work (at least, the bits your client hasn’t paid for) into a Library that
you deploy to your clients as an .mde file. This works even if your Client’s
Front-End file is an .mdb.
So Libraries are an all round winner and 90% of what they can do for you is
really very easy to accomplish. Going the extra mile will always be more taxing,
but this article will make it a breeze and give you extra insights to boot.
Using .MDB/.MDE Library Files ~ Running the Sample
When you can download the samples for this article, you will find that it
contains two apps, SimpleSample and DaisyChainSample. Both do exactly the same
thing and for the purposes of this article, use SimpleSample. If you want to try
some of the techniques mentioned in the Appendix, only then look at
DaisyChainSample. For more details on the Samples, refer to ReadMe.rtf included
in the download.
SimpleSample involves a traditional Front-End and Back End plus one Library file
(SimpleLibrary.mdb), located in the Resources\Libraries subfolder.

Fig 2: The Sample folder structure
When you open the Front-End file (FrontEnd.mdb), a Splash form
will display (See Figure 3).

Fig 3: Splash Form opened from a Library File
Now try and find the Splash form in FrontEnd.mdb. It’s not
there! But take a peek inside SimpleLibrary.mdb (Figure 4) and there it is,
proof that FrontEnd.mdb is opening a form that is stored in a Library file.

Fig 4: Showing that the Splash Form is a Library Form!
The Consequences of Using Physically Distinct Files: CurrentProject and
CodeProject
Most of the time, you develop a Library exactly as you would a Front-End.
However, your Library code is now in a physically distinct file and this has a
few consequences you need to be aware of.
As the Library is a separate file, it has a distinct VBA Project. You can see
this by looking in the Project Explorer of the VBA Editor (see Fig 5).

Fig 5: Your Library Files have distinct VBA Projects
To refer to these projects in code you use either
CurrentProject or CodeProject. For example:
strConn = CurrentProject.Connection
But how do you know which one to use? It turns out the answer is easy:
CurrentProject will ALWAYS refer to the file you opened in Access (eg, your
Front-End), whereas CodeProject refers to the Project (file) where the code is
written. So CurrentProject always refers to the same project, whereas
CodeProject doesn’t.
To illustrate this, look at the following lines of code:
strConn1 = CurrentProject.Connection
strConn2 = CodeProject.Connection
If strConn1 = strConn2 Then
boolSameFile = True
Else
boolSameFile = False
End If
If this code is written in a Front-End module, then CurrentProject and
CodeProject are one and the same and so boolSameFile is True. However, the same
code written in a Library module will return boolSameFile as False: strConn1
will still give you the connection string to the Front-End, but strConn2 will
now be set to the connection string for the Library file.
You can see this happening in the Immediate Window. Click on the Front-End
Project in the Project Explorer and try:
? CodeProject.AllForms.Count
This will give you the number of forms you have in the Front-End. Now click on a
Library Project. Running the same line in the Immediate Window will now give you
the number of forms in the Library file.
Similar reasoning applies to CurrentData and CodeData, (or CurrentDB and CodeDB),
that give you a reference to the database in each file (as opposed to the VBA
Project of each file).
Accessing the Objects and Code in your Library Files ~
Public Constants, Variables, Subs and Functions
We can now look at how to use your libraries.
This is the easiest way to use a library, as a repository of
Public methods, variables and constants. The good news is that this is dead
easy:
Constants, Variables, Subs and Functions, that are scoped as Public and stored
in a Library Code Module, can be used as if they were in the Front-End itself.
It is really easy and straightforward! For example, say you have a Public
Function in a Library called MyLibraryFunction. In your Front-End you can write:
Dim strSomeData as String
strSomeData = MyLibraryFunction()
Now you could write:
strLibraryData = strSomeData
where strLibraryData is defined in your Library like so:
Public strLibraryData As String
That’s the good news. "The really good news is that there isn’t any bad news! It
just works."
For other objects, such as Library Forms, Reports and Classes, it gets just a
little more complex but the following sections should provide an easy reference
and guide.
Opening Access Objects in a Library File
If from your Front-End you want to open the Splash form, that is stored in the GenericLibrary.mdb file, the following code will fail, with Access complaining
that it cannot find the Splash form:
DoCmd.OpenForm “Splash”
So how does the Front-End ever get to open a Form in a Library? The workaround
is simple: in the Library file, you define the following Public wrapper method:
Public Sub OpenFormInSimpleLibrary( _
FormName As Variant, _
Optional View As AcFormView, _
Optional FilterName As Variant, _
Optional WhereCondition As Variant, _
Optional DataMode As AcFormOpenDataMode, _
Optional WindowMode As AcWindowMode, _
Optional OpenArgs As Variant)
DoCmd.OpenForm FormName, View, FilterName, _
WhereCondition, DataMode, WindowMode, OpenArgs
End Sub
In my Front-End code I can now write:
OpenFormInSimpleLibrary “Splash”
This Public Sub can be ‘seen’ from the Front-End, so you can call it OK, but why
does the wrapped call to DoCmd.OpenForm now work when before it failed?
In essence, you can think that DoCmd.OpenForm requires the form to be opened to
be part of either the CodeProject.AllForms collection or the
CurrentProject.AllForms collection. As discussed above, in the Front-End, these
collections are indistinct, but in a Library File, CurrentProject refers to the
Front-End, whereas CodeProject refers to the Library. Note that this implies
that from the Library project you can open a Form in the Front-End, which can be
quite useful! Although the Library, to be generic, should have no knowledge of
the Front-End, you can pass the form name to a Library method as a string
parameter.
You need a similar Sub for closing objects, that wraps the DoCmd.Close method
(see the Sample App).
What if a Library needs to use a Class Instance defined in the
Front-End?
For example, I use a Class Module called classContext to deal with the retrieval
of context information, such as User Preferences. Different apps need different
contexts, so this class has to be defined in the Front-End.
As a result, the Libraries have no knowledge of this classContext class (or of
its instance, that I call the Context object). However, the Libraries often need
to use the Context object’s methods and properties. For example, if a Library
form needs to display context information:
lblUserName.Caption = Context.UserName
However, this will cause problems if the Context variable is declared in the
Front-End, as the Library cannot ‘see’ it.
The solution is easy. In the Library file, define the following Public variable:
Public Context as Object
This Library variable has Public scope so it can be ‘seen’ from the Front-End
where you can ‘late bind’ it to the classContext type:
‘defined in the Front-End:
Public Sub StartContext()
Set Context = New classContext
End Sub
Just make sure that you call StartContext before you try to use the Context
object!
Using Class Instances defined in a Library (Link Table Manager Sample)
There are two possible scenarios:
1. A Single Instance Of A Type That Is Defined In The Library File (Singleton)
If your Front-End needs to instantiate ONE and ONLY ONE object from a given
Library Class Module, you declare the variable in the Library:
Public LinkManager as classLinkManager
You then just need to provide a simple Sub in the Library to instantiate the one
and only LinkManager:
Public Sub SetLinkManager()
Set LinkManager = New classLinkManager
End Sub
The Library ‘knows’ what the LinkManagerClass type is (the corresponding class
module is stored inside it), whilst your Front-End can ‘see’ both the SetLinkManager sub and the LinkManager, variable because it is declared as
Public, so you do not need Late Binding.
All the code in your Front-End has to do is call SetLinkManager and then use the
LinkManager object at will. For example:
SetLinkManager()
LinkManager.CheckLinks()

Fig 6: The Link Manager in Action
Note that this way you are limited to precisely one
LinkManager object (in OOP speak, this is called a Singleton object).
2. Arbitrary Number Of Instances Of A Class That Is Defined In A Library
In this case, you will need to use the late binding technique we saw earlier.
For example, in your Library define the following Sub:
Public Sub NewUsefulObject() As UsefulClass
Set NewUsefulObject = New UsefulClass
End Sub
This public sub is visible from your Front-End code, so you can now declare a
variable of type object, and then late bind it to the UsefulObjectClass type:
Set YetAnotherUsefulObject = NewUsefulObject
You can now use this variable in your Front-End code with all the methods and
properties of the late bound class.
The downside is that you won’t get Intellisense due to the late binding.
Debugging and Editing Code in a Library File
You can debug code that is in a Library .mdb file from your Front-End, but you
CANNOT edit code in a Library from your Front-End.
BEWARE: You can make changes, compile them and test the result, but any changes
you make will NOT be stored once you close the file.
To edit your Libraries, you MUST open the Library file itself.
Accessing Data in Library Tables
One possibility is to link the Library Tables to your Front-End. However, this
involves binding your Front-End to a specific location of the Library file and
it reveals your Library tables in the Front-End’s database window (not always a
good thing!). It also involves an extra step that is not, strictly speaking,
necessary.
The following techniques will cover most of your requirements.
Library Queries
In your Libraries you can create Queries that use the Library Tables.
To display a DataSheet view of these queries from your Front-End, simply use the OpenQueryInSimpleLibrary style wrapper that we discussed earlier.
SQL Strings and the IN Clause
The best way to access data in your Library file tables is to use the IN sql
clause. Eg:
SELECT MyLibraryField FROM MyLibraryTable
IN 'C:\SampleAppFolder\Resources\Libraries\SimpleLibrary.mdb';
See Garry's Article on
remote queries
This code requires your Library to be installed in a specific location. To do
this in a generic way, you can write a wrapper function in your Libraries such
as:
Public Function SqlInSimpleLibrary () As String
SqlInSimpleLibrary = "IN """ & CodeProject.FullName & """"
End Function
(Note that we have used CodeProject to get the Library file path, not
CurrentProject!)
You can then use this Function to build your sql strings as follows:
strSql = “SELECT * FROM MyLibraryTable ” & _
SqlInSimpleLibrary() & “;”
You can now bind your Library data to Front-End forms, create recordsets, etc.
Eg:
Forms(“MyFrontEndForm”).Recordset =
strSql
Subforms? Sadly, no
You cannot use a Library form as a subform of a Front-End form.
Access requires subforms to be part of the same Project’s corresponding AllForms
collection so your Library forms, which are NOT part of the Front-End’s AllForms
collection, are not eligible. As only Access can add form objects to the
AllForms collection, there is nothing you can do about this.
Deploying Library Files to your Client’s PCs
One of the great features of Access is that you put so much into just one file,
which makes it really easy to just deliver your work onto your Client’s
machines.
When using Libraries, you have broken out of this comfort zone and your
Front-Ends now store references to precise locations where the Libraries are located.
Before your heart sinks, let me say, yet again, that the solution is again quite
simple. We will look at two separate case:
1. THE Front-End IS AN .MDB FILE:
An .mdb file's references are 'self healing'. Ie, if the User’s folder structure
is different to your development machine, Access will initially look for the
Libraries in the absolute path you set in Tools|References dialog of the VBA
Editor. If Access does not find the Library file there, it will look for them
under the same relative path from the Front-End file. If it finds them, it will
reset the references, otherwise it fails and you get an error.
2. THE Front-End IS A .MDE FILE:
In an .mde file, you cannot change the references, so you have to plan carefully
how you will deploy your Libraries. You have a variety of strategies that you
can use, but all of them require a specific location for the Libraries. For
example, most PCs have a C Drive, so you can create a folder on your Development
machine, for example C:\AccessLibraries\MyApp, and install the Libraries for
MyApp there.
At all times you have to remember that, if your Libraries have tables that your
Front-End will write to, for example, UsersColorsTbl in the Sample, you must
install them to a location where your User has Write Permissions to. Please note
that quite often Users are not give write permissions to the C:\Program Files\
folder, so it is not a good idea to install your libraries there.
Whatever you decide to do, the rule of thumb is: Using Libraries is simple, so
keep it simple!
Conclusion
I have shown a bullet proof way of using Access .mdb and .mde files as reusable
Libraries of generic functionality.
Using these Libraries is relatively simple if you are a good Access developer: just set the necessary references and
then, at most, write a few standardised wrapper methods and away you go, taking
care to use CodeProject where appropriate.
In a future article, we will discuss advanced scenarios and architectures that
can open up a whole new world. For example, Swift SQL, an Access SQL editing and
versioning tool that I have designed, is really just a Library file on steroids,
with a bit of Com Add-In technology thrown in. For most cases, however, this
article is more than enough to get you started.
Health Warning 1: Fixing Library bugs is tedious, so try to test your
code thoroughly before moving it to a Library file!
Health Warning 2: Libraries are extremely useful when used for the right
reasons, but they add a layer of complexity that you should avoid in many other
scenarios!
So start simple and only add your tried and tested and very generic stuff where
necessary.
About the Author
Andrew Wrigley develops Access, SQL Server and ASP.NET apps for medium sized
clients around the World. He is the author of Wingspan Swift SQL, a SQL editing
and versioning tool that brings editing Access SQL into the 21st century. For
more details and a free 14 day trial go to:
http://www.wingspan.info/Support/SwiftSql/StoryBoard.aspx

Downloads
Click here for the
simple library download file if you own "The Toolshed"
Click here for the
daisy chain library download file if you own "The Toolshed"
Else click here to find out how to purchase the Toolshed
and help us help you.
Other Pages at VB123.com That You May
Want To Visit
Remote Queries In
Microsoft Access
Taking Outlook and XML
to Task in MS Access
Duplicate Data Entry For Access
Form Based Selection
Criteria For Queries using Combo Boxes
Further External Reading:
Tony Toews (Access MVP) website:
http://www.granite.ab.ca/access/addins.htm
VBA References
http://support.microsoft.com:80/kb/824255/
Click on the
button for the next
help page in this Access Loop.
Appendix
Library Daisy Chains
Whilst most Access developers will never want to get into this situation, it is
possible to setup libraries that call other libraries. There are some advanced
scenarios where this is desirable. For the adventurous and the curious, here are
my notes on the subject.
The DaisyChainSample shows an example of this. It does exactly the same things
as SimpleSample, but now we have split most configuration functionality into a
ConfigLibrary.mdb, and all User specific functionality, eg, User Preferences,
into a different Library called UserSpecificLibrary.mdb. The rest of the
SimpleLibrary.mdb is now called GenericLibrary.mdb.
So, a Library can also reference another Library in a sort of daisy chain. For
example, in DaisyChainSample, you will see that ConfigLibrary.mdb is referenced
by GenericLibrary.mdb. This would make sense if you had a lot of similar apps
that just differed in configuration details. For example, the web behaviour
‘style sheet’ that sets what colors your controls will change to when the mouse
rolls over them. Different apps will have different color schemes, and this is
one way you can do it.
A few caveats apply:
1. SETTING DAISY CHAIN REFERENCES
Any file that uses a Library file must have a DIRECT reference to it. This is
because of the way the Access compiler treats each Project. In our sample:
FrontEnd.mdb MUST have a direct reference to GenericLibrary.mdb AND
ConfigLibrary.mdb, EVEN if GenericLibrary.mdb already has a reference to
ConfigLibrary.mdb.
2. CONVERTING YOUR DAISY CHAINED LIBRARY FILES TO .MDE FORMAT
With ‘daisy chained’ libraries you need to strictly convert them from the
outermost Library (eg, ConfigLibrary.mdb) inwards, ending up with the Front-End
(FrontEnd.mdb).
You will then need to reset your references as you go: in our sample, before you
convert GenericLibrary.mdb, you have to change the ConfigLibrary.MDB reference
to ConfigLibrary.MDE! Otherwise, your ‘innermost’ projects will be referencing
an .mdb file that will not be deployed!
Classes that Raise Custom Events
A separate advanced topic is using Library classes that raise their own custom
events.
Application design best practices suggest that your Library classes should raise
events to be handled by the Front-End classes (or form/report modules) where
they are used. However, in VBA, this is not as easy as it should be and we will
cover this issue in a future article. If you need this feature now, contact me
by email. Be warned that you need to delve in undocumented features of VBA to
get this to work.
Mark Plumpton, another reader discusses his approach
Interesting article about use of libraries. WingSpan will
definitely be a website to watch!
I used to use the method described a long time ago but came unstuck for 2 main
reasons:
- using mde front end which was not self-healing (as pointed out in the article)
- this meant a new library file also required a new frontend to be installed.
Andrew insists that it is "Mark Plumpton says that a new library file
requires a new front end, this is not true unless:
1. You change the location of the Library
or
2. You change the name of the file.
In all other instances, an updated library is just copied into the correct
folder and away you go."
Regards Andrew
- my reference libraries were constantly being expanded and updated! - I wanted
to edit then on the fly.
- (reason 3 - I was still really a newbie!)
As a result I went away from common libraries and now store all my common code
in text files - one per module in a source code folder. I have written a number
of "macro-functions" that allow me to import/export the modules and keep a
version number and update comments. Another function compares all the modules in
my existing project with the source code folder so I know which ones need
updating. I also have functions to insert global error calls and line numbering.
In Access 2000+ I just hit the F5 key and run the required function. See screen
shot below of how it looks.
Read more here
It would be really interesting to know how other developers work with these
issues in Access.
regards,
Mark Plumpton
Custom Data Solutions Ltd
UK