Présentation, description et utilisation des variables d'environnement sous Windows.

Pierre Castelain

Présentation, description et utilisation des variables d'environnement sous Windows. À l'article est associée une unité Delphi permettant une manipulation aisée de celles-ci.

- Titre : Présentation, description et utilisation des variables d'environnement sous Windows.

- Auteur : Pierre Castelain

- Parution : 8 novembre 2003

- Mise à jour : 2 janvier 2020

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 203 Pierre Castelain. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Remerciements

- II. Préambule

- III. Présentation

- IV. Variables d'environnement fournies par Windows

- V. Implémentation

- VI. Modifier les variables d'environnement

- VII. Variables système et utilisateur

- VIII. Emplacements dans la base de registre (Windows NT uniquement)

- IX. Manipuler les variables d'environnement par programme

- X. Code Delphi

I - Remerciements

Je tiens à remercier tout particulièrement les personnes suivantes pour leur aide précieuse lors de la rédaction et de la relecture de cet article :

- Nono40 : https://nono40.developpez.com;

- hachesse : https://hachesse.developpez.com.

II - Préambule

Cet article est un document de synthèse dont le but est de fournir un maximum d'informations concernant l'utilisation des variables d'environnement sous Windows. Il n'a pas la prétention d'être exhaustif, mais devrait permettre aux développeurs d'avoir une vision relativement complète de ce système.

Le but recherché n'est pas d'encourager le lecteur à utiliser ce mécanisme vieillissant, mais plutôt de servir de référence afin d'aider les développeurs devant manipuler des variables d'environnement dans le cadre de développement compatible avec l'applicatif existant.

III - Présentation

Les variables d'environnement, présentes depuis les premières versions de DOS, permettent de véhiculer simplement de l'information entre plusieurs programmes. De nos jours, celles-ci sont de moins en moins utilisées et remplacées par la base de registre. Elles restent tout de même pratiques et sont encore utilisées par les systèmes d'exploitation modernes.

On peut considérer une variable d'environnement comme une variable globale au système. Chaque application, programme ou service peut lire ou modifier la valeur d'une de ces variables sous certaines conditions que nous verrons un peu plus loin.

Windows propose un certain nombre de ces variables qui permettent aux applications d'obtenir des informations sur la configuration du système. Par exemple les variables TMP ou TEMP fournissent le chemin du dossier temporaire de Windows et la variable PATH indique à Windows où aller chercher les programmes lancés depuis l'invite de commande et les DLL nécessaires aux applications.

Pour que plusieurs applications puissent partager une information sous forme de variable d'environnement, il suffit que celles-ci connaissent le nom de la variable pour pouvoir y accéder. C'est donc un système très simple.

Prenons un exemple afin d'illustrer ce mécanisme. Imaginons deux applications manipulant un même fichier de données. La première application permet de saisir des données dans le fichier et la seconde permet d'afficher ces données. Ces deux applications peuvent utiliser une variable que nous appellerons par exemple CHEMIN_DONNEES pour stocker le chemin d'accès au fichier. Ces applications peuvent donc être installées n'importe où sur le disque, il leur suffit de lire la valeur stockée dans la variable CHEMIN_DONNEES pour connaître le nom du fichier à utiliser. De même, le déplacement de ce fichier est possible et ne nécessite que la modification de la valeur de la variable.

IV - Variables d'environnement fournies par Windows

Il existe quelques variables fournies par le système d'exploitation. En voici une liste non exhaustive classée par type de système. La casse des variables n'a aucune importance. Les noms des variables sont indiqués tels qu'ils apparaissent sous les systèmes utilisés par l'auteur.

Variables communes à la plupart des versions de Windows

- TMP et TEMP : répertoire temporaire de Windows.

- PROMPT : invite affichée par l'invite de commande.

- Winbootdir : répertoire de démarrage de Windows.

- COMSPEC : nom du programme d'invite de commande.

- PATH : chemins de recherche des programmes et DLL (séparés par des points-virgules).

- Windir : répertoire de Windows.

Variables disponibles sous Windows NT et 2000

- COMPUTERNAME : nom de l'ordinateur.

- HOMEDRIVE : disque local primaire (partition système).

- HOMEPATH : dossier par défaut pour les utilisateurs.

- LOGONSERVER : nom du serveur de domaine.

- NUMBER_OF_PROCESSORS : nombre de processeurs installés.

- OS : nom du système d'exploitation.

- Os2LibPath : chemin de la bibliothèque Microsoft OS/2.

- PATHEXT : liste des extensions de fichier reconnues comme des exécutables.

- PROCESSOR_ARCHITECTURE : type de processeur installé.

- PROCESSOR_IDENTIFIER : identification du processeur installé (type, modèle, etc.).

- PROCESSOR_LEVEL : niveau du processeur.

- PROCESSOR_REVISION : révision du processeur.

- SystemDrive : disque local sur lequel le système réside.

- SystemRoot : chemin du système (égal à Windir).

- USERDOMAIN : nom du domaine sous lequel l'utilisateur s'est connecté.

- USERNAME : nom de l'utilisateur courant.

- USERPROFILE : chemin du profil de l'utilisateur courant.

Variables disponibles sous Windows 2000

- ALLUSERSPROFILE : chemin du profil commun à tous les utilisateurs.

- APPDATA : chemin des données applicatives de l'utilisateur courant.

- CommonProgramFiles : chemin des programmes communs.

- ProgramFiles : chemin des programmes.

V - Implémentation

Les variables d'environnement sont stockées sous la forme d'un bloc d'environnement dans chaque processus en cours d'exécution. Sous Windows, chaque processus possède donc un bloc de données contenant un ensemble de variables et leur valeur. Ce bloc est constitué d'un vecteur de chaînes de caractères C (à zéro terminal) sous la forme « Nom_de_la_variable=Valeur_de_la_variable » et terminé par un zéro (il y a donc deux caractères zéro à la fin du bloc). Un de ces blocs peut donc se présenter ainsi :

TEMP=%USERPROFILE%\Local Settings\Temp#0
TMP=%USERPROFILE%\Local Settings\Temp#0
#0

Note : #0 représente ici le caractère de code ANSI égal à zéro. Les retours à la ligne ont été ajoutés pour améliorer la lisibilité, en réalité ils n'existent pas.

Par défaut, un processus enfant hérite du bloc d'environnement de son processus parent sous la forme d'une copie de celui-ci. Le processus enfant hérite donc de toutes les variables d'environnement de ses processus ancêtres. Il est cependant possible de fournir un nouveau bloc d'environnement en créant celui-ci et en passant son adresse à la fonction CreateProcess.

Ce mécanisme permet d'offrir l'accès à ces variables depuis toutes les applications sans risque de collision puisque chaque processus travaille sur sa propre copie de l'environnement.

Pour bien comprendre ce mécanisme, je vous propose un petit exercice.

- Ouvrez une invite de commandes (Menu Démarrer, Exécuter, tapez « CMD » sous Windows NT ou « COMMAND » sous 9x).

- Nous allons utiliser la commande SET qui permet d'afficher et de modifier la valeur de chaque variable.

- Tapez la commande « SET DV=DEVELOPPEZ.COM »

- Nous venons de créer une nouvelle variable nommée DV dont la valeur est « DEVELOPPEZ.COM ».

- Tapez la commande « SET » pour afficher la liste des variables ainsi que leurs valeurs respectives.

- Vous pouvez également taper la commande « ECHO %DV% » pour afficher la valeur de la variable DV (les caractères % permettent de spécifier à l'invite de commande qu'il s'agit d'une variable d'environnement dont nous voulons obtenir la valeur).

- Ne fermez pas l'invite de commande actuelle et ouvrez-en une seconde.

- Tapez la commande « SET » pour obtenir la liste des variables.

- Vous pouvez constater que la variable DV n'existe pas dans cet environnement, celui-ci étant directement hérité de l'environnement principal de Windows et non de l'environnement de la première invite de commande.

- Fermez cette invite de commande et retournez sur la première.

- Tapez la commande « CMD » (ou « COMMAND » si vous êtes sous Windows 9x) pour créer une nouvelle invite de commande (attention, celle-ci n'ouvre pas de nouvelle fenêtre).

- Utilisez la commande « SET » pour vérifier la présence de la variable DV.

- Vous pouvez donc constater que cette nouvelle invite a hérité de l'environnement de la première. Ce processus a bien hérité l'environnement du processus parent.

- Utilisez deux fois la commande « EXIT » pour fermer les deux invites.

VI - Modifier les variables d'environnement

La modification « manuelle » des variables d'environnement se fait différemment selon la version de Windows utilisée.

Les versions 9x de Windows (95, 98 et Millenium) utilisent le fichier autoexec.bat situé à la racine de la partition de démarrage (habituellement C: ). Ce fichier qui est lu au démarrage de Windows (ou plutôt du DOS) contient entre autres une suite de commandes SET définissant les variables. Il est donc nécessaire de redémarrer Windows lorsque l'on modifie une ou plusieurs de ces variables et que l'on désire que l'ensemble des applications en tiennent compte. La taille du bloc d'environnement n'est pas illimitée sous ces versions de Windows et le système ne génère malheureusement aucun message d'erreur (en dehors de la console) lors du dépassement de la capacité de ce bloc. Il est toutefois possible de modifier la taille du bloc en modifiant le fichier system.ini situé dans le dossier de Windows. Il suffit d'ajouter la ligne CommandEnvSize=Taille en octets dans la section [NonWindowsApp]. Par exemple pour un bloc de 4 ko :

[NonWindowsApp]
CommandEnvSize=4096

Les versions NT de Windows (NT 4, 2000 et XP) stockent les variables dans la base de registre et permettent la modification de celles-ci via l'icône « Système » du panneau de configuration (onglet « Environnement » ou « Avancé » selon les versions). Contrairement à Windows 9X, la prise en compte des modifications est immédiate (elle nécessite tout de même quelques secondes) et valable pour toutes les applications qui seront démarrées après les modifications. De rares applications sont capables de détecter que l'environnement a été modifié et rechargent celui-ci sans avoir besoin d'être relancées (en particulier le shell).

VII - Variables système et utilisateur

Sous Windows NT, les variables d'environnement sont séparées en deux groupes distincts, les variables dites « système » et les variables dites « utilisateur ». Cette distinction est en fait relativement simple. Les variables système sont communes à tous les utilisateurs d'un même ordinateur, elles sont valables pour la machine alors que les variables utilisateur ne sont valables que pour un seul utilisateur de cette machine. Il est possible qu'une même variable apparaisse donc deux fois avec une valeur différente dans chaque groupe. Dans ce cas, c'est la variable utilisateur qui est prise en compte.

VIII - Emplacements dans la base de registre (Windows NT uniquement)

Les variables d'environnement sont enregistrées sous la forme d'une liste de valeurs situées dans certaines clés précises du registre. Le nom de la valeur correspond au nom de la variable d'environnement et le contenu de la valeur à la valeur de la variable d'environnement.

Le contenu de ces valeurs est de type chaîne (REG_SZ) ou de type chaîne « extensible » (REG_EXPAND_SZ) dans le cas où le contenu de la valeur contient une référence à une autre variable d'environnement. Par exemple la variable TEMP est généralement définie comme ayant la valeur « %USERPROFILE%\Local Settings\Temp ». Cette variable peut ainsi être définie de manière globale tout en étant spécifique à chaque utilisateur (la variable USERPROFILE contenant le nom de l'utilisateur). Ces valeurs ne peuvent être manipulées avec l'éditeur de registre RegEdit, il faut utiliser RegEdt32 pour pouvoir le faire.

- Les variables utilisateur sont stockées sous la clé :
HKEY_CURRENT_USER\Environment

- Les variables système sont stockées sous la clé :
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment

- Il existe un troisième emplacement qui est généralement très mal compris. Il s'agit de la clé :
HKEY_USERS\.DEFAULT\Environment
Cet emplacement ne définit pas les variables d'environnement par défaut fournies à chaque nouvel utilisateur, mais plutôt les variables disponibles quand aucun utilisateur n'est connecté, c'est-à-dire quand Windows présente l'invite de connexion. Si vous voulez spécifier des variables utilisateur qui seront définies à chaque création d'utilisateur, il vous faut créer un profil et le copier dans le profil par défaut. Cette manipulation dépasse le cadre de cet article, vous trouverez facilement la marche à suivre sur de nombreux sites et forums.

Attention, la modification des variables d'environnement réalisée directement dans la base de registre n'est pas prise en compte directement par le système. Il faut que celui-ci soit informé de cette modification par un message WM_SETTINGCHANGE comme nous le verrons un peu plus loin.

IX - Manipuler les variables d'environnement par programme

L'API Windows propose quelques fonctions pour manipuler les variables d'environnement. Ces fonctions sont exclusivement prévues pour manipuler l'environnement courant du processus courant. La modification globale des variables ne peut se faire que par l'intermédiaire de la base de registre (ou du fichier autoexec.bat pour les versions 9x de Windows).

- GetEnvironmentVariable : cette fonction permet d'obtenir la valeur d'une variable de l'environnement du processus courant si elle existe. Dans le cas contraire, la fonction retourne zéro et la fonction GetLastError retourne ERROR_ENVVAR_NOT_FOUND.

- SetEnvironmentVariable : cette fonction permet d'ajouter, de modifier ou de supprimer une variable de l'environnement du processus courant. Si la valeur passée est nulle, la variable est supprimée, sinon la variable est modifiée dans le cas où elle existe déjà et créée dans le cas où elle n'existe pas.
Attention, comme nous l'avons déjà vu, ces modifications ne sont valables que pour l'environnement du processus courant (en général l'application) et par héritage pour l'environnement des processus enfants du processus courant.

- GetEnvironmentStrings : cette fonction permet d'obtenir la liste complète des variables de l'environnement du processus courant. Cette liste est fournie sous la forme d'un vecteur de chaînes de caractères à zéro terminal (chaînes C), lui-même terminé par un zéro. La fonction retourne l'adresse du bloc de mémoire contenant ces informations. Il est strictement interdit de modifier ce bloc de mémoire. Pour modifier les variables, utilisez la fonction SetEnvironmentVariable.
Une fois que vous n'avez plus besoin de ce bloc de mémoire, utilisez la fonction FreeEnvironmentStrings pour le libérer.

- FreeEnvironmentStrings : cette fonction libère un bloc d'environnement fourni par GetEnvironmentStrings.

- CreateProcess : il est possible de modifier le bloc d'environnement d'un processus lancé par la fonction CreateProcess. Le paramètre lpEnvironment permet de spécifier l'adresse d'un bloc d'environnement que vous aurez préalablement créé et rempli. Si cette adresse n'est pas fournie, la fonction CreateProcess utilise l'environnement du processus courant.

- WM_SETTINGCHANGE : ce message permet d'informer les processus en cours d'exécution de la modification des variables d'environnement (entre autres). Il doit être envoyé à l'aide des fonctions SendMessageTimeOut ou BroadcastSystemMessage et le paramètre LParam doit contenir la chaîne 'Environment'. L'utilisation d'un temps mort (time out) permet d'attendre l'acquittement des applications traitant ce message tout en évitant de bloquer le système lorsque certaines applications ne traitent pas celui-ci.

X - Code Delphi

Ce paragraphe présente une unité Delphi proposant des fonctions simplifiant l'utilisation des API Windows pour la manipulation des variables d'environnement.

Attention, les fonctions agissant sur les variables système, utilisateur et par défaut ainsi que la fonction BroadcastEnvironmentChange ne sont valables que sous Windows NT.

Le source de cette unité est également disponible dans un fichier archive au format zip. Ce fichier peut être téléchargé en cliquant sur le lien suivant : Environment.zip

unit Environment;

interface
uses
Classes;

{ GetCurrentProcessEnvVar retourne la valeur de la variable d'environnement }
{ VariableName du processus courant ou une chaîne vide si cette variable    }
{ n'existe pas.                                                             }
function GetCurrentProcessEnvVar(const VariableName: string): string;

{ SetCurrentProcessEnvVar crée ou change la valeur de la variable     }
{ d'environnement VariableName du processus courant en VariableValue. }
procedure SetCurrentProcessEnvVar(const VariableName, VariableValue: string);

{ DeleteCurrentProcessEnvVar supprime la variable d'environnement VariableName }
{ de l'environnement du processus courant.                                     }
procedure DeleteCurrentProcessEnvVar(const VariableName: string);

{ ReadCurrentProcessEnvVars remplit la liste Vars avec l'ensemble des variables }
{  d'environnement du processus courant. Chaque ligne est de la forme          }
{  variable=valeur                                                             }
procedure ReadCurrentProcessEnvVars(Vars: TStrings);

{ BuildEnvironmentBlock construit un bloc d'environnement en utilisant une    }
{ liste de variables d'environnement fournie par Vars. Le bloc est copié dans }
{ Buffer et le nombre de caractères copiés est retourné comme résultat.       }
{ L'argument Len est utilisé à l'appel pour spécifier la taille du buffer en  }
{ nombre de caractères et contient après l'appel la taille minimale du buffer  }
{ pour contenir le bloc en entier.                                            }
{ Cette fonction est utilisée en 2 appels: le premier permet d'obtenir la     }
{ taille du buffer à allouer et le deuxième appel remplit le buffer.           }
function BuildEnvironmentBlock(Vars: TStrings; Buffer: PAnsiChar;
var Len: Longword): LongWord;

{ ReadSystemVars remplit la liste Vars avec l'ensemble des variables système. }
procedure ReadSystemEnvVars(Vars: TStrings);

{ ReadSystemVars remplit la liste Vars avec l'ensemble des variables utilisateur. }
procedure ReadUserEnvVars(Vars: TStrings);

{ ReadSystemVars remplit la liste Vars avec l'ensemble des variables par défaut. }
procedure ReadDefaultEnvVars(Vars: TStrings);

{ SetSystemEnvVar modifie la valeur d'une variable système et informe          }
{ l'ensemble des applications que l'environnement a changé si BroadcastChange  }
{ vaut vrai.                                                                   }
procedure SetSystemEnvVar(const VariableName, VariableValue: string;
const BroadcastChange: boolean);

{ DeleteSystemEnvVar supprime une variable système et informe l'ensemble des }
{ applications que l'environnement a changé si BroadcastChange vaut vrai.    }
procedure DeleteSystemEnvVar(const VariableName: string;
const BroadCastChange: boolean);

{ SetUserEnvVar modifie la valeur d'une variable utilisateur et informe       }
{ l'ensemble des applications que l'environnement a changé si BroadcastChange }
{ vaut vrai.                                                                  }
procedure SetUserEnvVar(const VariableName, VariableValue: string;
const BroadcastChange: boolean);

{ DeleteUserEnvVar supprime une variable utilisateur et informe l'ensemble des }
{ applications que l'environnement a changé si BroadcastChange vaut vrai.      }
procedure DeleteUserEnvVar(const VariableName: string;
const BroadcastChange: boolean);

{ SetDefaultEnvVar modifie la valeur d'une variable par défaut et informe     }
{ l'ensemble des applications que l'environnement a changé si BroadcastChange }
{  vaut vrai.                                                                 }
procedure SetDefaultEnvVar(const VariableName, VariableValue: string;
const BroadcastChange: boolean);

{ DeleteDefaultEnvVar supprime une variable par défaut et informe l'ensemble  }
{ des applications que l'environnement a changé si BroadcastChange vaut vrai. }
procedure DeleteDefaultEnvVar(const VariableName: string;
const BroadcastChange: boolean);

{ BroadcastEnvironmentChange informe l'ensemble des applications que }
{ l'environnement a changé.                                          }
procedure BroadcastEnvironmentChange(TimeOut: Cardinal = 2000);

implementation
uses
Windows, SysUtils, Registry, Messages;

function GetCurrentProcessEnvVar(const VariableName: string): string;
var
nSize: DWord;
begin
nSize:= 0;
nSize:= GetEnvironmentVariable(PChar(VariableName), nil, nSize);
if nSize = 0 then
result:= ''
else
begin
SetLength(result, nSize - 1);
if GetEnvironmentVariable(PChar(VariableName), PChar(result), nSize) <> nSize - 1 then
raise Exception.Create(SysErrorMessage(GetlastError))
end;
end;

procedure SetCurrentProcessEnvVar(const VariableName, VariableValue: string);
begin
SetEnvironmentVariable(PChar(VariableName), PChar(VariableValue));
end;

procedure DeleteCurrentProcessEnvVar(const VariableName: string);
begin
SetCurrentProcessEnvVar(VariableName, '');
end;

procedure ReadEnvironmentBlock(const Block: PAnsiChar; Vars: TStrings);
var
i: Integer;
s: string;
begin
Vars.Clear;
i:= 0;
while Block[i] <> #0 do
begin
s:= '';
while Block[i] <> #0 do
begin
s:= s + Block[i];
Inc(i);
end;
Vars.Add(s);
Inc(i);
end;
end;

procedure ReadCurrentProcessEnvVars(Vars: TStrings);
var
block: PAnsiChar;
begin
block:= GetEnvironmentStrings;
try
ReadEnvironmentBlock(block, Vars);
finally
FreeEnvironmentStrings(block);
end;
end;

function BuildEnvironmentBlock(Vars: TStrings; Buffer: PAnsiChar;
var Len: Longword): LongWord;
var
line, i: Integer;
p, l: LongWord;
begin
p:= 0;
l:= p;
for line:= 0 to Vars.Count - 1 do
begin
for i:= 1 to Length(Vars[line]) do
begin
if p < Len then
begin
Buffer[p]:= Vars[line][i];
Inc(l);
end;
Inc(p);
end;
if p < Len then
begin
Buffer[p]:= #0;
Inc(l);
end;
Inc(p);
end;
if p < Len then
begin
Buffer[p]:= #0;
Inc(l);
end;
result:= l;
Len:= p;
end;

procedure ReadSystemEnvVars(Vars: TStrings);
var
i: Integer;
begin
Vars.Clear;
with TRegistry.Create do
try
Access:= KEY_READ;
RootKey:= HKEY_LOCAL_MACHINE;
if OpenKey('SYSTEM\CurrentControlSet\Control\Session Manager\Environment',
false) then
begin
GetValueNames(Vars);
for i:= Vars.Count - 1 downto 0 do
try
Vars[i]:= Vars[i] + '=' + ReadString(Vars[i]);
except
Vars.Delete(i);
end;
CloseKey;
end
else
raise Exception.Create('Impossible d''ouvrir la clé.');
finally
Free;
end;
end;

procedure ReadUserEnvVars(Vars: TStrings);
var
i: Integer;
begin
Vars.Clear;
with TRegistry.Create do
try
Access:= KEY_READ;
RootKey:= HKEY_CURRENT_USER;
if OpenKey('Environment', false) then
begin
GetValueNames(Vars);
for i:= Vars.Count - 1 downto 0 do
try
Vars[i]:= Vars[i] + '=' + ReadString(Vars[i]);
except
Vars.Delete(i);
end;
CloseKey;
end
else
raise Exception.Create('Impossible d''ouvrir la clé.');
finally
Free;
end;
end;

procedure ReadDefaultEnvVars(Vars: TStrings);
var
i: Integer;
begin
Vars.Clear;
with TRegistry.Create do
try
Access:= KEY_READ;
RootKey:= HKEY_USERS;
if OpenKey('.DEFAULT\Environment', false) then
begin
GetValueNames(Vars);
for i:= Vars.Count - 1 downto 0 do
try
Vars[i]:= Vars[i] + '=' + ReadString(Vars[i]);
except
Vars.Delete(i);
end;
CloseKey;
end
else
raise Exception.Create('Impossible d''ouvrir la clé.');
finally
Free;
end;
end;

procedure SetSystemEnvVar(const VariableName, VariableValue: string;
const BroadcastChange: boolean);
begin
with TRegistry.Create do
try
Access:= KEY_WRITE;
RootKey:= HKEY_LOCAL_MACHINE;
if OpenKey('SYSTEM\CurrentControlSet\Control\Session Manager\Environment',
false) then
begin
if (VariableValue = '') then
DeleteValue(VariableName)
else
WriteString(VariableName, VariableValue);
if BroadcastChange then
BroadcastEnvironmentChange;
end;
finally
Free;
end;
end;

procedure SetUserEnvVar(const VariableName, VariableValue: string;
const BroadcastChange: boolean);
begin
with TRegistry.Create do
try
Access:= KEY_WRITE;
RootKey:= HKEY_CURRENT_USER;
if OpenKey('Environment', false) then
begin
if (VariableValue = '') then
DeleteValue(VariableName)
else
WriteString(VariableName, VariableValue);
if BroadcastChange then
BroadcastEnvironmentChange;
end;
finally
Free;
end;
end;

procedure SetDefaultEnvVar(const VariableName, VariableValue: string;
const BroadcastChange: boolean);
begin
with TRegistry.Create do
try
Access:= KEY_WRITE;
RootKey:= HKEY_USERS;
if OpenKey('.DEFAULT\Environment', false) then
begin
if (VariableValue = '') then
DeleteValue(VariableName)
else
WriteString(VariableName, VariableValue);
if BroadcastChange then
BroadcastEnvironmentChange;
end;
finally
Free;
end;
end;

procedure BroadcastEnvironmentChange(TimeOut: Cardinal = 2000);
var
lParam: PChar;
dwResult: Cardinal;
begin
lParam:= 'Environment';
SendMessageTimeOut(HWND_BROADCAST, WM_SETTINGCHANGE, 0,
Integer(lParam), SMTO_NORMAL    , TimeOut, dwResult);
if dwResult <> 0 then
raise Exception.Create(SysErrorMessage(dwResult));
end;

procedure DeleteSystemEnvVar(const VariableName: string;
const BroadCastChange: boolean);
begin
SetSystemEnvVar(VariableName, '', BroadCastChange);
end;

procedure DeleteUserEnvVar(const VariableName: string;
const BroadCastChange: boolean);
begin
SetUserEnvVar(VariableName, '', BroadCastChange);
end;

procedure DeleteDefaultEnvVar(const VariableName: string;
const BroadCastChange: boolean);
begin
SetDefaultEnvVar(VariableName, '', BroadCastChange);
end;

end.