The blog of dlaa.me

Posts from March 2006

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

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

I recently had occasion to use a particular tool for the first time and found that it didn't work on my machine. This was weird, because nobody else seemed to have any problems running the same tool on their machines. So I set out to determine what was wrong...

Simplifying things ridiculously for the purposes of this example, I'll note that the tool manipulates ZIP files, has a reference to "vjslib", and is compiled from code that looks something like this:

using java.util.zip;

class Program
{
    static void Main(string[] args)
    {
        new ZipFile("file.zip");
    }
}

(Aside: In case you're wondering what's up with the "java.util.zip" namespace and the reference to "vjslib.dll", I'll suggest that the author of this tool was probably following the recommendations of the article "Using the Zip Classes in the J# Class Libraries to Compress Files and Data with C#" which recommends exactly this approach. You may be aware that .NET 2.0 offers support for compressed streams via the classes in the new System.IO.Compression namespace. However, support for compressed streams is not the same thing as supporting the ZIP file format, so I believe this technique is still relevant.)

When run on my machine, the tool produces the following output (inadvertent profanity due to default 80-column wrapping of "assembly" removed for your protection):

Unhandled Exception: System.IO.FileNotFoundException: Could not load file or as*
embly 'vjslib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
' or one of its dependencies. The system cannot find the file specified.
File name: 'vjslib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d
50a3a'
   at Program.Main(String[] args)

That's odd, because my computer DOES have the Microsoft Visual J# Version 2.0 Redistributable Package installed as required (it comes with a Visual Studio Team Suite full install). But it's worth checking the GAC (Global Assembly Cache) anyway, just to be sure that vjslib is present there as we expect:

C:\Program Files\Microsoft.NET\SDK\v2.0 64bit>gacutil -l vjslib
Microsoft (R) .NET Global Assembly Cache Utility.  Version 2.0.50727.42
Copyright (c) Microsoft Corporation.  All rights reserved.

The Global Assembly Cache contains the following assemblies:
  vjslib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, pro
cessorArchitecture=x86

Number of items = 1

Yup, it's in there. So why can't it be found by the tool? To try to answer that question, we turn to the Assembly Binding Log Viewer (Fuslogvw.exe). Just run the viewer, enable the "Log bind failures to disk" setting, run the tool again, then refresh the viewer and open the failed binding entry to see the following (abbreviated) output:

*** Assembly Binder Log Entry  (2006-03-23 @ 10:52:44 AM) ***

The operation failed.
Bind result: hr = 0x80070002. The system cannot find the file specified.

...

LOG: Post-policy reference: vjslib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
LOG: GAC Lookup was unsuccessful.
...
LOG: All probing URLs attempted and failed.

Hum, that's really odd... We know vjslib is in the GAC, yet it can't be found in the GAC. My machine is correctly configured, has the necessary components installed, and appears to be working fine in every other respect.

So what's going on here??

(Stay tuned for the exciting answer in Part 2!)

Tags: Technical

Working hard / hardly working [A bit about my new team]

My new team (affectionately known as the Agility Team (not to be confused with the A-Team)) is small and new and kind of different from the typical Microsoft team. I've been asked what it's all about, but haven't really had a clear, concise answer until now. My new manager, Shawn Burke, just wrote a post in which he outlines the nature and purpose of the team. He even gives a brief description of our current project which, if you've been paying close attention, was hinted at by Scott Guthrie in a recent post about Atlas. Like Shawn says in his post, this project is pretty cool stuff and I'm really looking forward to seeing what customers do with it once they get their hands on it. "I love it when a plan comes together!"

An image is now worth two thousand HTML tags [How to: Use ASP.NET's IHttpHandler interface to display a custom image]

In a previous post, I referred to some MSDN sample code and outlined the process of creating an ASP.NET page to display an image instead of HTML. As is often the case, the relevant sample code was written to demonstrate a concept rather than to be "production-ready". In one of the comments for that post, Heath Stewart suggested the use of a .ashx file as a more efficient way to do the same thing. This seems like a great opportunity to learn a little more about ASP.NET, so let's give it a try!

First, a little research is in order - I recommend starting with the documentation for Creating HttpHandlers and following up by learning a little about the corresponding IHttpHandler Interface. Armed with that knowledge, we should be able to convert the modified sample code over to the IHttpHandler interface.

Begin by creating a new file in the web site directory you were already using. I used Visual Studio's "Add New Item" action to add a "Generic Handler" page that was automatically named Handler.ashx. I then pasted in the existing code from my earlier post, tweaked a few minor things, and had a working IHttpHandler in considerably less time than it's taken me to write this post. :)

Here's what I ended up with in my Handler.ashx:

<%@ WebHandler Language="C#" Class="Handler" %>

using System.Drawing;
using System.Drawing.Imaging;
using System.Web;

public class Handler : IHttpHandler
{

    public void ProcessRequest(HttpContext context)
    {
        // Set the page's content type to JPEG files
        context.Response.ContentType = "image/jpeg";

        // Create integer variables.
        int height = 100;
        int width = 200;

        // ...

        // Create a bitmap and use it to create a
        // Graphics object.
        using (Bitmap bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb))
        {
            using (Graphics g = Graphics.FromImage(bmp))
            {

                // ...

                g.Clear(Color.LightGray);

                // ...

            }

            // Save the bitmap to the response stream and
            // convert it to JPEG format.
            bmp.Save(context.Response.OutputStream, ImageFormat.Jpeg);
        }
    }

    public bool IsReusable
    {
        get
        {
            return true;
        }
    }
}

As you can see, the code is almost identical to the initial Page-based implementation! The only thing I think is worth calling out is that I've chosen to return "true" for the IsReusable property. The documentation for the IHttpHandler.IsReusable Property suggests that this property can be used to prevent concurrent use of the instance. Since our simple implementation doesn't make use of any global state, it should be safely reentrant, and therefore returns "true" to help ASP.NET avoid creating unnecessary instances of the class.

There you have it: a simple change that gives us an implementation consuming fewer resources and consequently scaling better on a busy web server. Thanks for the great suggestion, Heath!!

Tags: Technical

Start using using today! [A bit about the IDisposable interface and the using statement]

There's plenty to say about the IDisposable interface and the using statement, but you probably don't have time to read it all (and I don't have time to write it all!), so I'm going to try to keep this short and simple.

First, let's make sure we're all on the same page. If you're not familiar with the relevant concepts, please take a moment to learn about .NET Garbage Collection, the IDisposable interface, the using statement, and the use of objects that implement IDisposable. (If you're a bibliophile, I understand that the book "Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries" (ISBN 0321246756) contains additional material in section 10.3, "Dispose Pattern".)

Now that we're all familiar with the concepts, I'd like to call attention to a few things:

  • Implementation of the IDisposable interface by the author of a class is optional and completely unnecessary for a correctly written class. Even without IDisposable, the Garbage Collector will eventually clean up all of the class's resources (possibly with the help of a Finalize method override).
  • However, without IDisposable, there is no way of controlling *when* a class's resources will be cleaned up. The Garbage Collector (GC) runs only when it needs to, so it could be seconds, minutes, or even hours after you're done using a class before the GC runs and cleans up those resources. Any resources held by that class (like file handles, sockets, SQL connections, etc.) will remain in use until that class is cleaned up by the GC. This can cause unexpected problems when, for example, the user has closed a file in an application, but the application continues holding on to that file and prevents the user from copying it, moving it, etc.. Worse still, such problems will occur "randomly" according to whether or not the GC has run.
  • So it's a good practice to call IDisposable.Dispose whenever you're done using a class that implements IDisposable so that its resources can be freed immediately and deterministically (i.e., predictably). As a side effect, this helps minimize the resource consumption of your application which always makes users happy.
  • However, simply adding a call to Dispose at the end of a block of code isn't a complete solution because it means that Dispose won't get called if an Exception is thrown anywhere within that block of code. If you're going to call Dispose, you want to *always* call Dispose, so you really want the call to Dispose to be within the finally block of a try-finally statement pair.
  • To address this, you can manually add a try-finally pair, *or* you can use the using statement which does so for you! Under the covers, the using statement maps to a try-finally pair which calls Dispose for the specified object within the finally block, but the beauty of the using statement is that it's a simpler, more concise way of doing so that keeps all the relevant code in one place and hides the gory details from view. You can even declare and initialize the object in the using statement itself! (See the documentation for using for examples.)

With these points in mind, I propose following guidelines whenever dealing with an object that implements the IDisposable interface:

  • Always call the object's Dispose() method
  • Call Dispose() under all conditions (i.e., within a finally block)
  • Call Dispose() as soon as you're done with the object

Conveniently, the using statement makes it easy to do *all* of these things! The using statement is a simple programming construct that's very readable and that helps your code perform reliably, predictably, and efficiently. It doesn't get much better than that, so if you aren't already, please start using using today!

Tags: Technical