Enumerating Environment variables

topic: 

One of the way to enumerate the Environment Variables is by accessing _environ global variable. The GetEnvironmentStrings function provides another way by returning a pointer to the environment block of the calling process. It can also be done using WMI Win32_Environment

Class.

The Windows API support class

is used to handle Windows API structures.

$SAMPLECODE$

Retrieve the list of Environment Variables at the time when Windows started. A handy Array Browser

utility that displays an array content is used in above code to see the result list.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

#DEFINE ccEnvVarName 1
#DEFINE ccEnvVarValue 2

DECLARE Long GetModuleHandle IN win32api String
DECLARE Long GetProcAddress IN win32api Long, String

loWas = NEWOBJECT("WinApiSupport", "WinApiSupport.fxp")

* Get pointer to the process environment
lnHandle = GetModuleHandle("msvcrt.dll")
lnPtr = GetProcAddress(lnHandle,"_environ")
* It is a pointer to an array of pointers to the environment variables strings
lnPtr = loWas.Long2NumFromBuffer(lnPtr)

lnInd = 0
DO WHILE .T.
	* Pointer to the next environment variable string
	lnAddress = loWas.Long2NumFromBuffer(lnPtr + lnInd * 4)
	IF lnAddress = 0 
		EXIT
	ENDIF

	* Increment it now so we can use it to resize the array
	lnInd = lnInd + 1
	DIMENSION laEnvVars[lnInd, 2]
	* Copy string to a memory variable
	lcEnvItem = loWas.StrZCopy(lnAddress)
	* Extract variable name
	laEnvVars[m.lnInd, ccEnvVarName] = GETWORDNUM(lcEnvItem,1,"=")
	* Get variable value
	laEnvVars[m.lnInd, ccEnvVarValue] = GETWORDNUM(lcEnvItem,2,"=")
	*laEnvVars[m.lnInd, ccEnvVarValue] = GETENV(laEnvVars[m.lnInd, ccEnvVarName])
ENDDO

* Displays the array content in a Browser
= browarr(@laEnvVars)

Retrieve the list of Environment Variables for the current process at the time when application started. The list can be changed by application using SetEnvironmentVariable function.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

#DEFINE ccEnvVarName 1
#DEFINE ccEnvVarValue 2

DECLARE Long GetEnvironmentStrings IN WIN32API 
DECLARE Long FreeEnvironmentStrings IN WIN32API Long lpszEnvironmentBlock

loWas = NEWOBJECT("WinApiSupport", "WinApiSupport.fxp")

* Get current process environment variables block
lnPtr = GetEnvironmentStrings()

lnAddress = lnPtr 
lnInd = 1
DO WHILE .T.
	* Copy string to a memory variable
	lcEnvItem = loWas.StrZCopy(lnAddress )
	IF EMPTY(lcEnvItem)
		EXIT
	ENDIF
	
	DIMENSION laEnvVars[lnInd, 2]
	* Extract variable name
	laEnvVars[m.lnInd, ccEnvVarName] = GETWORDNUM(lcEnvItem,1,"=")
	* Get variable value
	laEnvVars[m.lnInd, ccEnvVarValue] = GETWORDNUM(lcEnvItem,2,"=")
	*laEnvVars[m.lnInd, ccEnvVarValue] = GETENV(laEnvVars[m.lnInd, ccEnvVarName])

	* Next item
	lnAddress = lnAddress + LEN(lcEnvItem) + 1
	* Increment 
	lnInd = lnInd + 1
	
ENDDO

* Release the environment variables block
= FreeEnvironmentStrings(lnPtr)

* Displays the array content in a Browser
= browarr(@laEnvVars)

Creating, Setting, Deleting and Reading of Environment variables

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

CLEAR

* Create/Set/Delete a variable
DECLARE Long SetEnvironmentVariable IN WIN32API String lpName, String lpValue
* Add one
= SetEnvironmentVariable("MyVar01", "MyVal 01")
* Add one more
= SetEnvironmentVariable("MyVar02", "MyVal 02")
* Delete one
= SetEnvironmentVariable("MyVar02", Null)

? GetEnvVar("MyVar01")
? GetEnvVar("MyVar02")
? GetEnvVar("OS")

RETURN

* The function returns value of an environment variable of the current process including the ones created with SetEnvironmentVariable. 
*  The GETENV() function does not return values for the later.
FUNCTION GetEnvVar(tnVarName)
LOCAL lcBuffer, lnLen, lcVarVal
	* Read a variable
	DECLARE Long GetEnvironmentVariable IN WIN32API String lpName, String @lpBuffer, Long nSize
	lcBuffer = SPACE(4096)
	lnLen = GetEnvironmentVariable(tnVarName, @lcBuffer, LEN(lcBuffer))
	lcVarVal = ""
	IF lnLen > 0
		lcVarVal = LEFT(lcBuffer, lnLen)
	ENDIF
	RETURN lcVarVal
ENDFUNC

Retrieve the list of Environment Variables using WMI.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16

SET MEMOWIDTH TO 1024
CLEAR

LOCAL loWMI, loEnvCol, loEnvVar
loLocator	= CREATEOBJECT('WbemScripting.SWbemLocator')
loWMI		= loLocator.ConnectServer()
loEnvCol	= loWMI.ExecQuery("select * from Win32_Environment")

FOR EACH  loEnvVar in loEnvCol
	WITH loEnvVar
		? .Name, .SystemVariable AT 25, .UserName, .VariableValue
	ENDWITH 
ENDFOR 

Comments

There is no function: loWas.StrZCopy(lnAddress )
in the WinAPIsupport code.
Perhaps you meant: loWas.StrZFromBuffer ??

I forgot to update the WinAPIsupport class code. Sorry about that. The missing code is below. You can add it to the class or you can copy the whole updated class.

1
2
3
4
5
6
7
8
	* Retrieve zero-terminated string 
	FUNCTION StrZCopy(tnPointer)
		LOCAL lcStr, lnStrPointer
		lcStr = SPACE(4096)
		lstrcpy(@lcStr, tnPointer)
		RETURN LEFT(lcStr, AT(CHR(0),lcStr)-1)
	ENDFUNC

Thank you!
Works Great.