Jump to content

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

GetEnv: reclaim AHk's variables


  • Please log in to reply
3 replies to this topic
shimanov
  • Members
  • 610 posts
  • Last active: Jul 18 2006 08:35 PM
  • Joined: 25 Sep 2005
The function, GetEnv, permits clearing and restoring all environment variables, and retrieving individual variables. This approach avoids any side-effects of using assumed empty variables with names, which coincide with defined environment variables.

The system calls employed are available with all versions of Windows.

syntax:
* GetEnv( "", "clear" ) ; clear environment variables
* GetEnv( "", "restore" ) ; restore environment variables
* GetEnv( "PATH" ) ; retrieve value assigned to environment variable named "PATH" (case insensitive)
known issues:
* it is advisable to restore environment variables before using Run commands
* it is necessary to restore environment variables before running the Reload command
demonstration (tested with Windows XP SP2):
Random, rv, 0, 0xFFFFFFFF

RunWait, %comspec% /c set > env%rv%.txt
	FileRead, env_before, env%rv%.txt 
	MsgBox,
		( LTrim
			< env_before >`n
			%env_before%
			
			< AHk: env variables >`n
			COMPUTERNAME = %COMPUTERNAME%
			*COMPSPEC = %COMSPEC%
			PATH = %PATH%
			*PROMPT = %PROMPT%
			*PATHEXT = %PATHEXT%
			TEMP = %TEMP%
			TMP = %TMP%
		)
GetEnv( "", "clear" )

FileDelete, env%rv%.txt

RunWait, c:\windows\system32\cmd /c set > env%rv%.txt
	FileRead, env_empty, env%rv%.txt 
	MsgBox, %
		( Join
			"< env_empty >`n"
			env_empty
			"`n`n< AHk: env variables >"
			"`nCOMPUTERNAME = " COMPUTERNAME
			"`n*COMPSPEC = " COMSPEC
			"`nPATH = " PATH
			"`n*PATHEXT = " PATHEXT
			"`n*PROMPT = " PROMPT
			"`nTEMP = " TEMP
			"`nTMP = " TMP
			"`n`n< GetEnv: variables >`n"
			"`nCOMPUTERNAME = " GetEnv( "COMPUTERNAME" )
			"`n*COMPSPEC = " GetEnv( "COMSPEC" )
			"`nPATH = " GetEnv( "PATH" )
			"`n*PATHEXT = " GetEnv( "PATHEXT" )
			"`n*PROMPT = " GetEnv( "PROMPT" )
			"`nTEMP = " GetEnv( "TEMP" )
			"`nTMP = " GetEnv( "TMP" )
		)

GetEnv( "", "restore" )
RunWait, %comspec% /c set > env%rv%.txt
	FileRead, env_after, env%rv%.txt 
	MsgBox,
		( LTrim
			< env_after >`n
			%env_after%
			
			< AHk: env variables >`n
			COMPUTERNAME = %COMPUTERNAME%
			*COMPSPEC = %COMSPEC%
			PATH = %PATH%
			*PATHEXT = %PATHEXT%
			*PROMPT = %PROMPT%
			TEMP = %TEMP%
			TMP = %TMP%
		)

FileDelete, env%rv%.txt

if ( env_before = env_after )
	MsgBox, Environment restored successfully!
else
	MsgBox, Environment restoration failed!
return

function:
GetEnv( p_name, p_mode="" )
{
	static	table, fields
	
	if ( p_mode = "clear" )
	{
		table = |
		fields = |
	
		pTable := DllCall( "GetEnvironmentStrings" )
		if ( ErrorLevel or !pTable )
		{
			MsgBox, [GetEnv] failed: EL = %ErrorLevel%
			return
		}
		
		index = 1
		offset = 0
		loop,
		{
			len := ReadString( record, pTable, offset, 32767 )
			
			if ( len = 0 )
				break
			else if ( Asc( record ) != 61 )
			{
				StringSplit, field, record, =
			
				DllCall( "SetEnvironmentVariable", "str", field1, "uint", 0 )
			
				table := table record
				fields := fields "|" index "," StrLen( field1 ) "," StrLen( field2 )
				
				index += len
			}

			offset += len+1
		}
		
		StringTrimLeft, table, table, 1
		StringTrimLeft, fields, fields, 2

		DllCall( "FreeEnvironmentStrings", "uint", pTable )
		
		return
	}
	else if ( p_mode = "restore" )
	{
		loop, parse, fields, |
		{
			StringSplit, field, A_LoopField, `,
				
			StringMid, name, table, field1, field2
			StringMid, value, table, field1+field2+1, field3
				
			EnvSet, %name%, %value%
		}
		
		return
	}
	
	old_StringCaseSense := A_StringCaseSense
	StringCaseSense, off
	
	loop, parse, fields, |
	{
		StringSplit, field, A_LoopField, `,
		
		StringMid, name, table, field1, field2
		if ( name = p_name )
		{
			StringMid, value, table, field1+field2+1, field3
			break
		}
	}

	StringCaseSense, %old_StringCaseSense%
	
	return, value
}

ReadString( byref r_string, p_address, p_offset, p_size )
{
	r_string = |
	
	p_address += p_offset

	loop, %p_size%
	{
		if ( *p_address = 0 )
			break
		
		r_string := r_string Chr( *p_address )
		
		p_address++
	}
	
	StringTrimLeft, r_string, r_string, 1
		
	return, StrLen( r_string )
}


Chris
  • Administrators
  • 10727 posts
  • Last active:
  • Joined: 02 Mar 2004
Nice solution. Hopefully this limitation in the program will get resolved relatively soon.

PhiLho
  • Moderators
  • 6850 posts
  • Last active: Jan 02 2012 10:09 PM
  • Joined: 27 Dec 2005
How?
I would suggest a directive to prefix or suffix all environment variables with user chosen string. Optional, of course, to preserve backward compatibility.
I find this cleaner that forcefully prefix all user's global variables with something.

Chris
  • Administrators
  • 10727 posts
  • Last active:
  • Joined: 02 Mar 2004
As discussed in another topic, the #v1.1 directive will probably turn off automatic retrieval of environment variables. Then there will probably be another option that can override it to turn them back on. That very same option will probably get implemented sooner than #v1.1 so that the environment variable issue can be solved sooner.

Edit: To solve this, v1.0.43.08 introduces the #NoEnv directive, which is recommended for all new scripts.