View previous topic :: View next topic |
Author |
Message |
ljfarrugia
Joined: 06 Jun 2016 Posts: 35
|
Posted: Sat Jun 11, 2016 4:50 pm Post subject: Setting environment variables within Clearwin code |
|
|
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? |
|
Back to top |
|
|
PaulLaidler Site Admin
Joined: 21 Feb 2005 Posts: 7934 Location: Salford, UK
|
Posted: Sat Jun 11, 2016 5:01 pm Post subject: |
|
|
In theory all API functions are available and SetEnvironmentVariable is already provided in win32api.ins. |
|
Back to top |
|
|
ljfarrugia
Joined: 06 Jun 2016 Posts: 35
|
Posted: Sat Jun 11, 2016 11:38 pm Post subject: |
|
|
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 ? |
|
Back to top |
|
|
PaulLaidler Site Admin
Joined: 21 Feb 2005 Posts: 7934 Location: Salford, UK
|
Posted: Sun Jun 12, 2016 7:18 am Post subject: |
|
|
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. |
|
Back to top |
|
|
ljfarrugia
Joined: 06 Jun 2016 Posts: 35
|
Posted: Sun Jun 12, 2016 9:50 am Post subject: |
|
|
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 |
|
Back to top |
|
|
JohnCampbell
Joined: 16 Feb 2006 Posts: 2560 Location: Sydney
|
Posted: Sun Jun 12, 2016 10:17 am Post subject: |
|
|
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 |
|
Back to top |
|
|
ljfarrugia
Joined: 06 Jun 2016 Posts: 35
|
Posted: Sun Jun 12, 2016 10:46 am Post subject: |
|
|
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. |
|
Back to top |
|
|
JohnCampbell
Joined: 16 Feb 2006 Posts: 2560 Location: Sydney
|
Posted: Sun Jun 12, 2016 3:15 pm Post subject: |
|
|
"I think character(*) is shorthand for character(len=*) "
It's not. character(*) defines a character*1 array(*) of unknown length, which would not work. |
|
Back to top |
|
|
ljfarrugia
Joined: 06 Jun 2016 Posts: 35
|
Posted: Sun Jun 12, 2016 4:32 pm Post subject: |
|
|
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. |
|
Back to top |
|
|
PaulLaidler Site Admin
Joined: 21 Feb 2005 Posts: 7934 Location: Salford, UK
|
Posted: Mon Jun 13, 2016 6:18 am Post subject: |
|
|
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.
Code: | 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
|
|
|
Back to top |
|
|
JohnCampbell
Joined: 16 Feb 2006 Posts: 2560 Location: Sydney
|
Posted: Mon Jun 13, 2016 9:35 am Post subject: |
|
|
"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 character*n 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.
Last edited by JohnCampbell on Mon Jun 13, 2016 9:37 am; edited 1 time in total |
|
Back to top |
|
|
ljfarrugia
Joined: 06 Jun 2016 Posts: 35
|
Posted: Mon Jun 13, 2016 9:37 am Post subject: |
|
|
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) |
|
Back to top |
|
|
PaulLaidler Site Admin
Joined: 21 Feb 2005 Posts: 7934 Location: Salford, UK
|
Posted: Mon Jun 13, 2016 10:32 am Post subject: |
|
|
Maybe you need to set HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment as well. |
|
Back to top |
|
|
ljfarrugia
Joined: 06 Jun 2016 Posts: 35
|
Posted: Mon Jun 13, 2016 1:57 pm Post subject: |
|
|
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. |
|
Back to top |
|
|
ljfarrugia
Joined: 06 Jun 2016 Posts: 35
|
Posted: Tue Jun 14, 2016 11:29 am Post subject: |
|
|
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 |
|
Back to top |
|
|
|