Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generate list of every possible VBA reference GUID

I have an Access database I created in Access 2016. I have some VBA code that requires some libraries in Access 2016. Most other users have different, aged versions of Access.

For instance, one library I need to run the code is Microsoft Access 16.0 Object Library. Many users are running Office 2013, which has Microsoft Access 15.0 Object Library instead of 16.0.

I need to programmatically add this version of the library when they run the VBA code. This would require me to know the GUID, which I have been unable to find online. All other areas I've researched tell you how to get the GUID of libraries you have active, but this won't work for me becuase I cannot use or fine the 15.0 library.

How can I find the GUID for this library, and for other libraries I do not have active or installed?

like image 495
J. Cal Avatar asked Nov 01 '25 20:11

J. Cal


2 Answers

Programmatically adding 16.0 when 15.0 is installed will likely only cause more crashes, and won't solve your problem.

Early-bound code (i.e. with a project reference to the type library) is version-specific, which means if your user is running a different version, you can expect problems.

Late-bound code (i.e. without a project reference to the type library) isn't version-specific: if your user is running a different version, then the late-bound calls will resolve at run-time to the appropriate method that exists in whatever version your user is running. If it exists.

That last point is key: if your code uses functionaliry that only exists in the 16.0 library, then you can expect run-time error 438 "Object doesn't support this property or method" to be thrown at your users' face regardless. Hence, write your code so that it can run on the lowest available version.

If you don't know what API differences there are between versions, then your only hope is to use the users' earliest version for development.


Write your code with early-bound declarations and calls; that way you get IntelliSense and autocompletion, and you can browse the Object Browser (F2) to explore what's available.

Avoid using enums and constants that exist in the type library: declare your own instead, and duplicate the underlying values (the Object Browser is great for this). Once you switch to late-bound code, these enums and constants won't be defined anymore, unless you defined them yourself. Make sure Option Explicit is specified, so that if you happen to forget one somewhere, you'll get a compile-time error telling about it, instead of silently passing a wrong value at run-time and experiencing weird, hard-to-debug behavior.

When you're ready to deploy, comment-out all the Dim accApp As Access.Application and other early-bound declarations; replace with Dim accApp As Object (Object is what's making the calls late-bound / resolved at run-time).

Then replace all Set foo = New XYZ assignments with CreateObject calls, e.g. Set accApp = New Access.Application would be Set accApp = CreateObject("Access.Application"). This is what instructs the runtime to go hit the registry to figure out where the type library for that ProgID might be. If that ProgID doesn't exist on the user's machine, things will blow up, at run-time.


As for the question as asked, Ross Knudsen's Kavod.ComReflection GitHub repository contains some clues:

private static IEnumerable<ComTypeRegistryEntry> GetComTypeRegistryEntries()
{
    using (var clsidRootKey = Registry.ClassesRoot.OpenSubKey("TypeLib"))
    {
        if (clsidRootKey == null)
        {
            yield break;
        }

        foreach (var typeLibKey in EnumerateSubKeys(clsidRootKey))
        {
            var currentTypeLib = GetCurrentKeyName(typeLibKey);
            Guid clsid;
            if (!Guid.TryParseExact(currentTypeLib, "B", out clsid))
            {
                Debug.WriteLine($"Couldn't parse CLSID = {currentTypeLib}");
                continue;
            }

            foreach (var entry in EnumerateRegistryEntryVersions(typeLibKey, clsid))
                yield return entry;
        }
    }
}

If you really want to get a list of all registered type libraries and their respective GUIDs, you need to scan the Windows Registry's ClassesRoot node and locate all TypeLib subkeys. This could be pretty fun to implement in VBA, but IMO not very useful for what you're trying to do.

like image 121
Mathieu Guindon Avatar answered Nov 04 '25 11:11

Mathieu Guindon


Unless on your machine you have Office 2013 installed, you will not have access to Microsoft Access 15.0 Object Library. Likewise, unless your users have Office 2016 installed, they will not have access to Microsoft Access 16.0 Object Library. However, vba code that references Microsoft Access 15.0 Object Library will still work if you have Office 2016.

So as I said in my comment, you need to develop your vba in the lowest common denominator when it comes to Office. i.e. If your earliest version of Access is 2010, then you need to develop in 2010.

Furthermore, 14.0 Object Library will work for 15.0 Object Library will work for 16.0 Object Library and so on but not the other way around. So as you see, if you develop something in Office 2010, it should still work in 2016. At least, you shouldn't have any library reference issues.

WARNING EDIT

Just remembered an awesome time I had while trying to debug some code. If you develop in Office 2013 and save your macro document, and then alter the document using Office 2016 and save it, Office will automagically choose what it deems the correct version of the Object Library, which would be 16.0. Which would render the macro document useless to your Office 2013 users.

like image 38
interesting-name-here Avatar answered Nov 04 '25 09:11

interesting-name-here