2017-02-21 191 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 +在文件夾中右鍵單擊並選擇「在此處打開命令」不同。父進程是不同的。