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