Cleaning Up Your Shared DLLs Registry References for MSIs

The legacy shared DLLs reference counting is a mechanism by which the Windows Operating System ensures that files which are shared are reference counted, so that if a product attempts to uninstall a file which is used by another product, then the file is not deleted.

The reference counts reside in the registry key:

[HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionSharedDLLs]

Each file has an individual entry with a REG_DWORD integer value which is the count itself.  As each uninstall is executed, the individual counts for those files are decremented and the file remains intact on the workstation until the count reaches zero, at which point the file is finally deleted.

What Is Wrong with That?

Who decides whether it is shared or not?  If I build an MSI installer which ships a file to any folder and I say it is shared, then a reference count is created and managed.  If another software vendor makes a product legacy installer which just so happens to have the same file in the same location and they decide NOT to set it as a shared file, then their installer will not update my reference count, so when they uninstall their product, my file is likely to be removed.

Software vendors often handle this key poorly. You will sometimes find file reference counts have been setup as REG_SZ string values not REG_DWORD integer values and so cannot be incremented or decremented correctly by installer engines.

SharedDLL_1

Some vendors have decided to never let the file be removed by manually setting unfeasibly large values in their reference counts, essentially making them permanent files.

SharedDLL_2

Finally, because the reference count is simply an integer value (1, 2, 3, 2, 1, 0), it is not possible to tell if I am decrementing the value I incremented earlier or I am decrementing the count which some other installer incremented.  Ideally the count should be shared amongst all products but registered against the individual product, which is the method Windows Installer uses and removes the possibility of decrementing somebody else’s count.

Although this mechanism of sharing files pre-dates the Windows Installer reference count, it does interact with these registry keys and will not remove a file which has non-zero SharedDLLs count.  In addition Windows Installer reference counts the component in a different part of the registry (but that is not discussed here).

Why Does It Need Fixing?

If, for whatever reason, these reference counts remain after the file has been removed, then your MSI install will be preserving a count that is no longer relevant. This will result in unexpected uninstall results, especially after having applied a patch or a major upgrade to a product.  If the file is no longer present, there is no reason to keep the reference count, especially if it affects future maintenance of the product.

What Can We Do About This?

The following script enumerates the SharedDLLs Registry Key and checks to see if all the files still exist, any which do not are removed and are noted in a report file. It is a simple Windows Managements Interface script to improve the health of your SharedDLLs reference counting.

const HKEY_LOCAL_MACHINE = &H80000002
const ForReading = 1, ForWriting = 2

Set wmoReg = GetObject("winmgmts:{impersonationLevel=impersonate}!.rootdefault:StdRegProv")
RegPath = "SOFTWAREMicrosoftWindowsCurrentVersionSharedDLLs"
Set fso = CreateObject("Scripting.FileSystemObject")
Set f   = fso.OpenTextFile("C:BadSharedDLLs.txt", ForWriting, True)
f.WriteLine "Removed SharedDLLs reference count for missing files:"
f.WriteLine " "

wmoReg.EnumValues HKEY_LOCAL_MACHINE, RegPath, Names, Types
For i = 0 To UBound(Names)
If Not fso.FileExists(Names(i)) Then
f.WriteLine "FileName: " & Names(i)
wmoReg.DeleteValue HKEY_LOCAL_MACHINE, RegPath, Names(i)
End If
Next

Tags: ,

7 comments on “Cleaning Up Your Shared DLLs Registry References for MSIs

  1. Cary Roys on

    An aside for those looking to manipulate reference counts while an MSI package is running.

    Windows Installer handles updates to reference counts in two phases, so you have to make sure that you get your logic in place before it starts or after it’s finished, and not in between:

    –Enumeration of counts takes place during CostFinalize. This determines what the counts will be set to later in the install. If you clear out counts after this, they could be rewritten to bad values later in the install.

    –Writing the new reference counts takes place during the publishing of the product information (likely PublishComponents, but I can’t be 100%). If you want to do post-install cleanup, do so after InstallFinalize to be on the safe side.

    Reply
  2. ChezWhiz on

    I figure someone has probably already written this in C++ so I was wondering if anyone had a link to such a C++ sample code example so this can be done by invoking an entry point function in an MSI custom action DLL rather than via script?

    Reply
  3. Flexera on

    We would recommend running the script outside of InstallShield. But to include it in the installation, you would use a custom action to run it and schedule it at the very beginning of the install.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *