windows 如何获取安装目录?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/255928/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 11:32:58  来源:igfitidea点击:

How to get the installation directory?

windowsdeploymentinstallerwindows-installer

提问by Michael Damatov

The MSI stores the installation directory for the future uninstall tasks.

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

Using the INSTALLPROPERTY_INSTALLLOCATIONproperty (that is "InstallLocation") works only the installer has set the ARPINSTALLLOCATIONproperty during the installation. But this property is optional and almost nobody uses it.

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

How could I retrieve the installation directory?

我如何检索安装目录?

采纳答案by CheGueVerra

Use a registry key to keep track of your install directory, that way you can reference it when upgrading and removing the product.

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

Using WIX I would create a Component that creates the key, right after the Directy tag of the install directory, declaration

使用 WIX,我将创建一个创建密钥的组件,紧跟在安装目录的 Directy 标记之后,声明

回答by Martin v. L?wis

I would try to use Installer.OpenProduct(productcode). This opens a session, on which you can then ask for Property("TARGETDIR").

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

回答by Martin v. L?wis

Try this: var sPath = this.Context.Parameters["assemblypath"].ToString();

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

回答by Martin v. L?wis

I'd use MsiGetComponentPath() - you need the ProductId and a ComponentId, but you get the full path to the installed file - just pick one that goes to the location of your installation directory. If you want to get the value of a directory for any random MSI, I do not believe there is an API that lets you do that.

我会使用 MsiGetComponentPath() - 您需要 ProductId 和一个 ComponentId,但您可以获得已安装文件的完整路径 - 只需选择一个进入安装目录位置的路径。如果您想获取任何随机 MSI 的目录值,我认为没有 API 可以让您这样做。

回答by Stein ?smul

As stated elsewhere in the thread, I normally write a registry key in HKLM to be able to easily retrieve the installation directory for subsequent installs.

正如线程中其他地方所述,我通常在 HKLM 中编写一个注册表项,以便能够轻松检索安装目录以进行后续安装。

In cases when I am dealing with a setup that hasn't done this, I use the built-in Windows Installer feature AppSearch: http://msdn.microsoft.com/en-us/library/aa367578(v=vs.85).aspxto locate the directory of the previous install by specifying a file signature to look for.

如果我处理的设置尚未完成,我会使用内置的 Windows Installer 功能 AppSearch:http: //msdn.microsoft.com/en-us/library/aa367578(v= vs.85 ).aspx通过指定要查找的文件签名来定位先前安装的目录。

A file signature can consist of the file name, file size and file version and other file properties. Each signature can be specified with a certain degree of flexibility so you can find different versions of the the same file for instance by specifying a version range to look for. Please check the SDK documentation: http://msdn.microsoft.com/en-us/library/aa371853(v=vs.85).aspx

文件签名可以由文件名、文件大小和文件版本以及其他文件属性组成。可以以一定的灵活性指定每个签名,因此您可以找到同一文件的不同版本,例如通过指定要查找的版本范围。请查看 SDK 文档:http: //msdn.microsoft.com/en-us/library/aa371853(v=vs.85).aspx

In most cases I use the main application EXE and set a tight signature by looking for a narrow version range of the file with the correct version and date.

在大多数情况下,我使用主应用程序 EXE 并通过查找具有正确版本和日期的文件的狭窄版本范围来设置紧密签名。

回答by jaysponsored

Recently I needed to automate Natural Docsinstall through Ketarin. I could assume it was installed into default path (%ProgramFiles(x86)%\Natural Docs), but I decided to take a safe approach. Sadly, even if the installer created a key on HKLM\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall, none of it's value lead me to find the install dir.

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

The Stein answer suggests AppSearch MSI function, and it looks interesting, but sadly Natural Docs MSI installer doesn't provide a Signature table to his approach works.

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

So I decided to search through registry to find any reference to Natural Docs install dir, and I find one into HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Componentskey.

所以我决定在注册表中搜索以找到对 Natural Docs 安装目录的任何引用,然后我找到了一个 into HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Componentskey。

MSI Components Registry Key

MSI 组件注册表项

I developed a Reg Class in C# for Ketarin that allows recursion. So I look all values through HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Componentsand if the Main application executable (NaturalDocs.exe) is found into one of subkeys values, it's extracted (C:\Program Files (x86)\Natural Docs\NaturalDocs.exebecomes C:\Program Files (x86)\Natural Docs) and it's added to the system environment variable %PATH% (So I can call "NaturalDocs.exe" directly instead of using full path).

我在 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" (functions, actually) can be found on GitHub (RegClassCS).

注册表“类”(实际上是函数)可以在 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;
        }
    }
}

Even if you don't use Ketarin, you can easily paste the function and build it through Visual Studio or CSC.

即使您不使用 Ketarin,您也可以轻松粘贴该函数并通过 Visual Studio 或CSC构建它。

A more general approach can be taken using RegClassVBSthat allow registry key recursion and doesn't depend on .NET Framework platform or build processes.

使用RegClassVBS可以采用更通用的方法,该方法允许注册表项递归并且不依赖于 .NET Framework 平台或构建过程。

Please note that the process of enumerating the Components Key can be CPU intense. The example above has a Length parameter, that you can use to show some progress to the user (maybe something like "i from (subKeysName.Length - 1) keys remaining" - be creative). A similar approach can be taken in RegClassVBS.

请注意,枚举组件键的过程可能会占用大量 CPU。上面的示例有一个 Length 参数,您可以使用它向用户显示一些进度(可能类似于“我来自 (subKeysName.Length - 1) 个剩余的键” - 有创意)。在 RegClassVBS 中可以采用类似的方法。

Both classes (RegClassCS and RegClassVBS) have documentation and examples that can guide you, and you can use it in any software and contribute to the development of them making a commit on the git repo, and (of course) opening a issue on it's github pages if you find any problem that you couldn't resolve yourself so we can try to reproduce the issue to figure out what we can do about it. =)

这两个类(RegClassCS 和 RegClassVBS)都有可以指导你的文档和示例,你可以在任何软件中使用它并为它们的开发做出贡献,在 git repo 上提交,并且(当然)在它的 github 上打开一个问题如果您发现任何您自己无法解决的问题,我们可以尝试重现该问题以找出我们可以采取的措施。=)