使用带有参数的自定义操作时,MSI 安装程序无法找到 InstallState
首先,是的,我知道 VS 安装项目是邪恶的。这就是我必须处理的事情。我也看到了几个相关的问题,但它们要么没有得到解答,要么与我的情况不够接近,无法得到答案(或者它们喋喋不休地谈论 VS 设置项目的邪恶和 WiX 的奇迹)。
我的应用程序有一个安装项目。复制文件效果很好,但复制文件后我需要执行两个自定义操作。我创建了一个安装程序类,并将其设置为安装项目中的自定义操作,并且它的框架(没有任何作用,只是显示了一个对话框,以便我可以附加调试器并环顾四周)工作得很好。然后,我发现我需要将参数从 MSI 传递到我的自定义操作,以便我可以通过安装程序类的 Context 属性访问它们。
这是安装程序类的当前代码(为了保护无辜者已更改一些名称)。它基本上什么也不做,只是在正确的时间显示一个对话框(在复制文件之后但在提交安装之前):
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
}
}
}
计划是让自定义操作正常工作,然后取出对话框并执行它。
以下是安装项目的自定义操作的安装操作的 CustomActionData 字符串:
/phonenumber=[phonenumber] /thirdpartyinstallpath1="[thirdpartyinstallpath1]\" /thirdpartyinstallpath2="[thirdpartyinstallpath2]\" /thirdpartyinstallpath3="[thirdpartyinstallpath3]\"
如果我不使用此参数字符串,也可以,但我没有参数。如果我确实指定了此字符串,则安装程序会在显示我自己的对话框之前失败,并出现两个错误: “初始化安装时发生异常:无法加载文件或程序集 'file:///C:\Windows\ SysWOW64\Files' 或其依赖项之一。系统找不到指定的文件“
,并且”错误 1001。无法找到文件 C:\Program Files (x86)\MyCompany\MyApp\MyApp。安装.CustomSetup.InstallState”
。
我做错了什么?我做错了什么吗?是否有一种解决方案不需要我使用某些不同的框架重新创建安装程序?
编辑:我发现删除除电话号码参数之外的所有内容,并将 [PHONENUMBER] 放在引号中,就可以传递该参数。但是,我无法传递任何目录路径;我尝试了 [INSTALLDIR],正如几个博客和演练所说的那样,没有骰子。
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
我遇到了类似的问题并通过以下方式解决了它:
在自定义操作的属性上将 InstallerClass 设置为 false。
I had a similar problem and solved it by:
On the properties of your custom action set InstallerClass to false.
我发现问题出在参数字符串的格式上。因为各种参数虽然是文件路径,但包含文件名而不是以反斜杠结尾,因此我不需要尾部反斜杠来结束这些值字符串。因为无论如何我都这样做了,所以结尾引号被视为字符串的一部分,这使得解析器使用下一个开头引号作为前一个值的结尾,从而损坏了整个参数字符串。因此,InstallState 无法正确写入,并且当自定义安装逻辑尝试使用它时会失败。
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.
如果有人从 VS2008 升级到 VS2010 后遇到此错误,请查看此线程:
http://social. msdn.microsoft.com/Forums/en-US/winformssetup/thread/829d5c90-9a0d-4258-9d4d-1341cc50f95b/
这为我解决了这个问题:
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:
我要确保的一件事是我的路径已正确逃脱; 来做
要么用or
One thing I would make sure of is that my paths were escaped properly; either do it with
or
就我而言,这是因为我错误地将自定义操作添加到回滚节点而不是安装节点。简单的错误。
In my case it was because I had mistakenly added the custom action to the rollback node instead of the install node. Simple mistake.
问题是终止引号前面的一个反斜杠将被解释为属于字符串的引号并且不会终止字符串。
在 CustomactionActionData 字符串中,
安装程序用用户输入替换
[thirdpartyinstallpath1]
和[thirdpartyinstallpath2]
,然后尝试解释 CustomactionActionData 字符串。如果“thirdpartyinstallpath1”的用户输入是“C:\Test\”,则上述 CustomactionActionData 字符串可能没问题,但如果用户输入“C:\Test”,安装将失败并显示错误
这样的 CustomactionActionData 字符串
使用像
/thirdpartyinstallpath1="[thirdpartyinstallpath1]" /thirdpartyinstallpath2="[thirdpartyinstallpath2]"
,如果用户输入为“C:\Test\如果用户输入是“C:\Test”,那就没问题了,但你永远不知道用户会做什么,
我的解决方法是在终止字符串之前留一个空白,如下所示:
/thirdpartyinstallpath1="[ Thirdpartyinstallpath1] " /thirdpartyinstallpath2="[thirdpartyinstallpath2] "
因此,没有任何更改可以通过用户输入删除终止字符串。
在代码中,您可以通过 Trim 从用户输入中删除所有前导和尾随空白字符
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
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
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