This is a new site that's currently running on alpha code. There are going to be bugs. If you discover any, please report them on the site's issues page (GitHub account required). Thanks.
Warning: Many URLs are going to change. Refer to the README file to discover which library project's documentation has been completed.
Applies to: ~>3.1
By default any console app process started by TPJConsoleApp etc. will inherit a copy of the environment variables of the parent process.
It is beyond the scope of this example to explain environment blocks and environment varaibles in detail. To learn about them please see the article “How to access environment variables”.
This can be changed by creating a new environment block and storing a pointer to it in the Environment property. An environment block can be either in ANSI format where each character is one byte (the default) or in Unicode format where each character occupies two bytes. Whether ANSI or Unicode format is used depends on the value of the UnicodeEnvironment Boolean property.
Prior to ~>3.1 the Environment property only supported ANSI environment blocks.
This example shows how to pass a custom environment block to a console application using the Environment and UnicodeEnvironment properties.
There are two applications in this example:
The gist mentioned here contains all the routines from the article “How to access environment variables”. If you want to know how they work then please read the article.
Before we get started on the apps themselves we need code to read environment variables and to create the required environment block. Since the purpose of this example is to learn about how to pass an environment block to a console app using TPJConsoleApp and not to learn about how to create and manipulate environment blocks, we will steal some code from elsewhere to perform these tasks.
All the code you need (and more) can be found in the gist delphidabbler/UEnvVars.pas. Either copy and paste the content of this gist into a file named UEnvVars.pas
or download the file itself using the button displayed on the gist’s web page.
Start a new Delphi VCL forms application. Drop a TMemo, a TCheckBox and a TButton onto the form. The memo control will be used to enter custom environment variables in Name=Value
format, one per line. The checkbox will be used to determine whether the child process gets a copy of the parent process’ environment block along with the environment variables entered in the memo. Clicking the button will execute the console app.
Now add the UEnvVars.pas
file that you created earlier to the project. We will use the CreateEnvBlock routine to create an environment block containing the required environment variables.
All the code of the GUI app goes into the button’s OnClick event handler, so double click the button in the designer and enter the following code into the resulting event handler:
procedure TForm1.Button1Click(Sender: TObject);
var
EnvBlockSize: Integer;
EnvBlock: Pointer;
App: TPJConsoleApp;
begin
// create the environment block
EnvBlockSize := CreateEnvBlock(Memo1.Lines, CheckBox1.Checked, nil, 0);
GetMem(EnvBlock, EnvBlockSize * SizeOf(Char));
try
CreateEnvBlock(Memo1.Lines, CheckBox1.Checked, EnvBlock, EnvBlockSize);
// run the console app
App := TPJConsoleApp.Create;
try
App.CommandLine := 'PrintEnv.exe';
App.Visible := True;
App.Environment := EnvBlock;
{$IFDEF UNICODE}
App.UnicodeEnvironment := True;
{$ELSE}
App.UnicodeEnvironment := False;
{$ENDIF}
App.Execute;
finally
App.Free;
end
finally
// free the environment block
FreeMem(EnvBlock);
end;
end;
The first two lines find the size of the environment block and allocate sufficient memory for it. The second call to CreateEnvBlock is where the environment block gets created. CreateEnvBlock accepts a string list containing the custom environment variables, so we pass the memo’s Lines property to it. The second parameter determines whether a copy of the parent process’ environment variables also gets included in the block, so we pass in the checkbox’s Checked property.
Next we create a TPJConsoleApp instance ready to execute PrintEnv.exe
and store a pointer to the environment block in the Environment property. We use conditional compilation to set the UnicodeEnvironment property to True
when compiled on a Delphi compiler with Unicode support and False
when compiled without Unicode support. The console app is then executed and the TPJConsoleApp instance is freed when the app returns.
Lastly we release the memory that holds the environment block: this should not be freed until after the console app has terminated.
All we need now is to write the PrintEnv.exe
console app that the above code tries to execute.
Start a new Delphi console application project ensuring it places its executable file in the same directory as the GUI app.
Add UEnvVars.pas
, to the project. We will be using the GetAllEnvVars routine to populate a string list with all the app’s environment variables. Each item in the list will be displayed in Name=Value
format.
Now edit the project file to look like this:
program PrintEnv;
{$APPTYPE CONSOLE}
uses
Classes,
UEnvVars in 'UEnvVars.pas';
{$R *.res}
var
EnvVars: TStrings;
I: Integer;
begin
EnvVars := TStringList.Create;
try
GetAllEnvVars(EnvVars);
for I := 0 to Pred(EnvVars.Count) do
begin
WriteLn(EnvVars[I]);
end;
WriteLn;
Write('Press enter to end');
ReadLn;
finally
EnvVars.Free;
end;
end.
Here we create a string list to hold the environment variables then call GetAllEnvVars to populate it. Next we write each environment variable in turn to stdout then finally wait for the user to press Enter before terminating the app.
All that remains is to compile both apps then run the GUI program, enter some environment variables, decide whether to include the current environment, then click the button and check that PrintEnv.exe
displays the expected environment variables.
Sometimes a service may inject an environment variable into every new process, so you may see some unexpected values in the output of
PrintEnv.exe
. For some NVidia graphics drivers insert aPATH
environment variable if it is missing and may modify it when present. So, if you something similar it’s not a bug in this code!