以编程方式将目录添加到 Windows PATH 环境变量
我正在编写一个 Win32 DLL,其函数将目录添加到 Windows PATH 环境变量(将在安装程序中使用)。
DLL 运行后查看 Regedit 或控制面板中的环境变量表明我的 DLL 已成功将路径添加到 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment
和 HKEY_CURRENT_USER\Environment
。
但是,当我启动新的命令提示符时(运行 DLL 后),我添加的目录不会显示在 echo %PATH%
的输出中,并且我无法访问该目录中的可执行文件目录,通过键入其名称。
我认为我的程序没有很好地通知系统 PATH 已更改,或者可能是在更改完全生效之前通知它们。我读了一篇 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 操作系统上运行。
更新:我上面发布的代码的问题是我没有在“Environment”字符串上添加 L 前缀。尽管在我能找到的 Microsoft 文档中没有明确说明,但 LPARAM 需要是指向 WCHAR 字符串(2 字节字符)的指针,而不是 CHAR 字符串,这是 Visual Studio 编译器默认生成的字符串当我写一个字符串文字时。我的问题的解决方案是将“Environment”更改为“L”Environment”。 (我以为在发布这个问题之前我已经尝试过了,但显然我没有正确尝试!)但是任何想要完成此任务的 C++ 解决方案的人都应该看看 Dan Moulding 的答案。
I'm writing a Win32 DLL with a function that adds a directory to the Windows PATH environment variable (to be used in an installer).
Looking at the environment variables in Regedit or the Control Panel after the DLL has run shows me that my DLL has succeeded in adding the path to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment
and HKEY_CURRENT_USER\Environment
.
But when I start up a new Command Prompt (after running the DLL), the directory I added does not show up in the output of echo %PATH%
and I can not access the executable that lives in that directory by typing its name.
I think my program is not doing a good job of notifying the system that the PATH has changed, or maybe it is notifying them before the change has fully taken effect. I read an article by Microsoft that says to broadcast the WM_SETTINGCHANGE
message after changing an environment variable, and I am doing that with this code:
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 ... */ }
The order of my calls is: RegCreateKeyEx
, RegSetValueEx
, RegCloseKey
, SendMessageTimeout
If I press "OK" in the Control Panel "Environment Variables" window, the changes made by my DLL to the PATH show up in newly-created command prompts, so there is something that the Control Panel is doing to propagate PATH changes; I want to figure out what it is and do the same thing.
Does anyone know what I should do?
I'm running 64-bit Windows Vista but I want this to work on all Windows XP, Vista and Windows 7 operating systems.
Update: The problem with the code I posted above is that I did not put the L prefix on the "Environment" string. Although it does not say it explicitly anywhere in the Microsoft documentation that I can find, the LPARAM needs to be a pointer to a WCHAR string (2-byte characters) as opposed to a CHAR string, which is what Visual Studio's compiler generates by default when I write a string literal. The solution to my problem was to change "Environment" to L"Environment". (I thought I already tried that before posting this question, but apparently I didn't try it correctly!) But anyone who wants a complete C++ solution for this task should look at Dan Moulding's answer.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
事实证明,太阳底下确实没有什么新鲜事。这以前已经做过,至少一次。由我来。我创建了一个与您所描述的非常相似的 DLL,目的完全相同(用于修改 NSIS 安装程序的路径)。它由 Visual Leak Detector 安装程序使用。
该 DLL 称为 editenv.dll。 源代码可在 github 上找到。我刚刚测试了安装程序,它更新了系统 PATH 环境变量,没有问题。根据您所写的内容,我没有发现任何明显错误的地方。我也没有看到任何明显缺失的东西。但可能值得一看 editenv.dll 源代码(您对 EnvVar.cpp,以及可能的
pathAdd()
和pathRemove()
C API在 editenv.cpp 中)。It turns out there really isn't anything new under the sun. This has already been done before, at least once. By me. I created a DLL very much like what you describe for exactly the same purpose (for use in modifying the path from an NSIS installer). It gets used by the Visual Leak Detector installer.
The DLL is called editenv.dll. The source is available at github. I just tested the installer and it updated the system PATH environment variable, no problem. Based on what you've written, I don't see anything that stands out as being wrong. I also don't see anything obvious that's missing. But it may be worth a look at the editenv.dll source (you'd be most interested in
EnvVar::set()
in EnvVar.cpp, and possibly thepathAdd()
andpathRemove()
C APIs in editenv.cpp).我有一个程序可以调用与您相同的 Win32 API 来更新环境,并且运行良好。
需要注意的一件事是如何打开命令提示符。
如果您通过执行以下操作打开命令提示符:
那么提示符中的环境将显示新变量已设置。
不过,我的键盘上还有一个可编程功能键,我已将其设置为运行
cmd.exe
进程。如果我通过该功能键打开命令提示符,然后输入env
,它不会显示正在设置的变量。我不确定为什么它的工作方式不同,但它一定与
cmd.exe
进程的启动方式有关(尽管两者都在我的用户名下运行,而不是SYSTEM< /代码>)。
你如何打开命令提示符?
I have a program which calls the same Win32 API to yours to update the environment, and it works fine.
One thing to be careful of is how you are opening up the command prompt.
If you open up the command prompt by doing this:
then the environment in the prompt shows that the new variable is set.
However, I also have a programmable function key on my keyboard which I have set to run the
cmd.exe
process. If I open a command prompt via that function key and then typeenv
, it doesn't show the variable as being set.I'm not sure why it works differently, but it must have something to do with the way the
cmd.exe
process is launched (although both are running under my user name, notSYSTEM
).How are you opening up the command prompt?