What is the difference between a Registry Key & an Environment Variable?
I think Environment Variables are only something found in windows OS? And I hear thats its very easy to change these so its not good to trust them? Are Registry Keys just as easy to change?
Are Registry keys stored in the kernal?
My most important question is: I know that the environment variables let me know the path to %APPDATA, the current users name, the path to program files, the version of Windows OS running, etc. BUT do the Registry keys also contain this kind of data - can I also find out this information by looking at the registry keys?
Both are used to configure programs. The biggest difference is that environment variables are stored in memory, registry keys are stored in a file. Which explains many of their properties:
Environment variable values are lost as soon as the process that writes them terminates.
A process cannot update the environment variable values of another process. With one important exception: the environment for a process is created by the process that starts it. The lpEnvironment argument of CreateProcess(). This is how a parent process configures the child processes it starts.
The space for storing environment variables is severely limited, 64KB max.
Environment variables do not have user scope like registry keys do, they'll have the same value for any user, unless the parent process takes care of it explicitly.
Environment variable values cannot be secured.
Accessing environment variables is fast. With the caveat that searching for a variable is an O(n) operation since they don't have a hierarchical organization nor an index. The limited environment size makes that unnecessary. Windows heavily optimizes registry key access however.
Another important difference:
Environment variables are loaded to the process when it starts. So if you change them after the process is running, the process won't see that.
And about your other question:
User Variables: HKEY_CURRENT_USER\Environment
System Variables: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment
An article about the default system variables:
http://vlaurie.com/computers2/Articles/environment.htm
What is the difference between a Registry Key & an Environment
Variable?
Registry Keys are stored permanently in special file. Environment Variables are stored in memory of the process, but some of them (System Environment Variables) are loaded from registry on process start.
Related
I need to set a local environment variable for current user and it shoukd be visible to other processes like a new command prompt. I need it for windows. I have tried options like putenv and editing the registry from C++ code but the new cmd prompt see the old values. Primarily i need to edit PATH variable along with few custom env variables. Will appreciate if i can get a working sample code.
Please note that the environment variable need to persist past program execution.
My requirement is for windows. I even tried running setx from C++ code and it works fine but for PATH variable it trims it down to 1024 character and i lose the update. Is there a workaround to this?
IF my wording looks confusing about the requirement. I need exactly same behavior as if i am using setx.
Thanks in advance.
If you start Cmd.exe from your process you can control its environment. The environment variables are inherited from the parent process. They can also be overridden when you call CreateProcess.
If you change the users/system environment configuration in the registry(HKCU\Environment/HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment) and log off/reboot then the first process will use these new defaults.
If you update the registry you can tell other applications to refresh their environments without logging off by broadcasting a message:
BroadcastSystemMessage(0, 0, WM_SETTINGCHANGE, 0, (LPARAM)TEXT("Environment"));
In reality it is only Explorer.exe that reacts to this message but that is enough to affect new applications started from the taskbar/start menu.
The setx command is actually an executable that sets values in the registry. If you are looking to simulate the behavior where you can set an environment variable that will last longer than the current process you will need to write it to the HKCU\Environment key. The HKCU is for the the current user and can be written to without elevated permissions.
Use RegEdit.exe or reg.exe query HKCU\Environment to view the current settings. From C/C++ you can use the Registry functions. If you can, I recommend using the ATL CRegKey class as it follows RAII and ensures handles are properly cleaned up.
I know that getenv() returns a value of specified environment variable of the current user, but my code requires root privileges so getenv() would only use the sudo environment variables. I also know that SUDO_USER tells which user is invoking sudo, which is the user environment I want use for getenv().
char* gnome_env_var = getenv("GDMSESSION"); //returns null as not found in sudo env
char* usr = getenv("SUDO_USER");
Is there a way I can get the value of an environment variable for the logged in user, not the sudo environment?
EDIT
Okay, so what I'm hearing is that the set of environment variables are unique to each process, not user and using sudo to invoke a process with root privileges calls execve which can create an entirely new set of environment variables for that process. So to rephrase, is there a way besides messing with the sudoers file, and within the current process, of finding the calling process's environment variables?
I particularly need the GDMSession environment variable.
getenv doesn't tell you about the environment variables of the current user, but the current process. Users are free to have as many environments as they want(and can create processes), for example with the export shell built-in. In every call to execve, the calling program is free to create an entirely new environment for the executed process.
Therefore, there is no way to get the environment variables of the user, or even those of the process executing sudo. Why do you want that anyways?
You can, however, configure sudo to keep some or all environment variables, via the keep_env and reset_env directives in /etc/sudoers.
There isn't a "user environment." Every process has its own copy of the environment variables. They don't even automatically inherit -- that they appear to is an illusion maintained by the shell and the C library. It is more accurate to think of them as a second set of command line arguments to every program.
So before we can answer your question, you need to clear up what you mean! There are possibilities - none of them are elegant, mind, but they do exist - but they depend crucially on which environment variable you want to get at in which process's state and why.
I have a program I am making in C++ WinAPI & I need to determine the version of Windows the user is running & the path to Program Files.
I know I can determine this by looking at the Windows Environment Variables or the Registry Keys(can I get the path to program files from the Registry?) BUT which is better practice?
I know Environment Variables can be changed easily so its not good to trust them, but can the registry keys be changed as easily - which is better to trust?
Is it better practice to go to the Registry for this information or the Environment Variables? Which would you do?
You should use the GetVersionEx Function API instead. It's better than the environment variable and the registry.
For the path to program files, there is also an API: SHGetFolderPath Function
Is there a way to set the global windows path environment variable programmatically (C++)?
As far as I can see, putenv sets it only for the current application.
Changing directly in the registry (HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment) is also an option though I would prefer API methods if there are?
MSDN Says:
Calling SetEnvironmentVariable has no
effect on the system environment
variables. To programmatically add or
modify system environment variables,
add them to the
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session
Manager\Environment registry key, then
broadcast a WM_SETTINGCHANGE message
with lParam set to the string
"Environment". This allows
applications, such as the shell, to
pick up your updates. Note that the
values of the environment variables
listed in this key are limited to 1024
characters.
As was pointed out earlier, to change the PATH at the machine level just change this registry entry:
HLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment
But you can also set the PATH at the user level by changing this registry entry:
HKEY_CURRENT_USER\Environment\Path
And you can also set the PATH at the application level by adding the application\Path details to this registry entry:
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\
There is no API - changing the registry is the way to do it. The changed value will be used for processes starting after the change was made.
Also: Notice that running applications must actively process the settings changed message and many (most?) do not do so.
If you want to do it through the registry, you might want to look at the source code of this program.
Microsoft also provides a small command line utility called setx with its resource toolkits, which will let you do this. By the way, the regular set command just lets you define local environment variables I think.
Yes You are correct.
You also need to effect these settings without logging off
Send Message of borad casting to all windows SETTINGCHANGE for the parameter (LPARAM) "Environment" with SMTO_ABORTIFHUNG for some milliseconds(5000) using SendMessageTimeout API.
This is what setX.exe provided with resource Kit does.
I would like to write a program that sets an environment variable in an instance of the shell (cmd.exe) it was called from. The idea is that I could store some state in this variable and then use it again on a subsequent call.
I know there are commands like SetEnvironmentVariable, but my understanding is that those only change the variable for the current process and won't modify the calling shell's variables.
Specifically what I would like to be able to do is create a command that can bounce between two directories. Pushd/Popd can go to a directory and back, but don't have a way of returning a 2nd time to the originally pushed directory.
MSDN states the following:
Calling SetEnvironmentVariable has no
effect on the system environment
variables. To programmatically add or
modify system environment variables,
add them to the
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session
Manager\Environment registry key, then
broadcast a WM_SETTINGCHANGE message
with lParam set to the string
"Environment". This allows
applications, such as the shell, to
pick up your updates. Note that the
values of the environment variables
listed in this key are limited to 1024
characters.
Considering that there are two levels of environment - System and Process - changing those in the shell would constitute changing the environment of another process. I don't believe that this is possible.
A common techniques is the write an env file, that is then "call"ed from the script.
del env.var
foo.exe ## writes to env.var
call env.var
In Windows when one process creates another, it can simply let the child inherit the current environment strings, or it can give the new child process a modified, or even completely new environment.
See the full info for the CreateProccess() win32 API
There is no supported way for a child process to reach back to the parent process and change the parent's environment.
That being said, with CMD scripts and PowerShell, the parent command shell can take output from the child process and update its own environment. This is a common technique.
personly, I don't like any kind of complex CMD scripts - they are a bitch to write an debug. You may want to do this in PowerShell - there is a learning curve to be sure, but it is much richer.
There is a way...
Just inject your code into parent process and call SetEnvironmentVariableA inside
cmd's process memory. After injecting just free the allocated memory.