Easy for you, hard for me

Posted on 1997-12-18
Last Modified: 2013-12-03
Hi wizard of knowledge,

when creating a new process under Windows NT using CreateProcess and specifing NULL for the environment block (lpEnvironment), the child application will inherit the environment of the calling application. Alternately, I could specify a pointer to a another environent block.

My problem is, that the environment of an application does not change, even if a user sets a new environment in the control panel. So how can I be notified when the environment changes (or alternatly: how can I obtain the NEW USER-CHANGED environment and pass it to the child process?). I heard that "GetEnvironmentStrings" does always return the environment as it was, when the application started (it will not change, when the user modifies the environment using the control panel).

Hmm, I hope anyone understands, what I am trying to say..
Sorry for only giving 70 points, but that is all I have :-(

Question by:Mirko

Expert Comment

ID: 1409622
By default, a child process inherits the environment variables of its parent process. However, you can specify a different environment for the child process by creating a new environment block and passing a pointer to it as a parameter to the CreateProcess function.

The GetEnvironmentStrings function returns a pointer to the environment block of the calling process. This should be treated as a read-only block; do not modify it directly. Instead, use the SetEnvironmentVariable function to change an environment variable. When you are finished with the environment block obtained from GetEnvironmentStrings, call the FreeEnvironmentStrings function to free the block.

The GetEnvironmentVariable function determines whether a specified variable is defined in the environment of the calling process, and, if so, what its value is.

For more information, there is the examples of Changing Environment Variables.
Changing Environment Variables

Each process has an environment block associated with it. The environment block consists of a null-terminated block of null-terminated strings (meaning there are two null bytes at the end of the block), where each string is in the form:


All strings in the environment block must be sorted alphabetically by name. Because the equal sign is a separator, it must not be used in the name of an environment variable.

By default, a child process inherits a copy of the environment block of the parent process. The following example demonstrates how to create a new environment block to pass to a child process.

LPTSTR lpszCurrentVariable;
BOOL fSuccess;
// Copy environment strings into an environment block.
lpszCurrentVariable = tchNewEnv;
if (lstrcpy(lpszCurrentVariable, "OperatingSystem=Windows") == NULL)
   ErrorExit("lstrcpy failed");
lpszCurrentVariable += lstrlen(lpszCurrentVariable) + 1;
if (lstrcpy(lpszCurrentVariable, "API=Win32") == NULL)
   ErrorExit("lstrcpy failed");
// Terminate the block with a NULL byte.
lpszCurrentVariable += lstrlen(lpszCurrentVariable) + 1;
*lpszCurrentVariable = '\0';
// Create the child process, specifying a new environment block.
fSuccess = CreateProcess(NULL, "childenv", NULL, NULL, TRUE, 0,
   (LPVOID) tchNewEnv,        // new environment block
   NULL, &siStartInfo, &piProcInfo);
if (! fSuccess)
    ErrorExit("CreateProcess failed");

If you want the child process to inherit most of the parent’s environment with only a few changes, save the current values, make changes for the child process to inherit, create the child process, and then restore the saved values, as shown following.

LPTSTR lpszOldValue;
BOOL fSuccess;
// lpszOldValue gets current value of "varname", or NULL if "varname"
// environment variable does not exist. Set "varname" to new value,
// create child process, then use SetEnvironmentVariable to restore
// original value of "varname". If lpszOldValue is NULL, the "varname"
// variable will be deleted.
lpszOldValue = ((GetEnvironmentVariable("varname",
    tchBuf, BUFSIZE) > 0) ? tchBuf : NULL);
// Set a value for the child process to inherit.
if (! SetEnvironmentVariable("varname", "newvalue"))
   ErrorExit("SetEnvironmentVariable failed");
// Create a child process.
fSuccess = CreateProcess(NULL, "childenv", NULL, NULL, TRUE, 0,
   NULL,     // inherit parent's environment
   NULL, &siStartInfo, &piProcInfo);
if (! fSuccess)
   ErrorExit("CreateProcess failed");
// Restore the parent's environment.
if (! SetEnvironmentVariable("varname", lpszOldValue))
   ErrorExit("SetEnvironmentVariable failed");

The following example, taken from a console process, prints the contents of the process’s environment block.

LPTSTR lpszVariable;
LPVOID lpvEnv;
// Get a pointer to the environment block.
lpvEnv = GetEnvironmentStrings();
// Variable strings are separated by NULL byte, and the block is
// terminated by a NULL byte.
for (lpszVariable = (LPTSTR) lpvEnv; *lpszVariable; lpszVariable++)
   while (*lpszVariable)

Author Comment

ID: 1409623
Tiutin, I think you misunderstood my question a little bit.
As you mentioned in your answer, GetEnvironmenStrings returns the environment block of the calling application. But this block is the environment block of the calling application when it started!

That means, when during the lifetime of your program, the user changes the system environment, you will never notice that; but I need to notice it...
LVL 22

Expert Comment

ID: 1409624
I'm not familiar with anything in the control panel that affects the environment settings.  The environment is DOs stuff and the control panel is windows stuff.  When the user changes the windows settings with the control panel all applications receive a message (WM_SETTINGSCHANGED or something like that)  But this has no relation to changing the DOS environment settings.
Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

LVL 11

Accepted Solution

alexo earned 70 total points
ID: 1409625
Under NT, the environment is saved in the registry.  Your process could check the registry directly to get the latest environment.

I'll send the key names in a moment.

Note: I don't think it will work with Win95.

LVL 11

Expert Comment

ID: 1409626

Correction: it may work with Win95.  Documentation say it's OK but I'm suspicious.

Anyway, The environment in NT is created from a composition of two registry entries.

One holds the "global" environment:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment

The other holds the "per user" environment:

Most of the entries in the environment that a process gets are taken from one of those keys.  However, certain values (like "path") are a composite of their values in both keys.

An application may send an WM_SETTINGCHANGE message (a.k.a WM_WININICHANGE) when it changes entries in the registry but, if I understand the docs correctly, it is not done automatically.

Also, keep in mind that when you change the environment from a console window, only that process environment is changed.

Also see KnowledgeBase article Q104011


Author Comment

ID: 1409627
Thanks. That's exactly, what I needed.
Merry Christmas and a happy new year!

Featured Post

Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

zlib is a free compression library (a DLL) on which the popular gzip utility is built.  In this article, we'll see how to use the zlib functions to compress and decompress data in memory; that is, without needing to use a temporary file.  We'll be c…
Whether you've completed a degree in computer sciences or you're a self-taught programmer, writing your first lines of code in the real world is always a challenge. Here are some of the most common pitfalls for new programmers.
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA.…
This video shows how to remove a single email address from the Outlook 2010 Auto Suggestion memory. NOTE: For Outlook 2016 and 2013 perform the exact same steps. Open a new email: Click the New email button in Outlook. Start typing the address: …

760 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

23 Experts available now in Live!

Get 1:1 Help Now