如何获取安装目录?

时间:2008-11-01 18:32:50

标签: windows deployment installer windows-installer

MSI存储将来卸载任务的安装目录。

使用INSTALLPROPERTY_INSTALLLOCATION属性(即"InstallLocation")仅适用于安装程序在安装期间设置了ARPINSTALLLOCATION属性。但是这个属性是可选的,几乎没有人使用它。

如何检索安装目录?

6 个答案:

答案 0 :(得分:2)

使用注册表项来跟踪安装目录,这样您就可以在升级和删除产品时引用它。

使用WIX我会在安装目录的Directy标记之后创建一个创建密钥的Component,声明

答案 1 :(得分:0)

我会尝试使用Installer.OpenProduct(productcode)。这将打开一个会话,然后您可以在该会话中请求Property(“TARGETDIR”)。

答案 2 :(得分:0)

试试这个: var sPath = this.Context.Parameters [“assemblypath”]。ToString();

答案 3 :(得分:0)

我使用MsiGetComponentPath() - 您需要ProductId和ComponentId,但是您可以获得已安装文件的完整路径 - 只需选择一个转到安装目录位置的路径即可。如果你想获得任何随机MSI的目录值,我不相信有一个API可以让你这样做。

答案 4 :(得分:0)

正如线程中其他地方所述,我通常在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并通过查找具有正确版本和日期的文件的窄版本范围来设置严格签名。

答案 5 :(得分:0)

最近我需要通过Natural Docs自动安装Ketarin。我可以假设它安装在默认路径(%ProgramFiles(x86)%\Natural Docs)中,但我决定采取安全的方法。遗憾的是,即使安装程序在HKLM\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall上创建了一个密钥,它的价值也没有让我找到安装目录。

Stein的回答建议使用AppSearch MSI功能,看起来很有趣,但遗憾的是,Natural Docs MSI安装程序并没有为他的方法工作提供签名表。

所以我决定在注册表中搜索任何对Natural Docs install dir的引用,然后在HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components键中找到一个。

MSI Components Registry Key

我在C#中为Ketarin开发了一个允许递归的Reg类。所以我通过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"而不是使用完整路径)。

The Registry" class" (函数,实际上)可以在GitHub上找到(RegClassCS)。

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参数,您可以使用该参数向用户显示一些进度(可能是&#34;我来自(subKeysName.Length - 1)键剩余的&#34; - 具有创造性)。可以在RegClassVBS中采用类似的方法。

这两个类(RegClassCS和RegClassVBS)都有可以指导您的文档和示例,您可以在任何软件中使用它,并有助于开发它们在git repo上进行提交,并且(当然)打开一个问题在它的github页面上,如果你发现任何你无法解决的问题,那么我们可以尝试重现问题,找出我们可以做些什么。 =)