Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Function to Refresh Environment Variables


  • Please log in to reply
6 replies to this topic
NoobSawce
  • Members
  • 103 posts
  • Last active: Mar 19 2011 05:11 AM
  • Joined: 15 Feb 2011
Under normal circumstances, when a process is launched in Windows, it is passed a copy of the system's environment variables. This means that if another process updates one of the system's environment variables, your script won't get the changed value (although it may get a WM_SETTINGSCHANGE window message). This function allows you to "refresh" your copy of the environment variable with the system's copy defined in the registry. This script was tested on 32-Bit build of AHK_L, however I've written it so that it should work with any version of AHK, including basic.
RefreshEnvironment()
{
	; load the system-wide environment variables first in case there are user-level
	; variables with the same name (since they override the system definitions).
	Loop, HKLM, SYSTEM\CurrentControlSet\Control\Session Manager\Environment, 0, 0
	{
		RegRead, vEnvValue
		If (A_LoopRegType == "REG_EXPAND_SZ") {
			If (!ExpandEnvironmentStrings(vEnvValue)) {
				Return False
			}
		}
		EnvSet, %A_LoopRegName%, %vEnvValue%
	}

	; now load the user level environment variables
	Loop, HKCU, Environment, 0, 0
	{
		RegRead, vEnvValue
		If (A_LoopRegType == "REG_EXPAND_SZ") {
			If (!ExpandEnvironmentStrings(vEnvValue)) {
				Return False
			}
		}
		EnvSet, %A_LoopRegName%, %vEnvValue%
	}

	; return success.
	Return True
}

ExpandEnvironmentStrings(ByRef vInputString)
{
	; get the required size for the expanded string
	vSizeNeeded := DllCall("ExpandEnvironmentStrings", "Str", vInputString, "Int", 0, "Int", 0)
	If (vSizeNeeded == "" || vSizeNeeded <= 0)
		return False ; unable to get the size for the expanded string for some reason
	
	vByteSize := vSizeNeeded + 1
	If (A_PtrSize == 8) { ; Only 64-Bit builds of AHK_L will return 8, all others will be 4 or blank
		vByteSize *= 2 ; need to expand to wide character sizes
	}
	VarSetCapacity(vTempValue, vByteSize, 0)
	
	; attempt to expand the environment string
	If (!DllCall("ExpandEnvironmentStrings", "Str", vInputString, "Str", vTempValue, "Int", vSizeNeeded))
		return False ; unable to expand the environment string
	vInputString := vTempValue
	
	; return success
	Return True
}


DavidBiesack
  • Members
  • 7 posts
  • Last active: Feb 21 2011 01:59 PM
  • Joined: 04 Feb 2011

This function allows you to "refresh" your copy of the environment variable with the system's copy defined in the registry.


I found that this script loses the system setting for PATH and only sets the user PATH. Instead, the two must be merged. Here is my revised code to do that. I don't know if other environment variables require merging,
but it should not be hard to add them

RefreshEnvironment()
{
   ; load the system-wide environment variables first in case there are user-level
   ; variables with the same name (since they override the system definitions).
   ; treat PATH and PATHEXT special - we must contactenate the user and system values.
   sysPATH := ""
   sysPATHEXT := ""
   Loop, HKLM, SYSTEM\CurrentControlSet\Control\Session Manager\Environment, 0, 0
   {
      RegRead, vEnvValue
      If (A_LoopRegType == "REG_EXPAND_SZ") {
         If (!ExpandEnvironmentStrings(vEnvValue)) {
            Return False
         }
      }
      EnvSet, %A_LoopRegName%, %vEnvValue%
      if (A_LoopRegName = "PATH") {
         sysPATH := vEnvValue
         }
      else if (A_LoopRegName = "PATHEXT") {
         sysPATHEXT := vEnvValue
         }
   }

   ; now load the user level environment variables
   Loop, HKCU, Environment, 0, 0
   {
      RegRead, vEnvValue
      If (A_LoopRegType == "REG_EXPAND_SZ") {
         If (!ExpandEnvironmentStrings(vEnvValue)) {
            Return False
         }
      }
      envVal := vEnvValue
      if (A_LoopRegName = "PATH") {
         envVal := envVal . ";" . sysPATH
        }
      else if (A_LoopRegName = "PATHEXT") {
         envVal := envVal . ";" . sysPATHEXT
        }
      EnvSet, %A_LoopRegName%, %envVal%
   }

   ; return success.
   Return True
}

ExpandEnvironmentStrings(ByRef vInputString)
{
   ; get the required size for the expanded string
   vSizeNeeded := DllCall("ExpandEnvironmentStrings", "Str", vInputString, "Int", 0, "Int", 0)
   If (vSizeNeeded == "" || vSizeNeeded <= 0)
      return False ; unable to get the size for the expanded string for some reason

   vByteSize := vSizeNeeded + 1
   If (A_PtrSize == 8) { ; Only 64-Bit builds of AHK_L will return 8, all others will be 4 or blank
      vByteSize *= 2 ; need to expand to wide character sizes
   }
   VarSetCapacity(vTempValue, vByteSize, 0)

   ; attempt to expand the environment string
   If (!DllCall("ExpandEnvironmentStrings", "Str", vInputString, "Str", vTempValue, "Int", vSizeNeeded))
      return False ; unable to expand the environment string
   vInputString := vTempValue

   ; return success
   Return True
}

(Updated to also concatenate PATHEXT)

NoobSawce
  • Members
  • 103 posts
  • Last active: Mar 19 2011 05:11 AM
  • Joined: 15 Feb 2011
Forgot about that. PATHEXT is the other one that should merge system and user values. For the others (i.e. single value variables like TMP and TEMP), the user environment variables should override the system value. Nice catch. :)

EDIT: I probably didn't notice this because I don't use environment variables that much, so all of my systems are pretty much set to the default, which only defines a user level TMP and TEMP variable. Although, I've always found it wierd that USERPROFILE is a system level variable and not a user level one. :?

DavidBiesack
  • Members
  • 7 posts
  • Last active: Feb 21 2011 01:59 PM
  • Joined: 04 Feb 2011

Forgot about that. PATHEXT is the other one that should merge system and user values.

I updated the source above to also concatenate PATHEXT.

Erik
  • Guests
  • Last active:
  • Joined: --
I tried this after manually changing a value in:
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Session Manager\Environment]
But it did not update when I opened a new command prompt.
Windows XP SP3.
AHK_L Version v1.1.00.00 (2010)

MsgBox, start
x=RefreshEnvironment()
MsgBox, Done

Any thoughts?

Erik
  • Guests
  • Last active:
  • Joined: --
x:=.....

And I get an error that AHK_L needs to close.....

BatRamboZPM
  • Members
  • 2 posts
  • Last active: Oct 22 2015 11:00 AM
  • Joined: 18 Feb 2015
Shortest version:

RefreshEnvironment()
{
	Path := ""
	PathExt := ""
	RegKeys := "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment,HKCU\Environment"
	Loop, Parse, RegKeys, CSV
	{
		Loop, Reg, %A_LoopField%, V
		{
			RegRead, Value
			If (A_LoopRegType == "REG_EXPAND_SZ" && !ExpandEnvironmentStrings(Value))
				Continue
			If (A_LoopRegName = "PATH")
				Path .= Value . ";" 
			Else If (A_LoopRegName = "PATHEXT")
				PathExt .= Value . ";"
			Else 
				EnvSet, %A_LoopRegName%, %Value%
		}
	}
	EnvSet, PATH, %Path%
	EnvSet, PATHEXT, %PathExt%
}
Also if error occured while expanding string, function continues with next environment variable.