Tuesday, May 3, 2011

How can I change Windows shell (cmd.exe) environment variables from C++?

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.

From stackoverflow
  • 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.

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

    Steve Rowe : I don't want to change the global settings, just the ones in the calling shell.
    Michael : Shell in this case is explorer. cmd.exe doesn't respond to WM_SETTINGCHANGE messages.
  • 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
  • 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.

    Steve Rowe : Thanks. I'll give that a try.


Post a Comment