Tom Goff's .Net Musings

Tidbits of information regarding .Net, C#, and SQL Server.

Archive for May 2007

Custom Setup Action Woes

with 3 comments

We use custom setup actions in our Visual Studio Setup project in order to create shortcuts to our application on the Quick Launch toolbar and the Desktop, if the user so chooses. The managed custom action is easy to get setup and running, but troubleshooting issues can be a real pain.

NOTE: If you don’t know what a custom action is then check out this link[^]

The main source of pain is the fact that the errors only occur at the very end of the installation of the application. This means that I have to build an installer every time I want to try to test a “fix”. When diagnosing the issue, there are a few areas to check for information on the problem.

Generally, the first thing to do is enable logging for the MSI. If you know that it’s a problem with your custom action, then this probably won’t help. Next, it’s best to verify that the assembly holding your custom action does not have any binding issues. To determine this you need to use fuslogvw[^]. If your assembly cannot load because of a missing reference, then this will point out the problem. The latest technique in my arsenal is to use installutil[^]. Let me explain how this helps.

The message box below is one error I was receiving. Again, this error occurred during installation and would force a rollback of the installation. So, once I clicked OK then the installed files would be removed. There is generally a second dialog after this with the same information because it is trying to perform the rollback of the custom action. In order to use installutil, I would leave the dialog open so the offending files would be (temporarily) left on my system.

I’m sure we have all seen this error in the Visual Studio designer. In fact, when searching for a solution to this issue, all of the sites I found dealt with the designer. Anyway, I used installutil to “re-run” my custom install. Since the files were still on my system, I could just open command-prompt  (with the VS directories in the PATH) to my application’s folder and type the following:

C:...>installutil /logtoconsole=true /showcallstack CustomActionTest.exe

 This allowed me to see the callstack of the exception that was being thrown:

System.Reflection.ReflectionTypeLoadException: Unable to load one or more 
of the requested types. Retrieve the LoaderExceptions property for 
more information. 
at System.Reflection.Module.GetTypesInternal(StackCrawlMark& stackMark) 
at System.Reflection.Module.GetTypes() 
at System.Configuration.Install.AssemblyInstaller.GetInstallerTypes(Assembly assem) 
at System.Configuration.Install.AssemblyInstaller.InitializeFromAssembly()

Now we know the type of exception that is being thrown and where it’s being thrown from. The first thing to note here is that the ReflectionTypeLoadException[^] class has a LoaderExceptions property. This property returns an  “array of exceptions thrown by the class loader.” What I really wanted was the information in the LoaderExceptions property. Unfortunately, this information is not logged or reported anywhere. So my only option was to build my own application that could reproduce the exception.

Luckily, the code that threw the exception was simply opening the assembly, iterating over it’s modules, then iterating over the types in each module. The basic code is shown here:

    Module[] modules = assembly.GetModules(); 
    foreach (Module module in modules) { 
        Type[] types = module.GetTypes(); 
        // ... 
    }

After building an application that loaded my assembly and performed the code above, I was able to view the contents of the LoaderExceptions property. It turns out that some old, unfinished, and unused code was causing the problem. Specifically, I had been building P/Invoke calls to the Windows shell interface IShellFolder[^]. This interface uses a structure with a union called STRRET[^].

The quick conversion of STRET to C# equates to:

    [StructLayout(LayoutKind.Explicit)] 
    public struct STRRET { 
        [FieldOffset(0)] 
        public Int32 uType;  

        [FieldOffset(4)] 
        public IntPtr pOleStr;  

        [FieldOffset(4)] 
        public Int32 uOffset;  

        [FieldOffset(4)] 
        public IntPtr cStr; 
    }

At the time, I was trying to tweak the signature to use a .Net char array, like so:

    [StructLayout(LayoutKind.Explicit)] 
    public struct STRRET { 
        [FieldOffset(0)] 
        public Int32 uType;  

        [FieldOffset(4)] 
        public IntPtr pOleStr;  

        [FieldOffset(4)] 
        public Int32 uOffset;  

        [FieldOffset(4), MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] 
        public Char[] cStr; 
    }

Now as I said the code was unfinished and was not used anywhere in our application. In addition, the code compiles without any warnings or errors. Yet, this code completely disables the ability for my assembly to have it’s types reflected. I’m guessing this is an issue with the C# compiler, since it does not report this as invalid.

Anyway, I’ve put together a sample project[^] that illustrates all the points talked about above.

Advertisements

Written by Tom

May 24, 2007 at 9:18 am

Posted in .Net, C#, Gotcha

Double Initialization

leave a comment »

I was playing around with FXCop and ran into an interesting rule it was reporting on my code. The rule is called DoNotInitializeUnnecessarily, and reports a warning when you initialize a field member to it’s “default value”. The default value depends on the data type: zero (0) for integers, false for Booleans, null for reference types, etc. For example, the default value for the String field below is null, so there is no reason to explicitly set it to null:

    public class Class1 { 
        /// <summary> 
        /// Holds my string. 
        /// </summary> 
        private String myString = null; 

        /// <summary> 
        /// Gets my string. 
        /// </summary> 
        /// <value>My string.</value> 
        public String MyString { 
            get { 
                return this.myString; 
            } 
        } 
    }

Now, this isn’t much of a problem because this will get optimized out of release builds. Unfortunately, I almost always initialize Strings to String.Empty. So if I write:

    public class Class1 { 
        /// <summary> 
        /// Holds my string. 
        /// </summary> 
        private String myString = String.Empty; 

        /// <summary> 
        /// Gets my string. 
        /// </summary> 
        /// <value>My string.</value> 
        public String MyString { 
            get { 
                return this.myString; 
            } 
        } 
    }

Then the initialization will occur, regardless of whether it’s a release build. Obviously in this example, it’s not a problem because we want the string to be non-null. But, if we were to write:

    public class Class1 { 
        /// <summary> 
        /// Initializes a new instance of the <see cref="Class1"/> class. 
        /// </summary> 
        /// <param name="myString">My string.</param> 
        public Class1(String myString) { 
            this.myString = myString ?? String.Empty; 
        } 

        /// <summary> 
        /// Holds my string. 
        /// </summary> 
        private String myString = String.Empty; 

        /// <summary> 
        /// Gets my string. 
        /// </summary> 
        /// <value>My string.</value> 
        public String MyString { 
            get { 
                return this.myString; 
            } 
        } 
    }

Then the myString field will be initialized twice. First time, the field initializer sets it to String.Empty. Then in the constructor it’s initialized to the given parameter if it’s non-null, otherwise it’s set to String.Empty again.

To remove the double initialization, we need to remove the field initializer. I doubt that there are many cases were this would result in a noticeable speed improvement. Although, when things are running in long loops every little bit helps.

Things like this generally dictate how I will write code. I will probably avoid field initializers now, just so I don’t have to worry about double, or potentially triple, initialization. Field initializers were just a convenient way to set fields, but I didn’t realize there was a potential (albeit small) problem.

Written by Tom

May 11, 2007 at 12:54 pm

Posted in C#, Gotcha