GetEnv Environment Variable question
I received a question:
Can you explain me the internal behavior of VFP's GetEnv() function. It's seems to me that VFP during startup make a copy of environment block and GetEnv() works with this internal buffer. So using WinAPI's SetEnvironmentVariable and GetEnvironmentVariable do not change behavior of GetEnv() function. And what about behavior of other VFP functions and other internals of VFP - is it safe to change process's environment block or ...
The Fox GetEnv function is just a wrapper around the C Runtime library getenv function
When a process starts, a copy of the environment is put in the Program Segment Prefix. This copy is then used for any child processes. This is the way it’s been ever since the DOS days. I remember examining the PSP in the 16 bit command line debugger: type DEBUG in a Windows Command Prompt and it’s still there!
From the documentation of _putenv:
_putenv and _wputenv affect only the environment that is local to the current process; you cannot use them to modify the command-level environment. That is, these functions operate only on data structures accessible to the run-time library and not on the environment "segment" created for a process by the operating system. When the current process terminates, the environment reverts to the level of the calling process (in most cases, the operating-system level). However, the modified environment can be passed to any new processes created by _spawn, _exec, or system, and these new processes get any new items added by _putenv and _wputenv
Thus changing the environment variable only affects the current process and child processes.
The code below creates an environment variable called “test” and sets it to the current time.
Switch to another process and see what happens to the environment variable.
Instantiate an EXE server, have it check the variable
Instantiate a DLL server and have it check the variable
CLEAR ALL
CLEAR
oEnv=CREATEOBJECT("environ")
?"ComputerName=",oEnv.GetVar("ComputerName")
?"Test=",oEnv.GetVar("test")
oEnv.SetVar("test",TRANSFORM(DATETIME()))
?"Test=",oEnv.GetVar("test")
!set > d:\t.txt
TYPE d:\t.txt
DEFINE CLASS Environ as Custom
PROCEDURE init
DECLARE integer GetEnvironmentVariable IN WIN32API string, string @, integer dwSize
DECLARE integer SetEnvironmentVariable IN WIN32API string lpName, string lpValue
PROCEDURE GetVar(cVar as string)
LOCAL nLen,cstr
cstr=SPACE(200)
nLen=GetEnvironmentVariable(cVar,@cstr, LEN(cstr))
IF nLen>0
cstr=LEFT(cstr,nLen-1)
ELSE
cstr=""
ENDIF
RETURN cstr
PROCEDURE SetVar(cVar as string, cValue as String)
SetEnvironmentVariable(cVar, cValue)
return
ENDDEFINE
Comments
- Anonymous
December 14, 2005
I suppose that nowaday this behavior is useless and odd: at the DOS time the enviroment was only one common to all process and the C runtime library added this kind of workaroud (PSP) to avoid global modification.
In Win32 the Get/SetEnvironmentVariable API protect each process from the others because they work on the process environment.
I think that would be better if VFP internally use the regular GetEnvironmentVariable API: in my programs for this 'problem' I didn't use GetEnv bat a couple of API wrapper function xGetEnv() and xSetEnv().
And what about the GetCommandLine() API? Is it the same problem? - Anonymous
April 11, 2006
For anyone who really does need to permanently change the environment variables, this page at MSDN explains it: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/environment_variables.asp
Basically, just edit the registry at HKEY_LOCAL_MACHINESystemCurrentControlSetControlSession ManagerEnvironment