2017-02-21 154 views
0

我有一个C#应用程序,当运行设置一些环境变量。 这些环境变量需要在系统范围内设置。Windows环境变量扩展:管理员与非管理员

我使用此代码来实际执行该设置。

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的新env vars。 exe,但我不明白他们为什么没有扩大。

为什么要运行cmd并设置为管理员显示完全展开的环境变量并运行cmd并设置为普通用户不会?

当在C#程序中设置env vars时,我使用RegistryValueKind.ExpandString枚举。

编辑: 我知道声明时间顺序与系统变量的扩展时间问题,并编辑了问题示例以反映这一点。

回答

0

对环境变量的更改不可见。您需要notify对注册表进行更改的运行过程。

而且,您应该记住,您在进程(您的cmd窗口)中看到的环境不是从注册表中获取的,而是从其父进程继承的。您可以发送通知,但有些流程会处理它,有些则不会。处理环境本身之前

  • 一些值是从注册表检索到:

    的问题其余部分应该由环境负荷顺序进行说明。 %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变量被处理。
    • 在用户级别定义的变量会覆盖系统环境的值,除了一些变量(例如,PATH),其中的值被连接在一起。

所有这一切意味着,

  • ,不同的用户,可能会看到不同的环境

  • 同一用户可以看到不同的环境取决于父进程是什么。使用Win + R并执行cmd比使用Shift +在文件夹中右键单击并选择“在此处打开命令”不同。父进程是不同的。