CustomActionData and User Defined Path
When designing a setup project, you can define text boxes dialog to input a file system path. To process the input that the user has entered, usually a custom action is created to handle the user input, and the user input is passed through CustomActionData property. Unfortunately, there are several problems when dealing with path.
Spaces in the path
A space is a valid character for a path. If the user passes a path with a space in it, you should enclose the input with double-quotes, for example, this is a CustomActionData property value: /USERDEFINEDDATA="[USERPATH]".
This leads to a different problem below.Backslashes trimmed.
When the user enters a UNC path starting with "\\", if the value property is enclosed with double-quotes, the string that is passed to the custom action contains only one '\'. Not really a problem, you have to check if the path is a UNC path and make sure there are two '\'.Trailing backslash caused an exception.
This is an interesting problem. As soon as the user enters a path, either absolute path or a UNC path and ended the path with a backslash, the user will get this error when running the setup.
Error 1001: Exception occurred while initializing the installation:
System.IO.FileNotFoundException. Could not load file or assembly:
'file:///C:\WINNT\[Your assembly name here]' or one of its dependencies.
The system could not find the file specified.This error happens only when the CustomActionData inside double-quotes.
If you check my previous post about passing [TARGETDIR] to custom action, you notice that you have to pass a backslash at the end. You can do the same with a user defined path, something like this /USERDEFINEDDATA="[USERPATH]\". This code works great if the user enters a path with a trailing backslash, and there will be only ONE trailing backslash. The problem is if the user did not supply the trailing backslash, the user will get the same 1001 error again.
My solution is this, set CustomActionData with a character that you know is not a valid path character, for example a Pipe character ('|'). Assign your CustomActionData like this /USERDEFINEDDATA="[USERPATH] | ". With this, a user defined path with trailing backslash will come to the custom action as "C:\some Path\some path\|", and user defined path without a trailing backslash will come to the custom action as "C:\Some Path\Some Path|". What you have to do now is to trim the '|' character, and you are good. Now you have a code that can handle user input with or without trailing backslash.
Comments
Anonymous
October 29, 2008
Couldn't you do something like /USERDEFINEDDATA=@"[USERPATH]"?Anonymous
October 30, 2008
Andrew, Unfortunately, that won't work. @ works with C#, but not with MSI. MSI does not escape the string if you use @. If you inspect the MSI using Orca, you will see that the @ sign will be there, just like you wrote it. When the value is passed to your code, it will include the @ sign. Let says you passed c:Windows, your custom action will see "@c:Windows", and trailing backslash will still cause a problem.Anonymous
December 15, 2009
Thanks! You have seriously saved my day with this tiny (but very important!) information. I can't count the number of sites that I have visited that never mentioned the problem with the tailing backslash combined with the quotes.Anonymous
July 20, 2010
can we give conditional value e.g. /USERDEFINEDDATA="[USERPATH]" OR "[TARGETPATH]" WHICHEVER BETWEEN THE TWO IS NOT BLANK OR NULLAnonymous
November 09, 2010
Thanks! man you have solved my hardest problem. GREAT!Anonymous
April 30, 2012
When a single double quotation (“) is passed as an argument to a custom action, the installer will fail with the same error message. Is there any workaround available for it?Anonymous
June 19, 2012
thanks a lot ............really good. This worked /targetvdir="[TARGETVDIR]" /targetdir="[TARGETDIR]"