The blog of dlaa.me

When the GAC makes you gack (Part 2) [How something can be both IN and NOT IN the GAC at the same time]

In Part 1 we investigated a curious tool failure and discovered that it's possible for something to be both IN and NOT IN the GAC at the same time. The results of the investigation so far have been informative, but unrevealing. So let's try another approach...

The Sysinternals Filemon tool should let us see exactly where the tool is looking for vjslib.dll and maybe that will help figure out why it can't be found. Run Filemon, specify a filter of "*tool_name*" to limit the output, then run the program of interest. Filemon will capture a whole bunch of stuff, so save the output to a file where it can be searched more easily. We'll start with a simple string search for "vjslib" to see what turns up:

D:\Temp>findstr vjslib Filemon.LOG
327     6:58:10 PM      GACBlog.exe:212 QUERY INFORMATION       C:\WINDOWS\assem
bly\GAC_64\vjslib\2.0.0.0__b03f5f7f11d50a3a     PATH NOT FOUND  Attributes: Erro
r
328     6:58:10 PM      GACBlog.exe:212 QUERY INFORMATION       C:\WINDOWS\assem
bly\GAC_MSIL\vjslib\2.0.0.0__b03f5f7f11d50a3a   PATH NOT FOUND  Attributes: Erro
r
329     6:58:10 PM      GACBlog.exe:212 QUERY INFORMATION       C:\WINDOWS\assem
bly\GAC\vjslib\2.0.0.0__b03f5f7f11d50a3a        PATH NOT FOUND  Attributes: Erro
r
...

Oooh, that's interesting, there seem to be multiple GACs: GAC_64, GAC_MSIL, and GAC each get probed unsuccessfully. But we recall from Part 1 that gacutil told us vjslib was in the GAC, so what GAC is it in??

C:\WINDOWS\assembly>dir vjslib.dll /s
 Volume in drive C is C
 Volume Serial Number is 0C48-9782

 Directory of C:\WINDOWS\assembly\GAC_32\vjslib\2.0.0.0__b03f5f7f11d50a3a

2006-02-21  11:18 AM         3,661,824 vjslib.dll
               1 File(s)      3,661,824 bytes

     Total Files Listed:
               1 File(s)      3,661,824 bytes
...

Ah-ha! There's a fourth GAC, GAC_32, that contains the required assembly, but that GAC isn't getting checked when the tool is run and so the tool is failing.

At this point we can begin to guess that the problem is unique to my machine because I'm the only person who's trying to run the tool under a 64-bit OS. (Which also explains why most people won't have been able to reproduce this problem with the sample code in Part 1.) Now that we understand the problem a little better, we can pretty easily find more detailed information about what's going on by doing some quick web searching. In this case, Junfeng Zhang's post GAC, Assembly ProcessorArchitecture, and Probing explains the motivation behind multiple GACs.

Okay, so we've figured out what the problem is: the tool is compiled to be architecture-independent and the GAC probing sequence for architecture-independent programs on 64-bit OSes does not include the architecture-dependent 32-bit GAC where vjslib.dll is actually installed. The question now becomes how to fix the tool so that it will run successfully on both 32- and 64-bit OSes.

My first thought was to find out how to modify the probing sequence for the tool in order to include the 32-bit GAC. While that may be possible and that approach may work, a little more thought convinced me it wasn't the right approach to take here. The way I reasoned, if the tool has a dependency on a 32-bit reference, then the tool is not really architecture-independent after all! The problem is that the tool is claiming to be something it's not and that's what's causing it problems. If, when we compiled the tool, we were to specify the platform target of "x86" instead of "Any CPU" in Visual Studio (or using the /platform C# compiler option), then the tool should run successfully because it would naturally probe the 32-bit GAC where vjslib.dll lives.

And, indeed, that simple change fixes the tool, solves the problem, and answers the question of how something can be both IN and NOT IN the GAC at the same time! This investigation was a neat learning experience for me - I hope it's as much fun to read about as it was to experience! :)

Tags: Technical