上下文
所以这是一个安装旧软件的软件包。当我说老了,想想20岁。这是巨大的,我们依赖它,我们正在编写替代品,但在此之前,我们仍然坚持使用这个旧的应用程序。
问题:
msi将通过SCCM推送,我们的IT部门坚持认为这意味着我们不能在此msi包中包含任何UI元素(例如浏览安装路径)。
该程序必须安装在: volume +“:\”+ companyabbreviation 。 默认路径为[WindowsVolume] companyabbreviation
我们还必须为程序生成一些空文件夹才能正常运行,例如“ TRANSFER ”
为了达到这个目的,在没有淹没ICE警告的情况下,wix xml看起来像这样:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="VOLUME_WindowsVolume_companyabbreviation" Name="WindowsVolume_companyabbreviation">
<Directory Id="Directory_0_1_0" Name="subfolderA">
<Directory Id="Directory_0_2_1" Name="subsubfolderAA" />
</Directory>
<Directory Id="Directory_0_1_0" Name="subfolderB" />
<!-- and a lot more directories -->
<Directory Id="Directory_0_2_6" Name="TRANSFER" />
</Directory>
</Directory>
<!-- Component groups -->
<ComponentGroup Id="FEATUREID_Directory_0_2_6" Directory="VOLUME_WindowsVolume_companyabbreviation">
<Component Id="INSTALL_Directory_0_2_6" Guid="4a9cd25e-4d66-4398-af52-356a3b48c337">
<CreateFolder Directory="Directory_0_2_6" />
<RemoveFile Id="PurgeCacheFolderDirectory_0_2_6" Name="*.*" On="uninstall" />
<RemoveFolder Id="Directory_0_2_6" On="uninstall" />
</Component>
</ComponentGroup>
<!-- more Component Groups, components, features, etc.. -->
<SetDirectory Id="VOLUME_WindowsVolume_companyabbreviation" Value="[WindowsVolume]companyabbreviation" />
这可以按预期工作。
由于这是一个旧的应用程序(从未打包但通过自制程序安装程序分发),目标计算机通常会在获得msi之前进行某种“安装”。
因此,我从旧的自制安装中创建了一个清理自定义操作。哪个也很好用。我们只是确保它只在一个以前没有人通过msi安装的系统上运行,如果尝试安装的话。
<Binary Id="CustomActionsId" SourceFile="../customActions/CA UPDATE FROM REGISTRY.CA.dll" />
<CustomAction Id="Launch_UPDATE_FROM_REGEDIT" BinaryKey="CustomActionsId" DllEntry="UPDATE_FROM_REGISTRY" Execute="immediate" Return="check" />
<InstallExecuteSequence>
<Custom Action="Launch_UPDATE_FROM_REGEDIT" Before="CostFinalize">NOT Installed</Custom>
</InstallExecuteSequence>
现在我们应该准备好发布了:)
除此之外,我们刚刚发现我的前任?很久以前决定,他们会告诉客户如何从默认位置移动程序......
请参阅,开发人员可以使用多个安装,只需通过修改一组注册表键来选择要运行的安装。
基本上,开发人员确保可以将应用程序移动到另一个驱动器,例如: D:\ companyabbreviation ,并通过注册表编辑要启动的版本。要使用哪个 TRANSFER 文件夹,等等......
嗯,你可能会争辩说,这需要很多分区,但是在公司知道CVS,SVN,GIT等之前的时间......好吧我觉得这很有意义。
后来另一位开发人员看到了这个功能,作为一种方法来解决一些客户缺乏管理权限(因此无法在WindowsVolume Root上安装)并确定旧的安装程序在出现时会尊重注册表项。 如果密钥不存在,他会让旧安装程序创建它,并将值设置为默认路径。
因此,多年以后,现在我们的MSI,也需要尊重这一点,如果我们的任何用户移动了应用程序......(我们已经检查过,有些人会这样做......)
我们的想法是使用自定义操作来更新路径:
我们做了一个帮手功能:
public static ActionResult getCustomActionInfo(Session session, string WhereSourceStringContains, ref List<string> data)
{
var CustomActionsActions = session.Database.ExecuteQuery("SELECT Action from CustomAction");
var CustomActionsTypes = session.Database.ExecuteQuery("SELECT Type from CustomAction");
var CustomActionsSources = session.Database.ExecuteQuery("SELECT Source from CustomAction");
var CustomActionsTargets = session.Database.ExecuteQuery("SELECT Target from CustomAction");
session.Log("Retrieved " + CustomActionsTargets.Count.ToString() + " custom actions");
int index = -1;
for (int i = 0; i < CustomActionsTargets.Count; i++)
{
if (CustomActionsTypes[i].ToString().Trim() == "51" && CustomActionsSources[i].ToString().Contains(WhereSourceStringContains))
{
index = i;
break;
}
}
if (index == -1)
{
session.Log("Error could not locate the " + WhereSourceStringContains + " setDirectory customAction, cannot set a different installation target..");
return ActionResult.SkipRemainingActions;
}
else
{
session.Log("row found with index: " + index.ToString() + "\r\n\t [action] => " + CustomActionsActions[index].ToString() + "\r\n\t [type] => " + CustomActionsTypes[index].ToString() + "\r\n\t [source] => " + CustomActionsSources[index].ToString() + "\r\n\t [target] => " + CustomActionsTargets[index].ToString());
data.Add(index.ToString());
data.Add(CustomActionsActions[index].ToString());
data.Add(CustomActionsTypes[index].ToString());
data.Add(CustomActionsSources[index].ToString());
data.Add(CustomActionsTargets[index].ToString());
}
return ActionResult.Success;
}
和
public static void setCustomActionTarget(Session session, string ActionData, string TargetData)
{
session.Database.Execute("UPDATE CustomAction SET Target='" + TargetData + "' WHERE Action='" + ActionData + "'");
}
然后这段代码会让事情发生:
[CustomAction]
public static ActionResult UPDATE_FROM_REGISTRY(Session session)
{
var view32 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32);
RegistryKey ProductKey = view32.OpenSubKey(@"secretPath\To\Applications\Key");
/* instDir is the previous location of the folder */
string instDir = ProductKey.GetValue("instDir ").ToString().Trim();
session.Log("discovered a instDir key: " + instDir );
string BaseDir = instDir .Substring(0, DataDir.ToUpper().LastIndexOf("\\")).ToUpper();
List<string> PRODUCT = new List<string>();
ActionResult test = getCustomActionInfo(session, "companyabbreviation", ref PRODUCT );
if (test != ActionResult.Success) return test;
string BaseTarget = SABITC[4];
session.Log("BaseTarget: " + BaseTarget + " == BaseDir: " + BaseDir.Replace(@"C:\", "[WindowsVolume]") + " ?? ");
if (BaseTarget.ToUpper() == BaseDir.Replace(@"C:\", "[WindowsVolume]").ToUpper())
{
session.Log("\tdefault directory was used for SABITC, do nothing to change that :D ");
}
else
{
session.Log("\tinstall at old location: " + BaseDir);
setCustomActionTarget(session, SABITC[1], BaseDir); //here throws exception
//TODO: update "target" and instdir in msi registry entries, to ensure information is not overwritten by defaults..
}
}
很明显你不允许修改会话数据库,但是我们怎么能实现这个呢?
我对在wix xml中创建属性不感兴趣,如果可以避免的话。 - 原因是目前xml是自动生成的,因为我们的开发人员(主要是工程师)不应该必须学习wix,才能维护数学代码。
如果我们必须使用xml中定义的属性,我们必须以某种方式让自定义操作知道目录节点的ID是什么。
假设客户决定只移动提到的TRANSFER文件夹: 可以这样做:
<!-- information for the custom action -->
<Property Id="TRANSFER_ID" Value="Directory_0_2_6"/>
<!-- values below can be overwritten by the custom action:
but unfortunately also this line also sets default paths,
and in case of errors, it makes the directory tree above unreliable
at least for humans that read it in the future.-->
<Property Id="Directory_0_2_6" Value="C:\companyabbrevation\TRANSFER\" />
为了完成这项工作,我们必须手动修改所有这些自动生成的wix文件,并将“默认”路径值设置为目录树隐式设置的内容。 - 或者创建解析xml的内容,找到正确的目录ID,然后添加属性节点。
也许如果我们可以在安装时动态地向MSI添加属性,我们仍然能够做到这一点吗?
无效解决方案的要求摘要:
* change installation folder using information found in registry
* do not overwrite registry information for specific keys, if they are present.