如何在C#中设置系统环境变量?

时间:2013-10-31 11:33:13

标签: c# .net environment-variables

我正在尝试在我的应用程序中设置系统环境变量,但获得SecurityException。我测试了我在谷歌找到的所有内容 - 没有成功。 这是我的代码(注意,我是我的电脑的管理员并以管理员身份运行VS2012):

尝试1

new EnvironmentPermission(EnvironmentPermissionAccess.Write, "TEST1").Demand();
Environment.SetEnvironmentVariable("TEST1", "MyTest", EnvironmentVariableTarget.Machine);

尝试2

new EnvironmentPermission(EnvironmentPermissionAccess.Write, "TEST1").Demand();

using (var envKey = Registry.LocalMachine.OpenSubKey(@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment", true))
{

  Contract.Assert(envKey != null, @"HKLM\System\CurrentControlSet\Control\Session Manager\Environment is missing!");
  envKey.SetValue("TEST1", "TestValue");
}

尝试3 我还试图装出我的app with administrator priviliges

你还有其他建议吗?

2 个答案:

答案 0 :(得分:22)

documentation告诉您如何执行此操作。

  

调用SetEnvironmentVariable对系统环境变量没有影响。要以编程方式添加或修改系统环境变量,请将它们添加到HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment注册表项,然后广播WM_SETTINGCHANGE消息,并将lParam设置为字符串"Environment"。这允许应用程序(如shell)获取更新。

因此,您需要写入您已尝试写入的注册表设置。然后如上所述广播WM_SETTINGCHANGE消息。您需要以提升的权限运行才能成功。

一些示例代码:

using Microsoft.Win32;
using System;
using System.Diagnostics.Contracts;
using System.Runtime.InteropServices;

namespace ConsoleApplication1
{
    class Program
    {
        const int HWND_BROADCAST = 0xffff;
        const uint WM_SETTINGCHANGE = 0x001a;

        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern bool SendNotifyMessage(IntPtr hWnd, uint Msg, 
            UIntPtr wParam, string lParam);

        static void Main(string[] args)
        {
            using (var envKey = Registry.LocalMachine.OpenSubKey(
                @"SYSTEM\CurrentControlSet\Control\Session Manager\Environment",
                true))
            {
                Contract.Assert(envKey != null, @"registry key is missing!");
                envKey.SetValue("TEST1", "TestValue");
                SendNotifyMessage((IntPtr)HWND_BROADCAST, WM_SETTINGCHANGE,
                    (UIntPtr)0, "Environment");
            }
        }
    }
}

但是,虽然此代码确实有效,但.net框架提供了更简单地执行相同任务的功能。

Environment.SetEnvironmentVariable("TEST1", "TestValue", 
    EnvironmentVariableTarget.Machine);

三个参数Environment.SetEnvironmentVariable重载的documentation表示:

  

如果target是EnvironmentVariableTarget.Machine,则环境变量存储在本地计算机注册表的HKEY_LOCAL_MACHINE \ SYSTEM \ ControlSet001 \ Control \ Session Manager \ Environment项中。它也会复制到文件资源管理器的所有实例中。然后,环境变量将由从文件资源管理器启动的任何新进程继承。

     

如果target是User或Machine,则通过Windows WM_SETTINGCHANGE消息通知其他应用程序设置操作。

答案 1 :(得分:1)

除了David Heffernan的答案外,下面的函数还避免了一些设置和将值附加到环境变量的陷阱:

void AddToEnvironmentVariable(string variable, string newValue, EnvironmentVariableTarget target)
{
    var content = Environment.GetEnvironmentVariable(variable, target) ?? string.Empty;
    if (content.Contains(newValue))
        return;

    var varBuilder = new StringBuilder(content);
    if (content != string.Empty && !content.EndsWith(';'))
        varBuilder.Append(";");
    varBuilder.Append(newValue);
    var finalValue = varBuilder.ToString();

    Environment.SetEnvironmentVariable(variable, finalValue, EnvironmentVariableTarget.Process);
    if (target != EnvironmentVariableTarget.Process)
        Environment.SetEnvironmentVariable(variable, finalValue, target);
}

它使用;处理正确的附加操作,并通过设置GetEnvironmentVariable目标来确保对Process的后续调用包含附加值。