Поделиться через


Checking if a Windows Side-by-Side assembly is installed

Centrally installed Windows Side-by-Side assemblies are located in the Windows\WinSxS directory. This is called the "Windows Side-by-Side Assembly Cache", a term that mirrors the Global Assembly Cache for managed assemblies. Let’s discuss how to check for files in this cache.

Why not just probe the WinSxS directory for the expected files?

The existence of files in this directory should not be taken as an indication that the operating system considers these files to be installed. True to its designation of "cache", the directory may hold on to recently-installed or soon-to-be-installed files until they are installed or scavenged in bulk. Scavenging happens periodically, but it cannot be controlled or induced. It is important to note then, that uninstalling a Side-by-Side assembly may not immediately remove the associated files from the WinSxS directory. This is expected, and not a violation of Windows Logo requirements for clean uninstall.

Second, the internal layout of this directory is not documented as it changes with each release of Windows. For this reason, direct paths into this directory should not be hard-coded for probing anywhere. (They should not even be computed & stored – if the user were to upgrade their OS since the time a path was computed the information would no longer be accurate.)

Programmatically checking install state

The easiest method to check whether an assembly is installed is to simply try to use it. While trying to run a program that depends on an assembly and checking for failure to launch is certainly a (heavy-handed) way of accomplishing this, perhaps the best approach is to use the Activation Context APIs.
Given a manifest "CheckMFC.manifest":

 <?xml version='1.0' encoding='UTF-8' standalone='yes'?> 
<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'> 
  <dependency> 
    <dependentAssembly> 
      <assemblyIdentity name="Microsoft.VC90.MFC" 
                        version="9.0.30729.1" 
                        processorArchitecture="x86" 
                        publicKeyToken="1fc8b3b9a1e18e3b" 
                        type="win32" /> 
    </dependentAssembly> 
  </dependency> 
</assembly>

Use the following code:

 BOOL fInstalled = FALSE; 
ACTCTXW acw = { sizeof(acw) }; 
acw.lpSource = L"CheckMFC.manifest"; 

HANDLE hActCtx = CreateActCtxW(&acw); 
if (hActCtx != INVALID_HANDLE_VALUE) { 
    fInstalled = TRUE; 
    ReleaseActCtx(hActCtx); 
}

Note that this code doesn’t check for version 9.0.30729.1 strictly – it will also flag success if there’s a compatible higher version installed (technically, if there is an installed assembly with a higher revision/build version that redirects 9.0.30729.1 through a publisher policy).

 

A second way to check is to use the Assembly Cache APIs directly, notably IAssemblyCache::QueryAssemblyInfo. Note that in general, these APIs are supported only on Vista and later, and may not be available or work as intended on earlier OSes. The difference with this method is that it requires you to know the exact details of the assembly you are looking for, including the full version number, Major.Minor.Revision.Build, which is overly restrictive if the question is "is there an installed assembly that will let my application run?"

 

In the next post, I will provide a simple tool to verify the installation of the Visual Studio redistributable assemblies.