我有一个C#应用程序,在运行时设置一些环境变量。 这些环境变量需要在系统范围内设置。
我使用此代码实际执行该设置。
public static void SetEnvironmentVariable(string _keyName, string _value, RegistryValueKind _type)
{
using (RegistryKey reg = Registry.LocalMachine.OpenSubKey(@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment", true))
{
if (reg != null)
{
reg.SetValue(_keyName, _value, _type);
}
else
{
string x =
string.Format(
"Could find registry key that hosts Environment Variables: SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment");
App.AppLogger.Error(x);
throw new Exception(x);
}
}
}
此代码有效,但我注意到一些奇怪的行为。 运行我的应用程序和此代码后,我立即以常规用户身份运行cmd,并使用“set”命令查看环境。 它没有显示任何变化。
然后我以管理员身份运行cmd提示符并运行set。它显示了变化。不仅如此,它还显示了完全扩展的变量。其中ALLFOO = Foo,PATH = C:\ Windows \ System32;%ALLFOO%;, set命令显示PATH = C:\ Windows \ System32; Foo;。
然后我退出并重新开启。然后我作为普通用户运行cmd。 我输入set并显示新的环境变量,但未展开。 它显示PATH = C:\ Windows \ System32;%ALLFOO%; (由于某种原因,似乎可以毫不费力地扩展%SYSTEMROOT%。)
我知道注销并重新启动会导致启动的新Explorer.exe为常规用户的cmd.exe获取新的环境变量,但我不明白为什么它们不会被扩展。
为什么运行cmd并设置为管理员显示完全展开的环境变量并运行cmd并设置为普通用户不会?
在C#程序中设置env变量时,我使用RegistryValueKind.ExpandString枚举。
编辑: 我知道系统变量的扩展时间问题的声明时间顺序,并编辑了问题示例以反映这一点。
答案 0 :(得分:0)
对环境变量的更改不是可见的。您需要notify正在运行的注册表更改过程。
并且,您应该记住,您在进程中看到的环境(您的cmd
窗口)不是从注册表中获取的,而是从其父进程继承的。您可以发送通知,但有些进程会处理,有些则不会。
其余问题应该通过环境加载顺序来解释:
在处理环境本身之前,会从注册表中检索一些值。 <{1}}在
中定义%systemroot%
加载系统环境
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SystemRoot
变量按字母顺序排在第一位REG_SZ
按字母顺序加入。由于REG_EXPAND_SZ
值已被加入,因此可以扩展它们。如果REG_SZ
变量引用了尚未展开的另一个REG_EXPAND_SZ
变量(字母顺序),则无法解析此引用,也不会展开。REG_EXPAND_SZ
,然后处理REG_SZ
变量。REG_EXPAND_SZ
)除外,其中值是连接的。所有这意味着
不同的用户可以并且可能会看到不同的环境
相同的用户可以看到不同的环境,具体取决于父进程的内容。使用 Win + R 并执行PATH
与在文件夹中使用 Shift +右键单击并选择“在此处打开命令”不同。父流程是不同的。