Silverfrost Forums

Welcome to our forums

Setting environment variables within Clearwin code

11 Jun 2016 3:50 #17628

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?

11 Jun 2016 4:01 #17629

In theory all API functions are available and SetEnvironmentVariable is already provided in win32api.ins.

11 Jun 2016 10:38 #17631

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 ?

12 Jun 2016 6:18 #17632

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.

12 Jun 2016 8:50 #17633

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,
 &amp;                 KEY_READ,handle)  /= ERROR_SUCCESS) return

  if(RegSetValueEx(handle,var,type,REG_SZ,val,l1)
 &amp; == ERROR_SUCCESS) i = 1
  write(*,*) i
  i = RegCloseKey(handle)
  end
12 Jun 2016 9:17 #17634

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

12 Jun 2016 9:46 #17636

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.

12 Jun 2016 2:15 #17638

'I think character() is shorthand for character(len=) '

It's not. character() defines a character1 array(*) of unknown length, which would not work.

12 Jun 2016 3:32 #17639

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.

13 Jun 2016 5:18 #17643

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      
       
13 Jun 2016 8:35 (Edited: 13 Jun 2016 8:37) #17644

'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.

13 Jun 2016 8:37 #17645

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)

13 Jun 2016 9:32 #17646

Maybe you need to set HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment as well.

13 Jun 2016 12:57 #17650

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.

14 Jun 2016 10:29 #17661

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

14 Jun 2016 11:03 #17662

It is what I would expect.

Please login to reply.