How do I obtain the complete set of environment variables passed to a new process by the start menu, not the set of environment variables passed to my process? Or how do I launch a process with this set of environment variables? (I technically do not need to access them in my initial process)
These can diverge, for example, if my process is launched and then the user uses the environment variable GUI to modify them.
Use-case: I'm writing a launcher utility that behaves similarly to the start menu, for starting applications.
A proper solution needs to do the following:
System.Environment.GetEnvironmentVariables(System.EnvironmentVariableTarget.User)Is there a Windows API call to get this full set of environment variables that the Windows start menu passes to launched processes? Or is there a way to launch a process such that Windows automatically sets its environment variables without my intervention, and without inheriting from the current process?
Here is code to parse the full set of environment variables into a C# Dictionary. It uses CreateEnvironmentBlock as suggested in the comments. CreateEnvironmentBlock needs a user token for the user whose variables you want to retrieve. We can get a token for the user that our process is running as via OpenProcessToken(GetCurrentProcess(), TOKEN_READ, out primaryToken);
Getting the environment block is really easy. More code is spent parsing the environment block into a C# dictionary, and I'm sure it could be much shorter.
Important bits without error checking:
IntPtr primaryToken = IntPtr.Zero;
OpenProcessToken(GetCurrentProcess(), TOKEN_READ, out primaryToken);
IntPtr lpEnvironment = IntPtr.Zero;
bool resultEnv = CreateEnvironmentBlock(out lpEnvironment, primaryToken, false);
// Do stuff with lpEnvironment here
DestroyEnvironmentBlock(lpEnvironment);
CloseHandle(primaryToken);
Full example, ready to compile:
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
public class EnvVarGetter
{
public static Dictionary<String, String> GetEnvironmentVariables()
{
IntPtr primaryToken = IntPtr.Zero;
OpenProcessToken(GetCurrentProcess(), TOKEN_READ, out primaryToken);
if (primaryToken == IntPtr.Zero)
{
return null;
}
IntPtr lpEnvironment = IntPtr.Zero;
bool resultEnv = CreateEnvironmentBlock(out lpEnvironment, primaryToken, false);
if (resultEnv != true)
{
int nError = GetLastError();
}
var envVars = new Dictionary<string, string> { };
IntPtr next = lpEnvironment;
while (Marshal.ReadByte(next) != 0)
{
var str = Marshal.PtrToStringUni(next);
// skip first character because windows allows env vars to begin with equal sign
var splitPoint = str.IndexOf('=', 1);
var envVarName = str.Substring(0, splitPoint);
var envVarVal = str.Substring(splitPoint + 1);
envVars.Add(envVarName, envVarVal);
next = (IntPtr)((Int64)next + (str.Length * 2) + 2);
}
DestroyEnvironmentBlock(lpEnvironment);
CloseHandle(primaryToken);
return envVars;
}
private static uint STANDARD_RIGHTS_REQUIRED = 0x000F0000;
private static uint STANDARD_RIGHTS_READ = 0x00020000;
private static uint TOKEN_ASSIGN_PRIMARY = 0x0001;
private static uint TOKEN_DUPLICATE = 0x0002;
private static uint TOKEN_IMPERSONATE = 0x0004;
private static uint TOKEN_QUERY = 0x0008;
private static uint TOKEN_QUERY_SOURCE = 0x0010;
private static uint TOKEN_ADJUST_PRIVILEGES = 0x0020;
private static uint TOKEN_ADJUST_GROUPS = 0x0040;
private static uint TOKEN_ADJUST_DEFAULT = 0x0080;
private static uint TOKEN_ADJUST_SESSIONID = 0x0100;
private static uint TOKEN_READ = (STANDARD_RIGHTS_READ | TOKEN_QUERY);
private static uint TOKEN_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_QUERY_SOURCE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool CloseHandle(IntPtr handle);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern int GetLastError();
[DllImport("userenv.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool CreateEnvironmentBlock(out IntPtr lpEnvironment, IntPtr hToken, bool bInherit);
[DllImport("userenv.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool DestroyEnvironmentBlock(IntPtr lpEnvironment);
[DllImport("advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool OpenProcessToken(IntPtr ProcessHandle,
UInt32 DesiredAccess, out IntPtr TokenHandle);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr GetCurrentProcess();
public static int Main()
{
// Loop indefinitely till user hits escape
do
{
// Get environment variables
var vars = EnvVarGetter.GetEnvironmentVariables();
// Log them
foreach(var pair in vars)
{
Console.WriteLine(pair);
}
while (!Console.KeyAvailable)
{
}
} while (Console.ReadKey(true).Key != ConsoleKey.Escape);
return 0;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With