设置向导项目中是否可以注册环境变量?

9
我正在为我的程序创建一个Visual Studio 2008安装向导。我发现可以添加注册表项等操作。但是,是否有可能在不编写自定义操作的情况下注册Windows环境变量呢?如果必须编写自定义操作,那么最简单的方法是什么?
http://support.microsoft.com/kb/307353

Visual Studio 2009 并不存在。实际上,需要注册环境变量的安装程序实例可以用一只手数出来。很有可能你并不是其中之一。 - Cody Gray
@CodyGray,请解释可能的替代方案。 - Andrey Rubshtein
1
我猜他会推荐注册表或用户配置目录/程序数据目录中的数据文件。或者如果你的项目是一个.Net项目,可以使用app.config值。虽然我不同意这种说法-如果你将程序添加到“PATH”,那么这可能是操纵环境变量的好理由。否则,我同意有更好的地方放置你的数据。 - Merlyn Morgan-Graham
2
嗯,是的。@Merlyn的建议与我的相当一致。但我不认为将您的程序添加到“PATH”中是正确的做法。再次强调,极其有限的使用情况。您不应该假定用户希望您限制他们的“PATH”。我肯定不想这样做。 - Cody Gray
我只会为旨在增强命令行脚本的工具执行此操作,如果我这样做,我会将其作为可选项,并默认关闭它。 明显受限制。 - Merlyn Morgan-Graham
为什么环境变量如此不好?是什么使注册表更好? - Andrey Rubshtein
4个回答

9

警告: 请勿使用此方法,它很危险。请使用内置的MSI功能更新环境变量。

示例: 直接写入HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment - Path会清除已有的内容。非常严重。

解决方案: MSI功能提供了Environment表,以可靠的方式促进合并和更新环境变量。请注意,该表也足够复杂,可能会触发意外结果。请进行充分测试。特别是卸载方案。


使用Visual Studio 2008,您可以通过在Windows注册表中设置适当的变量来轻松完成:
  1. 在“解决方案资源管理器”中,右键单击项目(而非解决方案),选择“查看->注册表”
  2. 创建注册表键(文件夹):
    1. 对于“用户”变量:右键单击“HKEY_CURRENT_USER”,选择“新建键”,并将其命名为“Environment”。
    2. 对于“系统”变量:右键单击“HKEY_LOCAL_MACHINE”,选择“新建键”,并将其命名为“SYSTEM”。“继续这样做以创建路径“HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment”。”
  3. 右键单击“Environment”键(文件夹),选择“新建->字符串”,并赋予它所需名称。
  4. 选择字符串后,找到“属性”窗口(按Alt+Enter会显示该窗口)
  5. 在属性窗口中,填写所需的“值”。
如果您希望Value引用安装目录,可以使用属性变量进行如下设置:[TARGETDIR]SomeFile.ext(有关更多属性变量,请参见http://msdn.microsoft.com/en-us/library/aa370905%28v=vs.85%29.aspx)。

向 OP 表示歉意 - 他/她已经诚实地提供了详细的答案 - 我很抱歉,这是一种非常危险的方法下面的答案是正确的方法。或者您可以在这里找到更长的写作:路径更新与 AppPaths - Stein Åsmul
一般来说,这是危险的吗?还是只有在特定情况下才会危险,比如修改现有变量(特别是PATH)?如果您正在创建自定义环境变量,我不清楚危险在哪里。 - michaelmoo
1
这些键是Windows中的“实现细节”。只有官方的Windows API函数才应该在此处编写环境变量管理。发生的情况是,使用上述方法覆盖了原有值,而不是合并新值 - 抹掉了所有内容。非常严重 - 特别是对于系统PATH变量,但它适用于所有环境变量(只是影响不同)。建议您保留答案,如果您删除它,其他人将建议使用MSI内置方法的原因。 - Stein Åsmul
我更新了头部区域,希望你不介意。只是需要防止人们因为被清除的PATH变量而遇到麻烦——这在开发团队中尤其糟糕。顺便说一下,有一些技巧可以恢复PATH变量:**1)** 使用系统还原,**2)** 尝试上次已知的好状态?**3)** 使用Process Explorer => 环境选项卡从尚未重新启动的EXE文件中获取缓存的PATH,**4)** 从具有相同软件包配置的类似SOE机器复制PATH,**5)** 通过注册表中的ControlSet001(或更高版本)进行恢复。这就是我所记得的全部内容。 - Stein Åsmul

3
Windows Installer 支持通过环境表使用环境变量,但 Visual Studio 安装项目不允许使用它。
解决方案是使用支持环境变量的不同安装工具:http://en.wikipedia.org/wiki/List_of_installation_software 另一种解决方案是通过使用Orca手动将其添加到环境表中进行编辑。
还有您提到的自定义操作方法。

3
顶部答案解释了如何在没有自定义操作的情况下完成它,但那些寻找自定义操作的人可以使用以下代码作为模板:
 [RunInstaller(true)]
public partial class GRInstallCustomAction : System.Configuration.Install.Installer
{
    string environmentKey = @"SYSTEM\CurrentControlSet\Control\Session Manager\Environment";
    string pathUrl = "C:\\Program Files (86)\\TargetFolder";
    public GRInstallCustomAction()
    {
        InitializeComponent();
    }

    [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)]
    public override void Install(IDictionary stateSaver)
    {
        base.Install(stateSaver);
    }

    [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)]
    public override void Commit(IDictionary savedState)
    {
        base.Commit(savedState);

        string environmentVar = Environment.GetEnvironmentVariable("PATH");


        //get non-expanded PATH environment variable            
        string oldPath = (string)Registry.LocalMachine.CreateSubKey(environmentKey).GetValue("Path", "", RegistryValueOptions.DoNotExpandEnvironmentNames);


        var index = oldPath.IndexOf(pathUrl);
        if (index < 0)
        {
            //set the path as an an expandable string
            Registry.LocalMachine.CreateSubKey(environmentKey).SetValue("Path", oldPath + ";" + pathUrl, RegistryValueKind.ExpandString);
        }

    }

    [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)]
    public override void Rollback(IDictionary savedState)
    {
        base.Rollback(savedState);


    }

    [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)]
    public override void Uninstall(IDictionary savedState)
    {
        base.Uninstall(savedState);

        //get non-expanded PATH environment variable            
        string oldPath = (string)Registry.LocalMachine.CreateSubKey(environmentKey).GetValue("Path", "", RegistryValueOptions.DoNotExpandEnvironmentNames);

        string removeString = pathUrl + ";";
        var index = oldPath.IndexOf(removeString);
        if (index < 0)
        {
            removeString = pathUrl;
            index = oldPath.IndexOf(removeString);
        }

        if (index > -1)
        {
            oldPath = oldPath.Remove(index, pathUrl.Length);
            //set the path as an an expandable string
            Registry.LocalMachine.CreateSubKey(environmentKey).SetValue("Path", oldPath, RegistryValueKind.ExpandString);
        }
    }
}

本教程将向您展示如何创建和应用自定义操作: https://msdn.microsoft.com/zh-cn/library/d9k65z2d(v=vs.100).aspx

注:此链接为中文版。

0

Ickydime(请参见上面的答案)的自定义操作示例显示了如何通过扩展PATH env变量来添加环境变量。下面我将分享如何使用Environment.SetEnvironmentVariable创建一个新的环境变量。

    string environmentKey = "MY_VAR";
    string pathUrl = "%ProgramFiles%\\...";
    public Installer1()
    {
        InitializeComponent();
    }

    [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)]
    public override void Install(IDictionary stateSaver)
    {
        base.Install(stateSaver);
    }

    [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)]
    public override void Commit(IDictionary savedState)
    {
        base.Commit(savedState);
        Environment.SetEnvironmentVariable(environmentKey, pathUrl, EnvironmentVariableTarget.Machine);
    }

    [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)]
    public override void Rollback(IDictionary savedState)
    {
        base.Rollback(savedState);
    }

    [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)]
    public override void Uninstall(IDictionary savedState)
    {
        base.Uninstall(savedState);
        Environment.SetEnvironmentVariable(environmentKey, null, EnvironmentVariableTarget.Machine);
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接