[AccessD] libraries, References and some subtleties to be considered

jwcolby jwcolby at colbyconsulting.com
Thu Dec 15 15:37:27 CST 2011


I use libraries - MDAs - to hold common code, variables and constants.  Libraries are essentially 
places to put common code so that many different applications can do things the same way.  If a bug 
is found it can be fixed in the library, in just one place.

It is possible for a lib to reference another lib.  For example my C2DbFW3G understands and uses my 
Presentation Level Security System and so it references C2DbPLSS.  However C2DbPLSS is a standalone 
library, i.e. it can be used without my FW3G.  Should I have just merged the two into one big lib? 
That is a conversation for another day.

While on this subject, two more things.  There can be no circular references between libs, i.e. FW3G 
cannot reference PLSS *and* PLSS also reference FW3G.  Any lib can reference another lib but the 
reference can never "circle back around".  Additionally the order of reference comes into play if 
there are two functions, classes, variables etc with the same name.  We all understand the scope 
thing (local function, module, global) but the same issue exists in libraries in that if a name is 
not found in the local container the compiler starts looking at other referenced objects, starting 
from the top reference in the references dialog and working down.

This can cause oddities if we have a function (for example) with the same name found in the 
application and the library.  Code in the application will use the function inside of the 
application container, whereas code in the library will use the function in the library container. 
If you use libraries and you write a function and move it to the library, do not forget to delete 
the function from the application or you will have problems.

I have two main libraries, C2DbFW3G which is the 3rd generation of my framework, and C2DbPLSS which 
is my Presentation Level Security System.

Having an application reference a library causes some issues shall we say which do not exist if you 
do not use them, and I just thought I would walk through my findings and how I handle things in 
order to start a conversation on the subject.

Some tidbits in no particular order.

When the developer references a library they do so via a browse button and so the reference ends up 
specific to a location available from the developer's machine.  This implies that the location may 
or may not be available to another user opening the application.

When the application opens, it tries to find the file at the location specified in the existing 
reference.  If found it uses that copy of the library, no questions asked.

If the library cannot be found at that referenced location then the application silently begins to 
search a set of paths to find the library.

http://support.microsoft.com/kb/824255

If the library is found the search immediately ceases and the reference is "fixed up" to point to 
that location.  When the application closes it saves that new reference location.  So the 
application has been silently "re-referenced" to the new location.  When I say silently, I mean that 
there is no immediate in-your-face indication that any of this happened.

This silent re-reference can cause odd problems.  Let's take some real life scenarios that I 
encounter at my client.

I have a directory on my C: drive at the client called C:\Dev\DisNew\  This path, in particular the 
Dev\ part, is unique to my machine (standing for development).  I build a framework and an 
application in this location.  I reference the lib from the application, browsing to that location 
and voila, the reference points to a library in a location that does not physically exist anywhere 
else in the company.

I copy the two files up to X:\DisNew\Test which is the production (X:\DisNew) test directory.  the 
user has a batch file which builds a directory on their local C: drive, copies the library and 
application to that local directory and opens the application.  The application tries to find the 
lib at my dev directory and fails, so it tries to find it in the local directory and succeeds.  Life 
is good.

Now... I go into the X:\Disnew\Tester directory and open the application file.  Guess what happens? 
  The application opens and tests the reference and... finds it because it can see my dev path.  The 
file works.  Life is good, nothing changes.

A user goes into the X:\DisNew\Tester directory and opens the application file and ... the 
application cannot find my dev directory so it starts "the search".  It finds the library in the 
X:\DisNew\Test directory and re-references and the application works.  Now when the user closes the 
file... the file is referenced to the lib on the network.  Life is no longer good!

Now we decide that the application file tests good and copy it to production where it is copied, 
along with the lib down to the user's hard disk.  The user opens the copy on their hard disk and... 
the application is referenced to the lib on the network (test directory) and so it opens the lib on 
the network.  Now I am trying to copy a new version of the lib to tester and the file is locked.  Or 
something.  Life is not good.

Let's discuss decompile for a minute.  Decompile flushes the pcode buffers in the Access container, 
which, simply put, means that all of the "compiled" code is flushed out.  Yes I understand that 
Access is an interpreter but it actually compiles the English (VBA) language stuff we write into 
P-Code and interprets the P-Code.  The compile of the Decompile / Compile matched pair simply 
recompiles every single line of VBA code into P-Code and stuffs it back into the buffers.

When you perform a decompile / compile, you *REALLY* need to decompile / compile the library first, 
then the application using the application.  I don't understand all of the stuff but apparently 
there is a table of pointers built by the compile, things like the entry point to functions and the 
locations of constant and variables.  Apparently when you compile the application, it goes out and 
searches the library for these tables in order to correctly call functions and variables in the library.

But why do we do a decompile / compile in the first place?  Because it is possible and in fact not 
uncommon, for the P-Code to get corrupted over time.  If the lib is corrupted and you recompile the 
app, then the app calls into corrupted lib stuff.  So, decompile / compile the lib *before* you 
decompile the application that references the lib.  And if you decompile / compile the lib, then you 
must must *must* recompile the app because the lib entry points and variables might change.

Guess what?  If you happen to get confused and decompile / compile anything on a network share... it 
may (or may not) cause weird things like the app refusing to close.  So never never *never* 
decompile / compile anything that is not local to your hard disk.

Unfortunately the simple fact that FW3G references the PLSS does not expose the PLSS on through to 
the application.  So C2DbFW3G references C2DbPLSS and the application references C2DbPLSS *and* 
C2DbFW3G because it directly uses code in both.  Oh my goodness.  Now I have to decompile / compile 
the PLSS first, then the FW3G (because it references PLSS), and then the application (which directly 
references both libs).  All of this must be done on my local machine so as to avoid the "can't 
close" issue discussed above, and then copied to the final destination for public consumption.

Furthermore I need to make sure that I reference the PLSS in the FW3G to the DEV path on my local 
machine, and likewise reference PLSS and FW3G inside of the application to the dev path of my local 
machine.  Why?  Because that path is not public to the company and will trigger the re-reference 
when the user downloads all this stuff to their local machine.

But wait, there's more.  I have three different applications that use the PLSS and the framework. 
So if I decompile / compile the PLSS / FW3G, all of the applications that use these libs need to be 
recompiled.  Again, if I make changes to the libs, any app that I do not decompile will not 
reacquire the pointer tables in the libs and may start to fail.

And around and around we go.

I use batch files to copy these pieces to the user's system so that the user ends up with local 
copies and doesn't end up permanently re-referencing things back to the production location.  This 
works reasonably well as long as everyone plays by the rules.  If anyone (other than myself) 
actually opens any of these files up in tester or production, then the references silently change 
and things go south in a hurry.  It took me awhile to figure out that this was happening (a long 
time ago) and it took me awhile to remember that this occurs when I started having strange things 
happening recently.  That is the reason for starting this thread, to remind the list how this stuff 
works and to get input from other list members on their experiences with this stuff.

I am a believer in libraries to hold common code.  They exist for the simple reason that changes to 
that code, bug fixes etc can be done in one place and propagated to every place the change is 
needed.  It is important to understand what goes on behind the scenes however or you can have some 
strange things happening that will be very difficult to figure out.

-- 
John W. Colby
Colby Consulting

Reality is what refuses to go away
when you do not believe in it




More information about the AccessD mailing list