MSI存储未来卸载任务的安装目录。如何获取安装目录?
使用INSTALLPROPERTY_INSTALLLOCATION
属性(即"InstallLocation"
)只能在安装期间安装程序已设置ARPINSTALLLOCATION
属性。但是这个属性是可选的,几乎没有人使用它。
我该如何检索安装目录?
MSI存储未来卸载任务的安装目录。如何获取安装目录?
使用INSTALLPROPERTY_INSTALLLOCATION
属性(即"InstallLocation"
)只能在安装期间安装程序已设置ARPINSTALLLOCATION
属性。但是这个属性是可选的,几乎没有人使用它。
我该如何检索安装目录?
使用注册表键跟踪您的安装目录,这样您可以在升级和删除产品时参考它。
使用维克斯我会创建一个安装目录的Directy标签后立即创建密钥,一个组件,申报
我会尝试使用Installer.OpenProduct(产品代码)。这会打开一个会话,然后您可以要求输入Property(“TARGETDIR”)。
试试这个: var sPath = this.Context.Parameters [“assemblypath”]。ToString();
我会使用MsiGetComponentPath() - 你需要ProductId和ComponentId,但是你得到了安装文件的完整路径 - 只需选择一个到你的安装目录的位置。如果你想获得任意MSI目录的价值,我不相信有一个API可以让你做到这一点。
正如在线程中的其他地方所述,我通常在HKLM中编写一个注册表项,以便能够轻松地检索安装目录以进行后续安装。
在我处理尚未完成此操作的设置时,我使用内置的Windows Installer功能AppSearch:http://msdn.microsoft.com/en-us/library/aa367578(v=vs.85).aspx通过指定要查找的文件签名来查找以前安装的目录。
文件签名可以由文件名,文件大小和文件版本以及其他文件属性组成。每个签名都可以指定一定的灵活性,因此您可以通过指定要查找的版本范围来找到同一文件的不同版本。请检查SDK文档:http://msdn.microsoft.com/en-us/library/aa371853(v=vs.85).aspx
在大多数情况下,我使用主应用程序EXE并通过查找具有正确版本和日期的文件的窄版本范围来设置严格签名。
最近我需要通过Ketarin自动安装Natural Docs安装。我可以假设它已安装到默认路径(%ProgramFiles(x86)%\Natural Docs
),但我决定采取一种安全的方法。可悲的是,即使安装程序在HKLM\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall
上创建了密钥,它的价值也没有让我找到安装目录。
Stein答案建议AppSearch MSI功能,它看起来很有趣,但令人遗憾的是自然文档MSI安装程序不提供签名表到他的方法作品。
所以我决定通过注册表进行搜索,找到自然文档安装目录的任何参考,我找到一个到HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components
密钥。
我在C#中Ketarin允许递归开发的注册类。因此我通过HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components
查看所有值,并且如果主应用程序可执行文件(NaturalDocs.exe)被发现为其中一个子键值,则将其提取出来(C:\Program Files (x86)\Natural Docs\NaturalDocs.exe
变为C:\Program Files (x86)\Natural Docs
),并将其添加到系统环境变量%PATH%(因此,我可以调用“ NaturalDocs.exe“,而不是使用完整路径)。
可以在GitHub(RegClassCS)上找到Registry“class”(函数,实际上)。
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo("NaturalDocs.exe", "-h");
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = true;
var process = System.Diagnostics.Process.Start (startInfo);
process.WaitForExit();
if (process.ExitCode != 0)
{
string Components = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components";
bool breakFlag = false;
string hKeyName = "HKEY_LOCAL_MACHINE";
if (Environment.Is64BitOperatingSystem)
{
hKeyName = "HKEY_LOCAL_MACHINE64";
}
string[] subKeyNames = RegGetSubKeyNames(hKeyName, Components);
// Array.Reverse(subKeyNames);
for(int i = 0; i <= subKeyNames.Length - 1; i++)
{
string[] valueNames = RegGetValueNames(hKeyName, subKeyNames[i]);
foreach(string valueName in valueNames)
{
string valueKind = RegGetValueKind(hKeyName, subKeyNames[i], valueName);
switch(valueKind)
{
case "REG_SZ":
// case "REG_EXPAND_SZ":
// case "REG_BINARY":
string valueSZ = (RegGetValue(hKeyName, subKeyNames[i], valueName) as String);
if (valueSZ.IndexOf("NaturalDocs.exe") != -1)
{
startInfo = new System.Diagnostics.ProcessStartInfo("setx", "path \"%path%;" + System.IO.Path.GetDirectoryName(valueSZ) + "\" /M");
startInfo.Verb = "runas";
process = System.Diagnostics.Process.Start (startInfo);
process.WaitForExit();
if (process.ExitCode != 0)
{
Abort("SETX failed.");
}
breakFlag = true;
}
break;
/*
case "REG_MULTI_SZ":
string[] valueMultiSZ = (string[])RegGetValue("HKEY_CURRENT_USER", subKeyNames[i], valueKind);
for(int k = 0; k <= valueMultiSZ.Length - 1; k++)
{
Ketarin.Forms.LogDialog.Log("valueMultiSZ[" + k + "] = " + valueMultiSZ[k]);
}
break;
*/
default:
break;
}
if (breakFlag)
{
break;
}
}
if (breakFlag)
{
break;
}
}
}
即使你不使用Ketarin,你可以很容易地粘贴功能,通过Visual Studio或CSC建立它。
可以采用更通用的方法,使用RegClassVBS,它允许注册表键递归,并且不依赖于.NET Framework平台或构建过程。
请注意枚举组件密钥的过程可能是CPU密集型的。上面的例子有一个Length参数,你可以用来向用户显示一些进度(可能类似于“我从(subKeysName.Length - 1)剩余的键' - 是有创意的)。 RegClassVBS中可以采用类似的方法。
这两个类(RegClassCS和RegClassVBS)都有文档和示例可以指导您,并且您可以在任何软件中使用它并为它们的开发作出贡献,以便对git回购进行提交,并且(当然)打开如果你发现任何你自己无法解决的问题,就可以在它的github页面上发布问题,这样我们可以尝试重现问题,找出我们可以做些什么。 =)
我还没有做到这一点,所以我仍然需要知道如何获得目录... – 2008-11-01 18:44:09
你用什么来创建MSI文件,每种语言都会有它的规格来获取这些信息 – CheGueVerra 2008-11-01 18:46:29