Delay's Blog

Silverlight, WPF, Windows Phone, Web Platform, .NET, and more...

  • Delay's Blog

    Talkin' Toolkit [Speaking at the ASP.NET Connections conference in November]


    I'll be presenting the AMS302: "Atlas" Control Toolkit Unleashed: Creating Rich Client-Side Controls and Components session at the Microsoft ASP.NET Connections conference on November 7th in Las Vegas. The session's description is:

    The "Atlas" Control Toolkit is a set of controls and extenders designed to help ASP.NET developers easily integrate rich client UI features into their Web applications. As a community effort, the Toolkit contains controls written by Microsoft and non-Microsoft developers who have joined forces to create a powerful, shared-source library for all to use. You will learn how to integrate Toolkit components into your application as well as get an idea of how easy it is to create "Atlas" extenders using the Toolkit.

    If you will be attending the conference (or otherwise in the area) and would like to get together, please let me know and we'll make plans!

  • Delay's Blog

    Dynamic content made easy [How to: Use the new dynamic population support for Toolkit controls]


    One of the more frequent requests we've gotten for the "Atlas" Control Toolkit is some way to easily alter the content of a popup before displaying it to the user. Typically, page authors want to have a single popup element on their page that is used from multiple locations (often the rows of a data-bound server control) and they want the popup to display information specific to each location that displays it. For example, a page displaying multiple products might want a popup associated with each product to display additional details for that particular product.

    There was previously no easy way to accomplish this task, but with the 60914 release of the Toolkit, we've made it simple! The HoverMenu, ModalPopup, and PopupControl now all derive from new DynamicPopulate*Base classes (see the "Other neat stuff" page for details) and automatically expose four new properties: DynamicControlID, DynamicContextKey, DynamicServicePath, and DynamicServiceMethod. These properties behave just like they do for the DynamicPopulate control (please follow that link for more details) and the existing controls have been modified to call the "populate" function as part of their popup actions.

    What this means for page authors is that it's simple to add dynamic population to new/existing pages - what it means for control authors is that it's simple to add dynamic population to new/existing controls!

    Here's what dynamic population looks like in action (I've arbitrarily chosen ModalPopup for the demonstration):

    Animated demonstration

    The complete code for the sample follows; noteworthy sections have been bolded to make them stand out. The important things to note are:

    • The page content is generated by data binding an XmlDataSource to a DataList. The data are simple CSS style declarations that are used to decorate the dynamic content when it renders. The user can select which decoration to apply by choosing any of the links on the page.
    • Each row of the DataList includes a ModalPopupExtender declaration that pops a modal panel when the CSS style declaration is clicked. All ModalPopupsExtenders share the same popup element in order to avoid unnecessary duplication. The text of the row and the DynamicContextKey of the ModalPopupProperties are both set by a (data bound) call to Eval.
    • The popup (Panel1) contains both static content and dynamic content (Panel2). The static content includes the "OK" button that dismisses the popup. The dynamic content consists of the current server time which is styled according to the selected row's CSS style declaration and displayed in a random color.
    • The dynamic content is generated by a page method which uses its context key parameter to identify the specific row that is being dynamically populated. (Here, the context key is the CSS style declaration, but typically it might be a database index or row number.)

    That's all there is to it!

    Just save the following code to an .ASPX file in the SampleWebSite directory of a Toolkit installation if you want to try it out for yourself:

    <%@ Page Language="C#" %>
    @ Register Assembly="AtlasControlToolkit" Namespace="AtlasControlToolkit"
      TagPrefix="atlasToolkit" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

    script runat="server">
    public string GetContent(string contextKey)
    // Create a random color
        string color = (new Random()).Next(0xffffff).ToString("x6");
    // Use the style specified by the page author
        string style = contextKey;
    // Display the current time
        string time = DateTime.Now.ToLongTimeString();
    // Compose the content to return
        return "<span style='color:#" + color + "; " + style + "'>" + time + "</span> ";

    html xmlns="">
    head runat="server">
      <title>Dynamic ModalPopup Demonstration</title>

      <%-- Style the page so it looks pretty --%>
    <style type="text/css">
        body { font-family:Verdana;     font-size:10pt; }
    .background { background-color:Gray; }
    .popup { width:200px;             padding:10px;        background-color:White;
    border-style:solid;      border-color:Black;  border-width:2px;
    vertical-align: middle;  text-align:center; }
      <form id="form1" runat="server">

        <%-- Atlas pages need a ScriptManager --%>
    <atlas:ScriptManager ID="ScriptManager1" runat="server" />

        <%-- A very simple data source to drive the demonstration --%>
    <asp:XmlDataSource ID="XmlDataSource1" runat="server">
              <item style="font-weight:bold" />
              <item style="font-style:italic" />
              <item style="text-decoration:underline" />

        <%-- A simple list of all the data items available --%>
    <asp:DataList ID="DataList1" runat="server" DataSourceID="XmlDataSource1">

            How would you like your dynamic content styled?

            &bull; <asp:LinkButton ID="LinkButton" runat="server" Text='<%# Eval("style") %>' />

            <%-- The ModalPopupExtender, popping up Panel1 and dynamically populating Panel2 --%>
    <atlasToolkit:ModalPopupExtender ID="ModalPopupExtender" runat="server">
                TargetControlID="LinkButton" PopupControlID="Panel1" OkControlID="Button1"
                BackgroundCssClass="background" DynamicControlID="Panel2"
                DynamicContextKey='<%# Eval("style") %>' DynamicServiceMethod="GetContent" />


        <%-- All ModalPopups share the same popup --%>
    <asp:Panel ID="Panel1" runat="server" CssClass="popup" style="display:none;">
          <p>This popup popped at <asp:Label ID="Panel2" runat="server" /> and all was well.</p>
          <p><asp:Button ID="Button1" runat="server" Text="OK" /></p>


    If you found this "How to" helpful or if you have any suggestions for ways in which future "How to"'s could be improved, please let me know. Thank you!!

  • Delay's Blog

    Nearly breaking news ["Atlas" Control Toolkit updated again!]


    My team just [okay, *almost* just :) ] published the 60914 release of the "Atlas" Control Toolkit. Here are the highlights from the release notes:

    • 4 new controls
      • Animation: Adds powerful, easy to use animations to any element or control
      • NoBot: Applies simple rules to prevent automated bots or scripts from posting to a page
      • Slider: Adds an elegant scrollbar-like user interface for setting numeric values
      • UpdatePanelAnimation: Animates page elements corresponding to hidden postback activity
    • Made Microsoft.AtlasControlExtender.dll functionality public and integrated it into AtlasControlToolkit.dll
    • Added animation framework that makes creating and running complex animations easy
    • Added Atlas profile service support to the extender base class to make persisting values easier
    • Added DynamicPopulate*Base classes to make it easy to add DynamicPopulate functionality to any extender
    • Added PageRequestManagerID property to BehaviorBase to allow behaviors to easily hook up to partial update begin/end events

    Of particular note are the integration of Microsoft.AtlasControlExtender.dll and the new animation framework:

    • Microsoft.AtlasControlExtender.dll contains the extender framework itself and was formerly available only in binary form. By making that code public under the same permissive license that the rest of the Toolkit has, customers are now able to change anything they want about how the Toolkit works. The ability to debug into the extender framework makes finding problems with extenders even easier - and is a great opportunity to understand how things work behind the scenes!
    • The new animation framework makes extremely powerful and flexible animation capabilities very easy to add to new code or integrate with existing code. In addition to supporting a simple XML-like declarative language for specifying arbitrary animation behaviors (including support for sequential, parallel, and conditional animations), it's possible to invoke simple animations with just one "goof-proof" line of code!

    The release notes outline a bunch of other improvements we've made. Please take a moment to read about the new stuff. While you're at it, sample any of the controls right now (no install required). Then browse the project web site and download the latest Toolkit so you can start creating your own controls and/or contributing to the project!

    As always, if you have any feedback, please share it with us on the support forum (or email me)!!

  • Delay's Blog

    An example of watermark-friendly popping [How to: Integrate the PopupControl and TextBoxWatermark]

    One of the questions that comes up every now and then on the "Atlas" Control Toolkit support forums is how to point both the PopupControl and the TextBoxWatermark at the same TextBox. The straightforward implementation doesn't work quite right because both controls assume they have complete control over the TextBox. What happens is that the PopupControl's result gets written directly into the TextBox where it partially overwrites the watermark that's already there. But the TextBoxWatermark doesn't realize anything has happened and assumes the TextBox is still empty. Nuts...

    The solution to this problem is not immediately obvious, so I thought I'd post a simple example to help show how it's done using the 60731 release of the Toolkit.

    First, here's what the sample code below looks like when it's running:

    Animated demonstration

    The complete code for the sample follows - most of what's there is just to get the necessary elements on the page hooked up properly. There are a few things worth noting, though:

    • The unique "ID" attributes on the PopupControlProperties and TextBoxWatermarkProperties elements prevent the automatically assigned IDs (which are based only on the TargetControlID (that's common to both elements)) from clashing.
    • The CommitProperty on the PopupControlProperties defines a custom expando property of the TargetControlID (TextBox1) into which the result of the popup will be placed. This keeps the PopupControl from blindly stomping on the text/watermark in the TextBox.
    • The CommitScript on the PopupControlProperties points to a script that gets run when the popup returns (after the CommitProperty has been populated). In this case, the script simply gets the popup result from the CommitProperty and uses the TextBoxWatermark behavior's set_Text method to safely set the text into the TextBox without breaking the watermark behavior.

    That's all there is to it!

    Just save the following code to an .ASPX file in the SampleWebSite directory of a Toolkit installation if you want to try it out for yourself:

    <%@ Page Language="C#" %>
    @ Register Assembly="AtlasControlToolkit" Namespace="AtlasControlToolkit" TagPrefix="atlasToolkit" %>

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "">

    script runat="server">
        protected void RadioButtonList1_SelectedIndexChanged(object sender, EventArgs e)

    html xmlns="">
    head runat="server">
        <style type="text/css">
            .watermark { background-color:#bbbbff; font-style:italic; }
    .panel { background-color:#bbffbb; visibility:hidden; }
        <form id="form1" runat="server" style="background-color: #dddddd; width: 350px; height: 250px;
            border-style: dashed; border-width: 1px; padding: 5px;">

            <atlas:ScriptManager ID="ScriptManager1" runat="server" EnablePartialRendering="true" />

            <asp:TextBox ID="TextBox1" runat="server" Width="150"></asp:TextBox>
            <asp:Panel ID="Panel1" runat="server" Width="125px" CssClass="panel">
                <atlas:UpdatePanel ID="UpdatePanel1" runat="server">
                        <asp:RadioButtonList ID="RadioButtonList1" runat="server"
                            OnSelectedIndexChanged="RadioButtonList1_SelectedIndexChanged" AutoPostBack="true">
                            <asp:ListItem Text="Red" />
                            <asp:ListItem Text="Green" />
                            <asp:ListItem Text="Blue" />
                            <asp:ListItem Text="[Clear]" />

            <atlasToolkit:TextBoxWatermarkExtender ID="TextBoxWatermarkExtender1" runat="server">
                <atlasToolkit:TextBoxWatermarkProperties TargetControlID="TextBox1" WatermarkCssClass="watermark"
                    WatermarkText="Favorite Color" ID="TextBoxWatermarkBehavior" />
            <atlasToolkit:PopupControlExtender ID="PopupControlExtender1" runat="server">
                <atlasToolkit:PopupControlProperties TargetControlID="TextBox1" PopupControlID="Panel1"
                    Position="Bottom" ID="PopupControlBehavior" CommitProperty="favoriteColor"
                    CommitScript="commitScript()" />

            <script type="text/javascript">
            // Called when PopupControl has been dismissed (registerd via CommitScript property on
            // PopupControlProperties)
            function commitScript() {
    // Get the comitted property from the specified expando property on the TargetControlID
                // (CommitProperty above)
                var favoriteColor = $("TextBox1").favoriteColor;
    // If it's the magic value "[Clear]", then set empty text into the textbox (which
                // restores the watermark)
                if("[Clear]" == favoriteColor) {
                    favoriteColor =
    // Call into the TextBoxWatermark behavior to set the desired text


    If you found this simple "How to" helpful or if you have any suggestions for ways in which future "How to"s could be improved, please let me know. Thank you!!

  • Delay's Blog

    A late announcement and an even later announcement ["Atlas" Control Toolkit updated (twice)!]

    I'm happy to announce the 60731 release of the "Atlas" Control Toolkit (which came out two weeks ago)! (I'm also happy to announce the 60626 release of the "Atlas" Control Toolkit which came out about a month and a half ago - but that's old news by now and is only included here for completeness.)

    Why the delays?

    Well, there was a good reason for keeping the 60626 release a little quiet. The "Atlas" team released an updated version of their binaries just a few days after our 60626 release came out - so the bits it included were suddenly out of date. We expected to integrate the new "Atlas" bits and put out an updated release of the Toolkit a day or two later, but various issues came up and we weren't able to do so. By the time we'd resolved all of the issues, it was just about time for the 60731 release!

    So that's why there was no announcement for 60626. But why the delay for the 60731 release?

    No good reason, really, other than that I've been busy with other stuff and haven't posted to my blog in a while... :|


    Without further ado (or excuses), here are the highlights of the new releases:

    • 8 new controls
      • Accordion: Displays one pane at a time from a set of multiple panes
      • DynamicPopulate: (Re-)populates any element with HTML content downloaded from the server
      • FilteredTextBox: Prevents unwanted characters from being typed into a text box
      • NumericUpDown: Lets you attach flexible up/down "spinners" to any TextBox
      • PagingBulletedList: Adds flexible paging and sorting to any bulleted list
      • PasswordStrength: Provides interactive feedback about the strength of a password being created
      • Rating: Displays a "4 out of 5 stars" interface for ranking
      • ResizableControl: Makes any control resizable
    • A complete automated testing framework along with tests for all 21 controls in the Toolkit
    • Data binding support for extender properties declarations
    • Support for the July CTP of "Atlas"
    • An established process that allows anyone to contribute to the project (5 of the controls above were by people who aren't on the Toolkit team!)

    The release notes outline a bunch of other improvements we've made. Please take a moment to read about the new stuff. While you're at it, sample any of the controls right now (no install required). Then browse the project web site and download the latest Toolkit so you can start creating your own controls and/or contributing to the project!

    As always, if you have any feedback, please share it with us on the support forum (or email me)!!

  • Delay's Blog

    A brief bit 'bout backups [My current backup strategy]


    I've seen a few references to backup strategies on blogs and discussion lists lately and thought I'd write a bit about the strategy I recently decided on and implemented. Of course, everyone has their own approach to file management, their own comfort level for security, and their own ideas about what's "best". That's life and I'm not going to try to persuade anyone that my way is better than their way - but I will outline my way in case it's useful for others, too. :)

    The setup: My machine is running Windows 2003 Server and I try to keep as much unnecessary stuff off it as possible (no games, no P2P programs, no weird drivers, etc.). Along the same lines, all user accounts on the server are members of the restricted access Users group, not the Administrators group. The machine has one hard drive for storing the operating system and all programs (60 GB) and another hard drive for storing all data (320 GB). The data drive has a Mirror directory under which all data to be backed up is stored. The Mirror directory is ACLed to allow the Users group read/write access. Non-private subdirectories of it are shared out for read-only access by Users. I have an external USB 2.0 drive enclosure for backing up to (200 GB) that is normally powered off and that I mirror the Mirror directory to every couple of days or so. The external drive is ACLed to allow only members of the Backup Operators group to make changes. My data consists of the usual personal stuff (email, source code, etc.), all digital photos I've ever taken, all digital video I've ever taken, sentimental stuff (like wedding videos, baby's ultrasound video, etc.), and some of my music collection in WMA Lossless format. Very little data changes day-to-day, so a simple tool like RoboCopy (free with the Windows 2003 Resource Kit) is more than enough to keep the backup directory in sync (use RoboCopy's /MIR switch to make this easy). Along with the rest of the data is a file that records the MD5 hash of every file in the backup. As my data storage needs increase (which they do each time I take a picture or shoot a video!), I'll eventually buy a new large hard drive and swap it for the smallest of the two data drives currently in use. As long as my storage needs don't grow too rapidly, I'm figuring the cost of upgrading to be about $100 each year (that's the cost of a mid-sized drive like the 320 GB I purchased a few months ago). I'm counting on storage capacity to continue increasing like it has so that I'll always be able to buy $100 drives when I need to increase the storage space.

    Benefits provided by this approach:

    • All the data I care about is stored in two independent locations, so there's no single point of failure. (Duh, that's why it's a backup.)
    • Hard drive media doesn't suffer from the same "bit rot" problems that can render writable CDs/DVDs unreadable after just a couple of years.
    • The backup drive is completely separate from the primary drive, so if I ever make a mistake and delete something important, I can easily recover it from the backup. (Some RAID-based solutions immediately mirror all changes and therefore don't have this benefit.) Similarly, a destructive virus on my main machine can't immediately destroy all copies of any data.
    • I look over the list of changes whenever I perform the mirroring to the external drive, so I have an additional opportunity to catch accidental deletions, mysterious changes, etc..
    • I have immediate access to all of my data from any machine in my home. If I decide to look at old photos, I can access them just as easily as the photos I took yesterday.
    • All family members store their data under the Mirror directory (via appropriately ACLed shares), so everybody's data is automatically backed up.
    • In the event of a slow-moving catastrophe (ex: a flood) I can easily grab the external backup drive and take it with me wherever I go. All data will be accessible from any other Windows computer in the world.
    • The overall cost was minimal to set up (~$100) and should be minimal to maintain (~$100/year).
    • Data is separate from applications, so I can reinstall or upgrade the operating system whenever I want without worrying about the data itself.
    • User accounts have limited privileges and are therefore less likely to accidentally compromise the machine when reading email or surfing the web.
    • The MD5 hashes mean that it's easy to verify the contents of my backup drive and that I'll be able to detect data corruption problems if they ever happen.
    • The backup drive is ACLed so that I can't accidentally delete data on it.

    Problems this approach does not solve:

    • Both drives are at the same physical location, so all data can be lost in the event of a sudden catastrophe (ex: fire, earthquake). Possible mitigation: Set up a third external drive (after the first upgrade) and keep that drive somewhere far away. It may not be big enough to hold everything, but I'm happy to exclude music from the off site backup. Drawback: Inconvenience of updating the off site drive.
    • "Old data" is lost quickly. For example: if I accidentally delete an important file, I need to detect that mistake at the time of the next mirroring or else that file is gone for good. Possible mitigation: Multiple backup drives at staged intervals (ex: 1 week, 1 month, 3 months). Drawback: Cost.
    • A thief who steals the computer or external drive might have access to personal data. Possible mitigation: Encryption. Drawback: Inconvenience of decrypting files to use them and/or backing up EFS keys.
    • This solution may not scale well if my data storage needs increase faster than storage technology does. Possible mitigation: Move to a different backup strategy. Drawback: That strategy will have its own problems.

    I think this overview touches on pretty much all of the key points of this strategy. It's obviously not a perfect solution, but it meets most of my requirements and I'm pretty happy with how it's been working out so far. However, I'm always open to improvements - if you have any suggestions, I'd love to hear them!

  • Delay's Blog

    Three weeks since we shipped? Must be time to ship again! ["Atlas" Control Toolkit updated!]


    As you may already know, we released the "Atlas" Control Toolkit a few weeks ago to almost universally positive feedback.

    But it's hard to please everyone, and we got some negative feedback on our relative lack of support for Apple's Safari web browser. (Opera was mentioned, too, but it's another story that I may blog about some other day.) Contrary to the article's suggestion, we actively developed and tested our code on both IE 6 and Firefox 1.5; all nine controls worked in both browsers with two very minor exceptions due to specific limitations. However, we didn't have the time or resources to test with Safari, so our results for that browser were not very good. Sorry about that!

    This time around, Safari support was a BIG priority. In fact, we probably spent more time with Safari than with IE or Firefox! Safari brings with it a number of peculiarities and unfortunately has not yet been a specific focus of the Atlas team (like us, they hadn't gotten around to implementing complete Safari support). So we started out at somewhat of a disadvantage. But a whole bunch of dedicated effort - and a variety of elegant (and some less-than-ideally-elegant) workarounds - have gotten us to the point where all but two of our controls work great on Safari! That's a pretty significant improvement for only three week's time during which we also fixed bugs, added new features, helped users on the "Atlas" Control Toolkit Forums, incorporated a bunch of their feedback, and added new documentation.

    Oh, yeah, we also added *four* new controls to the Toolkit!! (Which all work flawlessly under Safari, by the way.) I'm happy to introduce the...

    • AlwaysVisibleControl: Docks any panel to the browser edge so it remains visible all the time!
    • DropShadow: Adds attractive drop shadows to any control on the page!
    • ModalPopup: Shows styled modal UI without using HTML dialogs!
    • RoundedCorners: Rounds the corners of any control for a clean, professional look!

    The release notes for the latest version outline a bunch of other improvements we made in the past three weeks. Please take a minute or two to read about all the new stuff. And while you're at it, sample the new (and existing) controls on the web right now (no install required). Then go ahead and download the new Toolkit so you can start creating your own controls!

    As always, if you have any feedback, please share it with us on the forum (or email me)!!

    Next up: Enabling community submissions to the Toolkit... (Yum, it's going to be good!)

  • Delay's Blog

    Good news is good news! [Coverage of the "Atlas" Control Toolkit release is favorable!]


    I've been watching the web for coverage of the Agility Team's recent "Atlas" Control Toolkit release. Here are some of the links I've found so far:

    I know I'm biased [ :) ], but the majority of the coverage so far seems to be positive! That's fantastic, but we know there are some rough edges, too. Fortunately, our friends on the "Atlas" Control Toolkit Forums are helping us identify and remedy any problems they find. If you tried the Toolkit out and had *any* difficulties, we'd love to hear about them on the Forum! (After all, we can't fix what we don't know about.)

    Meanwhile, if you know of other links to coverage of the "Atlas" Control Toolkit, please share them with me!

    Update: Added AJAX impact link passed on to me by reader Blake Handler.

    Update: Added CRN and Register links.

  • Delay's Blog

    ASP.NET and "Atlas" make AJAX easy [The Agility Team's "Atlas" Control Toolkit is available for download!]


    The Agility Team is proud to announce the release of the "Atlas" Control Toolkit! Check out the "Atlas" Control Toolkit page for an overview of the project, a link to the demo web site where you can try out the samples, and a download so you can play around with everything yourself!

    Particularly cool stuff that's worth calling out:

    • There are nine different sample controls that you can try right now from the comfort of your own browser!
    • It's really simple to add cool AJAX functionality to existing web sites by adding one of the Toolkit's controls to an existing page and hooking it up to existing page elements! No typing required!!
    • But don't take my word for it - check out the "Using a sample extender" walkthrough to see just how easy it is! (In fact, it's less work to add a control than it is to create the page in the first place!)
    • Creating your own custom controls is also easy, and the included AtlasControlExtender takes care of a bunch of the bookkeeping for you so that you're free to concentrate on the important stuff: adding neat functionality to your site!
    • Again, see how easy it is by reading the "Creating a new extender" walkthrough!
    • The source code to all the controls is part of the download and is being released under the Microsoft Permissive License (Ms-PL) which "... allows you to view, modify, and redistribute the source code for either commercial or non-commercial purposes."! You can do pretty much whatever you want with it!
    • Even better, we'll soon be opening the project up to the community so that *anyone* can add new controls and new features and everyone else can use them to make even better web pages! (More details coming soon...)

    Still have questions? Find a problem? Have a cool suggestion? Great!! Go to the "Atlas" Control Toolkit Forum and let us know! We'll be hanging out there doing our best to answer any questions people have. This is an early preview release, so we expect to get lots of good questions and hear lots of fantastic suggestions. Don't be shy - we're looking forward to hearing from you!

    ASP.NET is powerful. AJAX is hot. Atlas makes it easy. The AtlasControlToolkit makes it fun!!

  • Delay's Blog

    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\     PATH NOT FOUND  Attributes: Erro
    328     6:58:10 PM      GACBlog.exe:212 QUERY INFORMATION       C:\WINDOWS\assem
    bly\GAC_MSIL\vjslib\   PATH NOT FOUND  Attributes: Erro
    329     6:58:10 PM      GACBlog.exe:212 QUERY INFORMATION       C:\WINDOWS\assem
    bly\GAC\vjslib\        PATH NOT FOUND  Attributes: Erro

    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\
    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! :)

Page 27 of 28 (277 items) «2425262728