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.