It has always been possible to obtain the value of a system or user-set environment variable using dosparam@, but is it possible to SET environment variables within a Clearwin program?
Setting environment variables within Clearwin code
In theory all API functions are available and SetEnvironmentVariable is already provided in win32api.ins.
Yes but SetEnvironmentVariable only sets a variable within same process
I wanted to set a permanent one. Is the only way to use RegGreateKeyEx to create a new key in HKEY_CURRENT_USER Environment ?
You could try changing the registry via the key HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment or it will probably be easier launch cmd.exe from your program and call SETX. Maybe use StartProcess@ or CISSUE@ etc.
with HKEY_CURRENT_USER,'Environment' I think that you just need to add a value, and changing just the user variable would do
The code below doesnt work (always returns 0). Is there an obvious changeto make this work?
Program main
character(len=255) :: var,buf
var = 'TEMP1'
buf = 'anything'
call Setenv(var,buf)
end
C C----------------------------------------------------------------------C C subroutine SetEnv(var,val)
include <windows.ins>
character(*) :: var,val
integer :: handle
integer :: type,l1,i
type = 0
l1 = len_trim(var)
var(l1+1:l1+1) = char(0)
l1 = len_trim(val)
val(l1+1:l1+1) = char(0)
l1 = l1 +1
i = 0
if(RegOpenKeyEx(HKEY_CURRENT_USER,'Environment',0,
& KEY_READ,handle) /= ERROR_SUCCESS) return
if(RegSetValueEx(handle,var,type,REG_SZ,val,l1)
& == ERROR_SUCCESS) i = 1
write(*,*) i
i = RegCloseKey(handle)
end
What do the updated strings var and val look like in subroutine SetEnv, and what are their lengths ?
I think that : character() :: var,val should possibly be : character(*) :: var,val
John
The Win API functions are supposed to need null terminated strings. I've also tried it without the char(0) and the result is still the same
I think character() is shorthand for character(len=)
While the system command setx works fine on Win 10, it must be a relatively new command. It is unknown in Win XP and I want the program to work on as many versions of Windows as possible.
'I think character() is shorthand for character(len=) '
It's not. character() defines a character1 array(*) of unknown length, which would not work.
I don't think that character(*) var implies a character array var
placing a statement after this
write(*,'(a)') var(1)
results in a compilation error because var is not declared as an array
In any case changing it to character(len=*) var, val results in the same failure
Inside SetEnv, both variables look just as they should if printed out.
The main thing is the you need to use KEY_SET_VALUE. Here is the code assuming that 'Environment' is the correct key to use.
program main
character(len=255) :: var,buf
var = 'TMP_FILE'
buf = 'C:\temp\debug.txt'
call SetEnv(var,buf)
end
subroutine SetEnv(var,val)
character*(*) :: var,val
integer, parameter :: KEY_SET_VALUE = Z'2'
integer(7), parameter :: HKEY_CURRENT_USER = Z'80000001'
integer, parameter :: REG_SZ = Z'1'
stdcall RegOpenKeyEx 'RegOpenKeyExA' (VAL,INSTRING,VAL,VAL,REF):integer
stdcall RegSetValueEx 'RegSetValueExA' (VAL,INSTRING,VAL,VAL,INSTRING,VAL):integer
stdcall RegCloseKey 'RegCloseKey' (VAL):integer
integer ret,len
integer(7) key_handle
character(len=80)::subkey
subkey = 'Environment'
len = len_trim(val)+1
ret = RegOpenKeyEx(HKEY_CURRENT_USER,subkey,0,KEY_SET_VALUE,key_handle)
ret = RegSetValueEx(key_handle,var,0,REG_SZ,val,len)
ret = RegCloseKey(key_handle)
end
'I think character() is shorthand for character(len=) '
You are correct, the following 2 statements are the same character() :: aa character(*) :: bb
However, the following 2 statements are different character :: aa() character :: bb(*)
I have only ever used the bb*() types for declaring an argument of unknown length. I always use charactern to define the length, which is a non-standard extension.
I find it confusing that the following 2 statements are different character() :: aa character :: aa()
while the following 2 statements imply the same character*() :: bb character :: bb(*)
Shows there is always more to learn.
Thanks Paul
It seems to work perfectly on every Win installation I tried. But it seems that this way of setting environment variables requires a Windows reboot for them to be available for other processes (which is why I guess so many installation programs require just that)
Maybe you need to set HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment as well.
I think that is where the system wide environment variables are stored. I presume a user would have to have administrator privileges to make changes there?
In any case, I did edit one entry there, for one of my own system variables using regedit and saved the change. It still seems to need a Windows reboot to make the change available to a user.
After editing and saving the change, I opened a new DOS box and typed 'set' to see the available variables and the change had not been updated.
I just noticed that if an environment variable is set by using Win API function SetEnvironmentVariable in a program and then that program spawns another program by start_process@, then the value of the environment variable is also available for the spawned process.
Can this behaviour be relied on for all versions of Windows? (I checked it on Win 10). It is very useful
It is what I would expect.