Mega Code Archive

 
Categories / Delphi / System
 

Custom Environment Variable Blocks

Title: Custom Environment Variable Blocks Question: This article looks at how environment variables are passed from one process to another. Answer: When a program spawns a child process, by default the child process gets a copy of the parent's environment block. In my previous article I showed that additional environment variables can be passed to a child process by creating them in the parent process before executing the child process. The child then gets a copy of the new variables along with all the parent's other environment variables. What if you don't want to modify the parent process environment variables, or only want to pass certain variables to the child process? To do this you need to create a new environment block and pass that to the new process. An environment variable block is in the form 'VAR1=Value1'#0'VAR2=Value2'#0#0 - i.e. a sequence of zero terminated strings of environment variables / values terminated by an additional zero character. To create a new process with a custom environment block we need to: 1) create the new environment block containing the environment strings 2) create the new process (using the Windows API CreateProcess), passing the address of the environment block. The following procedure executes the given program and with an environment block containing the environment variables stored in the given string list (the string list stores environment variables in the form 'NAME=VALUE'). procedure ExecWithEnv(const ProgName: string; const Env: TStringList); var EnvBlock: Pointer; // environment block EnvStart: PChar; // location of vars in block BlockSize: Integer; // size of block Idx: Integer; // scans env strings SI: TStartupInfo; // process start up info PI: TProcessInformation; // process info begin // Work out size of environment block BlockSize := 0; for Idx := 0 to Pred(Env.Count) do // add space for #0 terminated string Inc(BlockSize, Length(Env[Idx]) + 1); // add space for final #0 Inc(BlockSize); // Create the environment block GetMem(EnvBlock, BlockSize); try EnvStart := EnvBlock; for Idx := 0 to Pred(Env.Count) do begin StrPCopy(EnvStart, Env[Idx]); Inc(EnvStart, Length(Env[Idx]) + 1); end; EnvStart^ := #0; // Execute the program FillChar(SI, SizeOf(SI), 0); SI.cb := SizeOf(SI); CreateProcess(nil, PChar(ProgName), nil, nil, True, 0, EnvBlock, nil, SI, PI); finally // Finished with env block FreeMem(EnvBlock, BlockSize); end; end; To create a process named 'MyProg.exe' with environment variables FOO=BAR and DELPHI=3000 when a button is clicked do the following: procedure TForm1.Button1Click(Sender: TObject); var EnvVars: TStringList; begin EnvVars := TStringList.Create; try EnvVars.Add('FOO=BAR'); EnvVars.Add('DELPHI=3000'); ExecWithEnv('MyProg.exe', EnvVars); finally EnvVars.Free; end; end; A demo program that demonstrates this and other environment variable techniques is available for download here.