Creating the Windows child process with new environment variables
Compiler: Visual C++ Express Edition 2005
Compiled on Platform: Windows XP Pro SP2
Target platform: none, just for learning and fun
Header file: Standard and Windows
Additional library: Windows Platform SDK
Additional project setting: Set project to be compiled as C
Project -> your_project_name Properties -> Configuration Properties -> C/C++ -> Advanced -> Compiled As: Compiled as C Code (/TC)
Other info: non-CLR or unmanaged. Need to add netapi32.lib (netapi32.dll) to the project. Click the Project menu->Select the your_project_name Properties... sub menu->Expand the Configuration Properties folder on the left pane->Expand the Linker subfolder->Select the Input subfolder->Select the Additional Dependencies field on the right pane->Click the ... at the end of the field->Type in 'netapi32.lib' in the empty pane->Click the OK button->Click the OK button second time to close the project Properties dialog.
To do: Creating child process with new environment variables
To show: More on the Windows thread and process usage - creating and changing the environment variable for child process
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>
#define BUFSIZE 4096
int wmain(int argc, WCHAR **argv)
{
LPTSTR lpszCurrentVariable;
// Child process to be executed
WCHAR szAppName[]=L"\\\\?\\C:\\windows\\system32\\cmd.exe";
// WCHAR szAppName[]=L"\\\\?\\C:\\WINDOWS\\system32\\sol.exe";
STARTUPINFO si = {0};
PROCESS_INFORMATION pi = {0};
BOOL fSuccess;
DWORD Ret = 100;
LPTSTR lpszVariable;
LPWCH lpvEnv;
// Get the current process and thread IDs
wprintf(L"Parent process ID (wmain()) is %u\n", GetCurrentProcessId());
wprintf(L"Parent thread ID (wmain()) is %u\n", GetCurrentThreadId());
// Get a pointer to the environment block
lpvEnv = GetEnvironmentStrings();
// If the returned pointer is NULL, exit
if (lpvEnv == NULL)
{
wprintf(L"GetEnvironmentStrings() failed, error %d\n", GetLastError());
return 1;
}
else
wprintf(L"GetEnvironmentStrings() is OK!\n");
// Copy environment strings into an environment block
lpszCurrentVariable = lpvEnv;
// Frees a block of environment strings
if(FreeEnvironmentStrings(lpvEnv) != 0)
wprintf(L"\nFreeEnvironmentStrings() - a block of environment strings was freed!\n");
else
wprintf(L"\nFreeEnvironmentStrings() failed, error %u\n", GetLastError());
if (FAILED(StringCchCopy(lpszCurrentVariable, BUFSIZE, L"MyNewOwnEnvSetting=ver 2.0")))
{
wprintf(L"StringCchCopy() - String copy #1 failed\n");
return 1;
}
else
wprintf(L"StringCchCopy() - env variable #1 was copied successfully!\n");
lpszCurrentVariable += lstrlen(lpszCurrentVariable) + 1;
if (FAILED(StringCchCopy(lpszCurrentVariable, BUFSIZE, L"MyNewOwnVar=MyPath")))
{
wprintf(L"StringCchCopy() - String copy #2 failed\n");
return 1;
}
else
wprintf(L"StringCchCopy() - Another env variable #2 was copied successfully!\n");
// Terminate the block with a NULL byte. Variable strings are separated by NULL byte, and the block is terminated by a NULL byte
lpszCurrentVariable += lstrlen(lpszCurrentVariable) + 1;
*lpszCurrentVariable = (WCHAR)0;
// Create the child process, specifying a new environment block
SecureZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
fSuccess = CreateProcess(szAppName, NULL, NULL, NULL, TRUE, NULL,
(LPVOID)lpszCurrentVariable, // new environment block
NULL, &si, &pi);
// Validate
if(!fSuccess)
{
wprintf(L"CreateProcess() failed, error %d\n", GetLastError());
return 1;
}
else
{
wprintf(L"\nCreateProcess() - Child process was created successfully!\n");
wprintf(L"Child process ID is %u\n", pi.dwProcessId);
wprintf(L"Child thread ID is %u\n", pi.dwThreadId);
// Verify the current process environment variable
wprintf(L"\n");
system("set");
wprintf(L"\n");
}
// Get the current env variable
lpszVariable = GetEnvironmentStrings();
// If the returned pointer is NULL, exit
if (lpszVariable == NULL)
{
wprintf(L"GetEnvironmentStrings() failed, error %d\n", GetLastError());
return 1;
}
else
wprintf(L"GetEnvironmentStrings() is OK!\n");
// Try to print it
while(*lpszVariable)
{
wprintf(L"%s\n", lpszVariable);
lpszVariable += lstrlen(lpszVariable) + 1;
}
// Frees a block of environment strings
if(FreeEnvironmentStrings(lpszVariable) != 0)
wprintf(L"\nFreeEnvironmentStrings() - a block of environment strings was freed!\n");
else
wprintf(L"\nFreeEnvironmentStrings() failed, error %u\n", GetLastError());
// Wait for the object to signal
Ret = WaitForSingleObject(pi.hProcess, INFINITE);
wprintf(L"\nThe WaitForSingleObject return value is 0X%.8X\n", Ret);
// Close process and thread handles.
if(CloseHandle(pi.hProcess) != 0)
wprintf(L"pi.hProcess handle was closed successfully!\n");
else
wprintf(L"Failed to close pi.hProcess handle, error %u\n", GetLastError());
if(CloseHandle(pi.hThread) != 0)
wprintf(L"pi.hThread handle was closed successfully!\n");
else
wprintf(L"Failed to close pi.hThread handle, error %u\n", GetLastError());
return 0;
}
Output example:
Parent process ID (wmain()) is 4156
Parent thread ID (wmain()) is 6124
GetEnvironmentStrings() is OK!
FreeEnvironmentStrings() - a block of environment strings was freed!
StringCchCopy() - env variable #1 was copied successfully!
StringCchCopy() - Another env variable #2 was copied successfully!
CreateProcess() - Child process was created successfully!
Child process ID is 540
Child thread ID is 4268
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.
c:\amad\winprocessthread\winprocessthread>COMSPEC=C:\WINDOWS\system32\cmd.exe
MyNewOwnEnvSetting=ver 2.0
MyNewOwnVar=MyPath
PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.JS;.WS
PROMPT=$P$G
GetEnvironmentStrings() is OK!
MyNewOwnEnvSetting=ver 2.0
MyNewOwnVar=MyPath
FreeEnvironmentStrings() - a block of environment strings was freed!
c:\amad\winprocessthread\winprocessthread>exit
The WaitForSingleObject return value is 0X00000000
pi.hProcess handle was closed successfully!
pi.hThread handle was closed successfully!
Press any key to continue . . .