Получить переменные среды Windows, переданные новому процессу (не текущего процесса) - PullRequest
1 голос
/ 13 мая 2019

Как получить полный набор переменных среды, переданных новому процессу с помощью меню «Пуск», не набор переменных среды, переданных моему процессу?Или как мне запустить процесс с этим набором переменных среды?(Технически мне не нужен доступ к ним в моем начальном процессе)

Они могут расходиться, например, если мой процесс запущен, а затем пользователь использует переменную среды GUI для их изменения.

Вариант использования: я пишу утилиту запуска, которая для запуска приложений работает аналогично меню «Пуск».

Для правильного решения необходимо выполнить следующее:

  • Получить обамашинные и пользовательские переменные среды
  • Объединение переменных PATH от машины и пользователя (объединяются ли другие переменные?)
  • Получить HOMEDRIVE, HOMEPATH, USERNAME, USERPROFILE и любые другие переменные, не предоставленные System.Environment.GetEnvironmentVariables(System.EnvironmentVariableTarget.User)
  • НЕ наследовать среду от текущего процесса

Существует ли вызов API Windows для получения этого полного набора переменных среды, которые меню Пуск Windows передает запущенным процессам?Или есть способ запустить процесс так, что Windows автоматически устанавливает переменные окружения без моего вмешательства и без наследования от текущего процесса?

1 Ответ

2 голосов
/ 15 мая 2019

Вот код для анализа полного набора переменных среды в словаре C #.Он использует CreateEnvironmentBlock, как предлагается в комментариях.CreateEnvironmentBlock нужен токен пользователя, для которого вы хотите получить переменные.Мы можем получить маркер для пользователя, который запускает наш процесс через OpenProcessToken(GetCurrentProcess(), TOKEN_READ, out primaryToken);

Получить блок среды очень просто.Больше кода тратится на анализ блока среды в словаре C #, и я уверен, что он может быть намного короче.

Важные биты без проверки ошибок:

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);

Полный пример, готов ккомпилировать:

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;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...