Monday, March 31, 2008

FileNotFoundException in Visual Studio Setup Project

The Velodoc XP setup project would consistently fail on a specific Windows Server 2003 server of ours but not on other computers of our network. The complete issue is described at http://www.codeplex.com/VelodocXP/WorkItem/View.aspx?WorkItemId=1005. The error message was:

Exception occurred while initializing the installation: System.IO.FileNotFoundException: Could not load file or assembly 'file:///C:\WINDOWS\system32\and' or one of its dependencies. The system cannot find the file specified.

Obviously, there is no such "C:\WINDOWS\system32\and" file in our application or on the system. MSI logs and fusion logs would not give any more information.

We have been puzzled by this issue for quite some time. We have finally removed features from our setup one by one until we have been able to identify that a specific custom action was at the source of the problem.

In the literature and samples that you will find regarding developing Visual Studio setup projects, custom action data is passed in the form /NAME = VALUE which works fine unless value contains a space.

The reference documentation at http://msdn2.microsoft.com/en-us/library/2w2fhwzz.aspx states that in setup custom actions, data should be passed as:

/NAME = VALUE if not a directory and value has no space
/NAME = "VALUE" if spaces are expected in a value which is not a directory
/NAME = "VALUE\" if the expected value is a directory

I wish we had not simply read how-to articles and sample code, but also the reference documentation.

2 comments:

Hugo said...

Good text! It's very clear. But it didn't worked for me :( I have a problem, I had a NullReferenceException and debugging I discovered that Installer.Context is null. Do you have any idea of why this can happen?

vapcguy said...

Actually, the way you avoid this error when you have spaces in the value you are passing through is to use this:

/f1="[EDITA1]"

in the CustomActionData property, with no slash (since you would just have to remove the slash when you retrieve the variable), and then call it like this:

public override void Install(System.Collections.IDictionary state)
{
string ourValue = Context.Parameters["f1"];
base.Install(state);
}

-Tom