2009-12-17 2 views
15

Я пишу DLL Win32 с функцией, которая добавляет каталог в переменную среды PATH Windows (для использования в установщике).Программно добавление каталога в переменную среды Windows PATH

Рассмотрение переменных среды в Regedit или панели управления после запуска DLL показывает мне, что моей DLL удалось добавить путь к HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment и HKEY_CURRENT_USER\Environment.

Но когда я запускаю новую командную строку (после запуска библиотеки DLL), каталог, который я добавил, не отображается в выводе echo %PATH%, и я не могу получить доступ к исполняемому файлу, который живет в этом каталоге, набрав его имя.

Я думаю, что моя программа не очень хорошо уведомляет систему о том, что PATH изменилась, или, может быть, она уведомляет их, прежде чем изменение полностью вступит в силу. Я прочитал article by Microsoft, который говорит, чтобы передать WM_SETTINGCHANGE сообщений после изменения переменного окружения, и я делаю, что с этим кодом:

DWORD result2 = 0; 
LRESULT result = SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, 
    (LPARAM)"Environment", SMTO_ABORTIFHUNG, 5000, &result2); 
if (result == 0){ /* ... Display error message to user ... */ } 

Порядок моих звонков: RegCreateKeyEx, RegSetValueEx, RegCloseKey, SendMessageTimeout

Если я нажмю «ОК» в окне «Переменные среды» панели управления, изменения, внесенные моей DLL в PATH, появятся во вновь созданных командных приглашениях, поэтому есть что-то, что делает панель управления для распространения изменений PATH; Я хочу выяснить, что это такое и сделать то же самое.

Кто-нибудь знает, что я должен делать?

У меня 64-разрядная версия Windows Vista, но я хочу, чтобы это работало на всех операционных системах Windows XP, Vista и Windows 7.

Обновление: Проблема с кодом, который я опубликовал выше, заключается в том, что я не поставил префикс L в строку «Окружающая среда». Хотя он не говорит об этом явно в документации Microsoft, которую я могу найти, LPARAM должен быть указателем на строку WCHAR (2-байтовые символы) в отличие от строки CHAR, что и компилятор Visual Studio по умолчанию когда я пишу строковый литерал. Решение моей проблемы состояло в том, чтобы изменить «Окружающая среда» на L «Окружающая среда». (Я думал, что я уже пробовал это, прежде чем публиковать этот вопрос, но, видимо, я не пробовал это правильно!) Но любой, кто хочет получить полное решение на C++ для этой задачи, должен посмотреть на ответ Дэна Молдинга.

+0

Возможно, вы захотите ознакомиться с исходным кодом некоторых инсталляторов с открытым исходным кодом, например. NSIS или Inno Setup. Они делают это уведомление правильно. – bialix

+6

Один маленький быстрый совет, вы можете показать содержимое PATH в командной строке, просто набрав «путь» и нажав enter. Сохраняет вам 7 нажатий клавиш на тест (9 отсчет смены)! – Todd

+0

Ах, вы должны создать приложение Unicode, поэтому 'windows.h' вносит в Unicode версию API (' SendMessageTimeoutW'), для чего потребуется 'LPCWSTR' для' LPARAM' вместо 'LPCSTR'. Я думаю, что если вы хотите поддерживать как «ANSI», так и Unicode-сборки, тогда правильная вещь - использовать «LPCTSTR» (т. Е. С помощью макроса '_T()»). Возможно, моя библиотека могла использовать обновление, чтобы сделать его «Unicode aware». В настоящее время он поддерживает только настройку переменных среды с помощью «ANSI», что может быть проблематичным, если вам нужен каталог с, скажем, кириллическими символами на вашем пути. –

ответ

11

Получается, действительно, не ничего нового под солнцем. Это уже было сделано раньше, по крайней мере, один раз. Мной. Я создал DLL, очень похожую на то, что вы описали, для той же цели (для использования в изменении пути от установщика NSIS). Он используется установщиком Visual Leak Detector.

DLL называется editenv.dll. The source доступен в github. Я просто протестировал установщик, и он обновил систему переменная среды PATH, без проблем. Основываясь на том, что вы написали, я не вижу ничего, что выделяется как неправильное. Я также не вижу ничего очевидного, чего не хватает. Но может быть стоит посмотреть на источник editenv.dll (вас больше всего интересует EnvVar::set() в EnvVar.cpp и, возможно, и pathRemove() C API в editenv.cpp).

+0

Спасибо за код Dan! Даже я не мог найти свое конкретное решение, посмотрев на ваш код, ваш ответ будет очень полезен будущим читателям этого вопроса. –

0

У меня есть программа, которая вызывает тот же API Win32, что и для обновления среды, и работает отлично.

. Осторожно, что как вы открываете командную строку.

Если открыть окно командной строки, делая это:

Start -> Run -> cmd.exe 

тогда среда в строке показывает, что новая переменная установлена.

Однако у меня также есть программируемый функциональный ключ на моей клавиатуре, который я установил для запуска процесса cmd.exe. Если я открою командную строку с помощью этой функциональной клавиши, а затем введите env, она не покажет переменную как установленную.

Я не уверен, почему он работает по-другому, но он должен иметь какое-то отношение к способу запуска процесса cmd.exe (хотя оба пользователя работают под моим именем пользователя, а не SYSTEM).

Как вы открываете командную строку?

+4

Программа, управляющая программируемыми функциональными клавишами, запускает CMD.EXE со своей собственной копией среды, которая не была обновлена, если вы не перезапустили ее после изменения дорожка. – Todd

+0

Интересно. Я начал свое приглашение командной строки, нажав «Командная строка» в моем стартовом меню. Это ярлык, который поставляется с Windows, в меню «Аксессуары», которое я «приколол» к меню «Пуск». Цель -% SystemRoot% \ system32 \ cmd.exe –

+0

@Todd - да, это звучит правильно. Хороший анализ! @David - Любая разница, если вы запускаете cmd.exe из Start-> Run? – LeopardSkinPillBoxHat

Смежные вопросы