如何在C#中永久设置环境变量

14

我正在使用以下代码来获取和设置环境变量。

public static string Get( string name, bool ExpandVariables=true ) {
    if ( ExpandVariables ) {
        return System.Environment.GetEnvironmentVariable( name );
    } else {
        return (string)Microsoft.Win32.Registry.LocalMachine.OpenSubKey( @"SYSTEM\CurrentControlSet\Control\Session Manager\Environment\" ).GetValue( name, "", Microsoft.Win32.RegistryValueOptions.DoNotExpandEnvironmentNames );
    }
}

public static void Set( string name, string value ) {
    System.Environment.SetEnvironmentVariable( name, value );
}

我面临的问题是,即使程序以管理员身份运行,环境变量也只在程序运行期间存在。我通过在先前实例中设置的变量上执行 Get 来确认了这一点。

以上的示例用法

Set("OPENSSL_CONF", @"c:\openssl\openssl.cfg");

并且进行检索

MessageBox.Show( Get("OPENSSL_CONF") );

在程序运行期间,使用Set后,使用Get返回值时没有任何问题。问题在于环境变量并不是永久的(在系统上设置)。

它也从未显示在高级属性下。

提前感谢。


为了使它们持久存在,您需要设置系统变量,目前您只是设置特定于进程的变量,这些变量仅在程序运行期间存在。 - Mrinal Kamboj
如果您只是从注册表中获取变量以设置环境变量,那么为什么不直接使用它,为什么要将其设置为环境变量。只有在动态设置内容(注册表内容几乎是静态的)并希望其持久存在时,才有意义。此外,在设置注册表值更改后会发生什么? - Mrinal Kamboj
4个回答

23
在程序运行时,使用Set设置值后,可以使用Get获取该值而没有任何问题。问题在于环境变量不是永久性的(在系统上设置)。
这是因为你正在使用的SetEnvironmentVariable重载将其存储在进程变量中。来自docs
调用此方法等效于使用目标参数的EnvironmentVariableTarget.Process重载,其中目标参数的值为EnvironmentVariableTarget.Process。
你需要使用指定EnvironmentVariableTarget.Machine的重载。
public static void Set(string name, string value) 
{
    Environment.SetEnvironmentVariable(name, value, EnvironmentVariableTarget.Machine);
}

Itchakov,你知道使用EnvironmentVariableTarget.Machine是否需要特定的权限吗? - BendEg

2

2

1
还要记住,环境变量始终在进程开始时继承,因此不能在进程已经运行时获取,这需要重新启动。 - Mrinal Kamboj
1
不确定为什么在这里搜索、谷歌和写文章时的“自动”搜索中都没有出现这些结果。对于搜索引擎来说,这是三次失败的壮举 ;) - Kraang Prime

0
这是一个示例,通过编程方式编辑注册表来永久更新用户PATH变量:
// Admin Permission not-required:
//      HKCU\Environment\Path
// Admin Permission required:
//      HKLM\SYSTEM\CurrentControlSet\Control
//         \Session Manager\Environment\Path

public static void UserPathAppend(string path, int verbose=1) {
    string oldpath = UserPathGet();

    List<string> newpathlist = oldpath.Split(';').ToList();
    newpathlist.Add(path);

    string newpath = String.Join(";", newpathlist.ToArray());

    UserPathSet(newpath);

    UpdateEnvPath();

    if (verbose!=0) {
        System.Windows.MessageBox.Show(
            "PATH APPEND:\n\n"
            + path + "\n\n"
            + "OLD HKCU PATH:\n\n"
            +  oldpath + "\n\n"
            + "NEW HKCU PATH:\n\n"
            +  newpath + "\n\n"
            + "REGISTRY KEY MODIFIED:\n\n"
            + "HKCU\\Environment\\Path\n\n"
            + "NOTE:\n\n"
            + "'Command Path' is a concat of 'HKLM Path' & 'HKCU Path'.\n",
            "Updated Current User Path Environment Variable"
        );
    }
}

public static void UserPathPrepend(string path, int verbose=1) {
    string oldpath = UserPathGet();

    List<string> newpathlist = oldpath.Split(';').ToList();
    newpathlist.Insert(0, path);

    string newpath = String.Join(";", newpathlist.ToArray());

    UserPathSet(newpath);

    UpdateEnvPath();

    if (verbose != 0) {
        System.Windows.MessageBox.Show(
            "PATH PREPEND:\n\n"
            + path + "\n\n"
            + "OLD HKCU PATH:\n\n"
            +  oldpath + "\n\n"
            + "NEW HKCU PATH:\n\n"
            +  newpath + "\n\n"
            + "REGISTRY KEY MODIFIED:\n\n"
            + "HKCU\\Environment\\Path\n\n"
            + "NOTE:\n\n"
            + "'Command Path' is a concat of 'HKLM Path' & 'HKCU Path'.\n",
            "Updated Current User Path Environment Variable"
        );
    }
}

public static string UserPathGet()
{
    // Reads Registry Path "HKCU\Environment\Path"
    string subKey = "Environment";

    Microsoft.Win32.RegistryKey sk = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(subKey);

    if (sk == null)
        return null;
    else
        return sk.GetValue("Path").ToString();
}

public static void UserPathSet(string newpath)
{
    // Writes Registry Path "HKCU\Environment\Path"
    string subKey = "Environment";

    Microsoft.Win32.RegistryKey sk1 = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(subKey);
    sk1.SetValue("Path", newpath);
}

//===========================================================
// Private: This part required if you don't want to logout 
//          and login again to see Path Variable update
//===========================================================

[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern IntPtr SendMessageTimeout(IntPtr hWnd, 
            uint Msg, UIntPtr wParam, string lParam, 
            SendMessageTimeoutFlags fuFlags, 
            uint uTimeout, out UIntPtr lpdwResult);

private enum SendMessageTimeoutFlags : uint
{
    SMTO_NORMAL = 0x0, SMTO_BLOCK = 0x1, 
    SMTO_ABORTIFHUNG = 0x2, SMTO_NOTIMEOUTIFNOTHUNG = 0x8
}

private static void UpdateEnvPath() {
    // SEE: https://support.microsoft.com/en-us/help/104011/how-to-propagate-environment-variables-to-the-system
    // Need to send WM_SETTINGCHANGE Message to 
    //    propagage changes to Path env from registry
    IntPtr HWND_BROADCAST = (IntPtr)0xffff;
    const UInt32 WM_SETTINGCHANGE = 0x001A;
    UIntPtr result;
    IntPtr settingResult
        = SendMessageTimeout(HWND_BROADCAST,
                             WM_SETTINGCHANGE, (UIntPtr)0,
                             "Environment",
                             SendMessageTimeoutFlags.SMTO_ABORTIFHUNG,
                             5000, out result);
}

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