简体   繁体   中英

MSI Installer cannot find InstallState when using custom action with parameters

First off, yes, I know that the VS Setup Projects are evil. It's what I have to work with. I've also seen several related questions, but they either go unanswered or they don't match my situation close enough for the answer to work (or they harp on about the evils of VS Setup Projects and the marvels of WiX).

I have an install project for my application. It worked just fine to copy files, but I needed to perform two custom actions after copying the files. I created an installer class and set it up as a custom action in the setup project, and the skeleton of it (which did no work, just showed a dialog so I could attach a debugger and look around) worked just fine. Then, I found I needed to pass parameters from the MSI to my custom action so I could access them via the Context property of the installer class.

Here's the current code of the installer class (some names have been changed to protect the innocent). It basically does nothing but show a dialog at the right time (after files are copied but before the installation is committed):

namespace MyApp.Install.CustomSetup
{
    [RunInstaller(true)]
    public partial class MyAppCustomInstallActions : System.Configuration.Install.Installer
    {
        public MyAppCustomInstallActions()
        {
            InitializeComponent();
        }

        protected override void OnAfterInstall(IDictionary savedState)
        {
            try
            {
                base.OnAfterInstall(savedState);
                if (MessageBox.Show(
                    "Custom Action OnAfterInstall successfully integrated. You can attach a debugger if desired. Do you wish to perform the custom actions?",
                    "DEBUG", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No) return;

                SetEditablePermissionOnFolder(savedState);
                SetApplicationSettingsFromWizard(savedState);
            }
            catch (Exception ex)
            {
                Context.LogMessage(ex.ToString());
                throw;
            }
        }

        private void SetApplicationSettingsFromWizard(IDictionary savedState)
        { 
            //TODO: Implement
        }

        private void SetEditablePermissionOnViewerFolder(IDictionary savedState)
        {
            //TODO: Implement
        }
    }
}

The plan is to get the custom actions working, then take out the dialog and just do it.

Here is the string for CustomActionData for the Install action of the setup project's custom actions:

/phonenumber=[phonenumber] /thirdpartyinstallpath1="[thirdpartyinstallpath1]\" /thirdpartyinstallpath2="[thirdpartyinstallpath2]\" /thirdpartyinstallpath3="[thirdpartyinstallpath3]\"

If I do not use this parameter string, it's fine but I have no parameters. If I do specify this string, the installer fails before my own dialog box shows up, with two errors: "Exception occurred while initializing the installation: Could not load file or assembly 'file:///C:\\Windows\\SysWOW64\\Files' or one of its dependencies. The system cannot find the file specified" , and "Error 1001. Could not find file C:\\Program Files (x86)\\MyCompany\\MyApp\\MyApp.Install.CustomSetup.InstallState" .

What am I doing wrong? Am I doing anything wrong? Is there a solution that doesn't require me to re-create an installer using some different framework?

EDIT: I found that removing everything but the phone number parameter, and putting [PHONENUMBER] in quotes, allows that parameter to be passed. However, I cannot pass any of the directory paths; I tried with [INSTALLDIR] exactly how several blogs and walkthroughs say to do it, no dice.

I had a similar problem and solved it by:

On the properties of your custom action set InstallerClass to false.

I found that the problem was in the format of the parameter string. Because the various parameters, though they were file paths, included the file name instead of ending in a backslash, I didn't need the trailing backslash to end those value strings. Because I did anyway, the ending quotes were treated as part of the string, which made the parser use the next opening quote as the end of the previous value, corrupting the whole parameter string. Because of this, InstallState couldn't be written correctly, and failed when the custom install logic tried to use it.

If anyone gets this error after upgrading from VS2008 to VS2010 then check out this thread: http://social.msdn.microsoft.com/Forums/en-US/winformssetup/thread/829d5c90-9a0d-4258-9d4d-1341cc50f95b/

This solved the issue for me:

Change "BackwardCompatibleIDGeneration" to true on setup project properties.

One thing I would make sure of is that my paths were escaped properly; either do it with

@"My Documents\Blah"

or

"My\ Documents\\Blah"

In my case it was because I had mistakenly added the custom action to the rollback node instead of the install node. Simple mistake.

The problem is one backslash in front of the terminating quote will be interpreted as a quote that belongs to the String and doesn't terminate the string. In the CustomactionActionData string

/thirdpartyinstallpath1="[thirdpartyinstallpath1]\" /thirdpartyinstallpath2="[thirdpartyinstallpath2]\"

the Installer Substituts [thirdpartyinstallpath1] and [thirdpartyinstallpath2] by the user input and then tries to interpret the CustomactionActionData string. If the user input for “thirdpartyinstallpath1” is “C:\\Test\\” the above CustomactionActionData string may be ok but if the user enters “C:\\Test” the Installation fails with the Error

"Exception occurred while initializing the installation: Could not load file or assembly 'file:///C:\\Windows\\SysWOW64\\Files...' or one of its dependencies..."

With a CustomactionActionData string like

/thirdpartyinstallpath1="[thirdpartyinstallpath1]" /thirdpartyinstallpath2="[thirdpartyinstallpath2]"

the Setup will fail if the user input is “C:\\Test\\”. This will be ok if the user input is “C:\\Test”. But you never can know what the user will do.

My workaround is a blank just before the terminating string like this:

/thirdpartyinstallpath1="[thirdpartyinstallpath1] " /thirdpartyinstallpath2="[thirdpartyinstallpath2] "

so there is no change to take away the terminating string by user input. In the Code you can removes all leading and trailing white-space characters from the user input by Trim

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM