Хобрук: Ваш путь к мастерству в программировании

Установка глобальных переменных среды программно

Мне нужно установить переменную среды программно.

Microsoft предоставляет документацию для этого здесь< /а>. Вам просто нужно создать новое значение в реестре под HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment. Эта часть работает нормально.

Проблема в том, что эти изменения вступают в силу только после выхода из системы и повторного входа в нее.

Чтобы обойти это, они предлагают выполнить этот небольшой фрагмент кода:

if (!SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0,
    (LPARAM) "Environment", SMTO_ABORTIFHUNG,
    5000, &dwReturnValue))
{
  ... take action in case of failure
}

Я сделал именно так, SendMessageTimeout возвращает TRUE, но по крайней мере под Windows 10 это не действует. Недавно открытое окно командной строки по-прежнему не будет отображать вновь созданную переменную.

Я также пытался запустить этот фрагмент кода в процессе с повышенными правами, но результат все тот же.

Но когда я использую системный апплет для изменения переменных среды, появляется моя вновь созданная переменная, и когда я нажимаю «ОК» в апплете и когда я открываю другую командную строку, переменная появляется.

Есть предположения?


  • Просто любопытно: по крайней мере, в Windows 10 это не работает. в более ранних версиях это работает? 22.02.2018
  • @alk Хороший вопрос, я не могу проверить это прямо сейчас, но я подозреваю, что это работало в более ранних версиях Windows, и, поскольку это своего рода взлом, он больше не работает. 22.02.2018
  • Вы запускаете приложение, вызывающее фрагмент кода, в режиме с повышенными правами? 22.02.2018
  • @ryyker вопрос отредактирован: повышен или нет, результат тот же 22.02.2018
  • Это должно быть обман... 22.02.2018
  • К вашему сведению, есть аналогичный вопрос здесь, где обсуждается изменение переменных среды на уровне компьютера, пользователя и приложения. Кроме того, не уверен, что это будет иметь значение, но должно ли (LPARAM) "Environment" быть (LPARAM)L"Environment"? 22.02.2018
  • Я думаю, нам нужен минимально воспроизводимый пример. 22.02.2018
  • Я также читаю, что у других были аналогичные результаты с использованием SendMessageTimeout. У меня нет с этим опыта, но есть предложение здесь с помощью SHChangeNotify(). 22.02.2018
  • Вы пытаетесь установить переменную среды для текущей среды или для всех сред? 22.02.2018
  • @UKMonkey для всех сред, так же, как и с системными переменными среды в панели управления. 22.02.2018
  • @MichaelWalz Не знал об этом звонке - интересно. Рад, что вы решили это! (Обратно спать я иду) 22.02.2018
  • @ryyker L (LPARAM)L"Environment" в вашем комментарии поднял красный флаг мозгом, спасибо. 22.02.2018
  • В Windows 10 апплет, о котором вы говорите, вероятно, написан с использованием методов С#. Конечно, вероятно, существует и подход winapi, но он будет спрятан где-то в лабиринте запутывания Microsoft. 22.02.2018
  • @ryyker есть есть один, см. мой собственный ответ ниже. 22.02.2018

Ответы:


1

Проблема была решена явным вызовом wide версии SendMessageTimeout и отправкой "Environment" в виде строки wide:

SendMessageTimeoutW(HWND_BROADCAST, WM_SETTINGCHANGE, 0, 
                   (LPARAM)L"Environment", SMTO_ABORTIFHUNG, 5000, &dwReturnValue);
22.02.2018
  • Я просмотрел несколько сайтов, которые пытались решить одну и ту же проблему. Этот ответ - единственный подход, который я видел, у которого действительно есть зубы для решения проблемы. 22.02.2018
  • @zett На самом деле я думаю, что это не так. Он нацелен на Unicode, иначе код в вопросе работает. 22.02.2018

  • 2

    Как выяснил Майкл, ширина строки должна соответствовать типу функции A/W. WM_SETTINGCHANGE находится в диапазоне < WM_USER и будет маршалироваться оконным менеджером.

    Вы можете использовать макрос TEXT для создания работающего кода. для всех везде, если вы не хотите жестко кодировать суффикс имени функции:

    SendMessageTimeout(
      HWND_BROADCAST,
      WM_SETTINGCHANGE, 
      0, 
      (LPARAM) TEXT("Environment"),
      SMTO_ABORTIFHUNG,
      5000,
      &dwReturnValue
    );
    
    22.02.2018
  • Что ж, это именно не то, что подразумевает ответ Майкла. Ваш код вызывает либо SendMessageTimeoutA, либо SendMessageTimeoutW, хотя, по словам Майкла, нужно всегда вызывать SendMessageTimeoutW, даже для сборок MBCS. 22.02.2018
  • @ zett42 Нет, его исходный код просто использует SendMessageTimeout, но на самом деле это SendMessageTimeoutW, когда UNICODE определен, но передается строка ANSI, и компилятор не может обнаружить несоответствие, потому что вам нужно выполнить приведение. В С++ компилятор может обнаружить это, если вы сделаете (LPARAM) static_cast<LPCTSTR>("Environment"). 22.02.2018
  • Это правильно, но я бы не стал использовать эти макросы из 1990-х. Они существовали только для поддержки Windows 9x. Просто используйте Unicode явно -- SendMessageTimeOutW с L"Environment". 22.02.2018
  • W является SendMessageTimeoutW обязательным, если программа скомпилирована как версия, отличная от UNICODE (MBCS). 22.02.2018
  • @zett42 zett42 И я считаю, что это утверждение неверно, W является обязательным, если ваша строка L ... потому что строка должна соответствовать функции. Если SendMessageTimeoutA со строкой ... ANSI не работает, то все программы, написанные для 95/98/ME, сломаны. 22.02.2018
  • Звучит разумно. Если бы @MichaelWalz мог уточнить. 22.02.2018
  • Что уточнить? Андерс прав без сомнения. Внутри Windows будет декодировать строку ANSI для этого сообщения. Чтобы проверить это, требуется менее 5 минут. Создайте простую программу, которая вызывает SendMessageTimeoutA с "Environment". Вручную измените значение в HKCU\Environment. Запустите свою программу и проверьте среду проводника в Process Explorer. Здорово. Теперь все, пожалуйста, прекратите использовать ANSI. 22.02.2018
  • Не могли бы вы фальшиво отредактировать свой пост, чтобы я мог отменить свой отрицательный голос? хД 23.02.2018
  • @zett42 Конечно :) 23.02.2018
  • Хотя должен быть размер символа ;-) 23.02.2018
  • Новые материалы

    Основы принципов S.O.L.I.D, Javascript, Git и NoSQL
    каковы принципы S.O.L.I.D? Принципы SOLID призваны помочь разработчикам создавать надежные, удобные в сопровождении приложения. мы видим пять ключевых принципов. Принципы SOLID были разработаны..

    Как настроить Selenium в проекте Angular
    Угловой | Селен Как настроить Selenium в проекте Angular Держите свое приложение Angular и тесты Selenium в одной рабочей области и запускайте их с помощью Mocha. В этой статье мы..

    Аргументы прогрессивного улучшения почти всегда упускают суть
    В наши дни в кругах веб-разработчиков много болтают о Progressive Enhancement — PE, но на самом деле почти все аргументы с обеих сторон упускают самую фундаментальную причину, по которой PE..

    Введение в Джанго Фреймворк
    Схема «работать умно, а не усердно» В этой и последующих статьях я познакомлю вас с тем, что такое фреймворк Django и как создать свое первое приложение с помощью простых и понятных шагов, а..

    Настольный ПК как «одно кольцо, чтобы править всеми» домашних компьютеров
    Вид после 9 месяцев использования С настольных компьютеров все началось, но в какой-то момент они стали «серверами», и мы все перешли на ноутбуки. В прошлом году я столкнулся с идеей настольных..

    Расширенные методы безопасности для VueJS: реализация аутентификации без пароля
    Руководство, которое поможет вам создавать безопасные приложения в долгосрочной перспективе Безопасность приложений часто упускается из виду в процессе разработки, потому что основная..

    стройный-i18следующий
    Представляем стройную оболочку для i18next. Эта библиотека, основанная на i18next, заключает экземпляр i18next в хранилище svelte и отслеживает события i18next, такие как languageChanged,..