views:

39

answers:

0

Background

I'm troubleshooting an WinForms 2.0 program that's already been burned to CD for distribution to an internet-challenged target audience. Some users are experiencing a fatal error that I can reproduce locally.

Reproducing the Error

I get the fatal error when I log into my Vista box using a standard user that I just created, even if I run the program as administrator. I do not get the fatal error when I log in as local administrator. I'm not sure that being administrator is necessarily the trigger (since runas did not help). I have reproduced this half a dozen times under each account with consistent results.

The faulty code

Base.cs (base class for several user controls, only one of which is shown on first screen)

private void BaseWindow_Load(object sender, EventArgs e)
{
    // This message shown once in both cases
    MessageBox.Show("BaseWindow_Load for " + this.GetType().FullName);

    SkinManager.ApplySkin(this);
}

SkinManager.cs

private static Skin skin = null;
public static void ApplySkin(UserControl applyTo)
{
    if (skin == null)
    {
        skin = new Skin(SkinsDirectory, "Default");
    }
}

Skin.cs

internal Skin(string skinPath, string skinName)
{
    config = SkinConfig.Load(path);
}

SkinConfig.cs

public static SkinConfig Load(string path)
{
    // This message shown only once running as Admin but twice running as standard user
    System.Windows.Forms.MessageBox.Show("@1");
    // !!! LOCK path HERE !!!
}

A user control loads on the first form, which triggers a call to SkinManager.ApplySkin, which checks if skin is null and, if so assigns it (without thread synchronization or recursion protection), which ultimately causes a file to be opened.

When logged in as local admin, that sequence completes just fine.

When logged in as my test standard user, ApplySkin is always called a second time while skin is still null, causing a second attempt to load, causing the file to be locked on the second attempt. The error handling is draconian at this point and the program terminates.

The Question

While this code can be easily fixed, I would like to understand why the error is happening only in some cases.

EDIT

Added stack traces from first and second pass through (with the second one happening before the first one completes)

First Time:

   at System.Environment.GetStackTrace(Exception e, Boolean needFileInfo)
   at System.Environment.get_StackTrace()
   at BizObj.SkinConfig.Load(String path)
   at BizObj.Skin..ctor(String skinPath, String skinName)
   at BizObj.SkinManager.ApplySkin(UserControl applyTo)
   at MyApp.Base.BaseWindow_Load(Object sender, EventArgs e)
   at System.Windows.Forms.UserControl.OnLoad(EventArgs e)
   at System.Windows.Forms.UserControl.OnCreateControl()
   at System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible)
   at System.Windows.Forms.Control.CreateControl()
   at System.Windows.Forms.Control.OnVisibleChanged(EventArgs e)
   at System.Windows.Forms.ScrollableControl.OnVisibleChanged(EventArgs e)
   at System.Windows.Forms.Control.OnParentVisibleChanged(EventArgs e)
   at System.Windows.Forms.Control.OnVisibleChanged(EventArgs e)
   at System.Windows.Forms.ScrollableControl.OnVisibleChanged(EventArgs e)
   at System.Windows.Forms.Form.OnVisibleChanged(EventArgs e)
   at System.Windows.Forms.Control.SetVisibleCore(Boolean value)
   at System.Windows.Forms.Form.SetVisibleCore(Boolean value)
   at System.Windows.Forms.Control.set_Visible(Boolean value)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.Run(Form mainForm)
   at MyApp.Start.Main()

Second Time:

   at System.Environment.GetStackTrace(Exception e, Boolean needFileInfo)
   at System.Environment.get_StackTrace()
   at BizObj.SkinConfig.Load(String path)
   at BizObj.Skin..ctor(String skinPath, String skinName)
   at BizObj.SkinManager.ApplySkin(UserControl applyTo)
   at MyApp.Base.BaseWindow_Load(Object sender, EventArgs e)
   at System.Windows.Forms.UserControl.OnLoad(EventArgs e)
   at System.Windows.Forms.UserControl.OnCreateControl()
   at System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible)
   at System.Windows.Forms.Control.CreateControl()
   at System.Windows.Forms.Control.OnVisibleChanged(EventArgs e)
   at System.Windows.Forms.ScrollableControl.OnVisibleChanged(EventArgs e)
   at System.Windows.Forms.Control.OnParentVisibleChanged(EventArgs e)
   at System.Windows.Forms.Control.OnVisibleChanged(EventArgs e)
   at System.Windows.Forms.ScrollableControl.OnVisibleChanged(EventArgs e)
   at System.Windows.Forms.Form.OnVisibleChanged(EventArgs e)
   at System.Windows.Forms.Control.SetVisibleCore(Boolean value)
   at System.Windows.Forms.Form.SetVisibleCore(Boolean value)
   at System.Windows.Forms.Control.set_Visible(Boolean value)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.Run(Form mainForm)
   at MyApp.Start.Main()