C#重新加载系统环境变量

5

当我启动C#进程时,系统环境变量会被其他进程更改。因此,我希望重新加载环境到我的进程中,因为这个应用程序也会启动需要更新环境的子进程。这是我尝试获取和设置环境变量的方式:

Dictionary<String,String> uservars= new Dictionary<String,String>();
  Dictionary<String, String> sysvars = new Dictionary<String, String>();
  foreach (System.Collections.DictionaryEntry de in System.Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Machine))
    sysvars.Add(de.Key.ToString().ToUpper(),de.Value.ToString());

  foreach (System.Collections.DictionaryEntry de in System.Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User))
  {
    uservars.Add(de.Key.ToString().ToUpper(), de.Value.ToString());
  }
  Dictionary<string, string> newdict = new Dictionary<string, string>();
  foreach (KeyValuePair<String, String> kvp in uservars)
  {
    if (sysvars.ContainsKey(kvp.Key))
    {
      newdict.Add(kvp.Key, kvp.Value + ";" + sysvars[kvp.Key]);
      sysvars.Remove(kvp.Key);
    }
    else
      newdict.Add(kvp.Key, kvp.Value);
  }
  foreach (KeyValuePair<string, string> kvp in sysvars)
    newdict.Add(kvp.Key, kvp.Value);

  foreach (KeyValuePair<string, string> kvp in newdict)
  {
    System.Environment.SetEnvironmentVariable(kvp.Key, kvp.Value);
  }

问题是,我使用System.Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User)获取的环境变量与应用程序启动时相同。但这些不是更新后的变量。
有没有直接从系统中获取这些变量的方法?

此外,我想提一下:如果我尝试使用RegistryKey regEnvir = Registry.CurrentUser.OpenSubKey("Environment");从注册表中获取环境变量,我也会得到我启动应用程序时的旧变量集。 - user1829716
错误的键,系统环境存储在HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment中。如果您没有看到它变化,那么这个程序只会修改自己的环境,并可能将其传递给启动的进程。 - Hans Passant
2个回答

3
有三组环境变量 - 来自计算机的全局变量,用户保存的变量和当前进程的变量。 Environment.SetEnvironmentVariable(key, value) 设置当前进程的变量,不会更改全局或用户的变量,要读取当前进程的变量,需要使用 Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Process)
当您运行子进程时,您的进程环境变量将被复制到子进程环境变量中。
更新(回答评论):
我认为您误解了环境变量的工作方式,它们只能在进程创建期间从父进程传递数据到子进程中,不能在进程之间传递数据。
环境变量的工作方式如下:
每个进程都有自己私有的环境变量副本,每个进程可以随时更改该私有副本,它是一份私有副本,对系统的其余部分没有任何影响。
当一个进程启动另一个进程时,父进程的私有环境变量被复制到新的子进程中,此操作后新的子进程具有私有环境变量副本,不再与父进程连接。
在注册表中存储有机器和用户环境变量,这些值在启动时传递给第一个进程(如果发送了正确的通知,则Windows资源管理器将在启动新进程时加载它们,以避免重新启动),更改进程的环境变量不会更改用户/机器设置,更改用户/机器设置不会影响任何正在运行的进程。
例如,在两个命令(cmd.exe)窗口中运行,使用SET命令更改其中一个的环境,然后在另一个窗口运行SET命令并查看没有发生任何更改。
因此,不存在“系统的当前环境”这样的东西,如果一个进程更改其环境,则没有办法让另一个进程发现和读取此更改(除非使用允许调试器读取其他进程内存的API,但您真的不想去那里)。

这是我所知道的。我的问题是,如何获取系统当前的环境变量设置。场景如下:在我的应用程序运行时刻t0期间,用户或脚本更改系统环境变量。在t1时间,用户想要在应用程序上启动一个操作。在此时间之前,我的应用程序将从系统中获取当前环境设置并更新自己的环境变量。然后,该应用程序还创建子进程等。 - user1829716

1
我相信如果在创建新进程之前广播WM_SETTINGCHANGED消息,它将继承新的环境设置。因此,您需要pInvoke Windows SDK PostMessage()或SendMessage()函数。只需将LPARAM和WPARAM参数都传递为0即可。

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