最近遇到一个问题, 一个程序 A 使用 CreateProcess 和 ShellExecute 的方式调用另外一个程序 B 启动, 程序 B 启动后, 使用 GetEnvironmentVariable 读取到的环境变量只有程序 A 启动时从系统里加载的环境变量.
有什么方法可以从系统中重新读取环境变量回来吗? 尝试过读取注册表, 但是一些用户没有权限去查, 限制比较多.
1
ysc3839 2022-11-25 15:57:16 +08:00
用 CreateEnvironmentBlock
https://learn.microsoft.com/en-us/windows/win32/api/userenv/nf-userenv-createenvironmentblock |
2
lonelyparasol OP @ysc3839 看起来可以, 我去试试, 基于用户的 token 去重新获取, 感谢.
|
3
JohnBull 2022-11-25 23:17:16 +08:00
这完全违背了环境变量的设计初衷。
你这是在强行用环境变量实现配置文件的功能。 |
4
FrankHB 2022-11-26 06:27:34 +08:00
@JohnBull 这哪来的设计初衷?又哪看出了 OP 要的是配置文件的功能?
照你的说法是不是 Windows 系统属性里设置环境变量的界面也是违反初衷,该改用配置文件? (要是非得把注册表当配置文件,行吧,当我没说。) |
5
ysc3839 2022-11-26 20:36:47 +08:00 via Android
@JohnBull 环境变量的设计初衷不就是子进程可以继承的配置文件吗?
很多 Docker 镜像都是用环境变量来当配置文件的。 |
6
JohnBull 2022-11-27 00:01:41 +08:00
@ysc3839 环境变量的设计初衷恰恰是让子进程能够继承父进程的参数,而不是遵从全局的,形成一个配置一致的进程树。如果你想要跳过环境变量实现一个全局的配置,那当初就应该使用配置文件,或者设计相应的命令行参数。而不是思考如何加载爷爷进程的环境变量……不是说做不到,而是这种设计实在是太拧吧了
通常,UNIX 应用程序历史悠久的配置原则是: 代码写死的默认值 < 全局配置文件 < 进程环境变量 < 命令行参数 对于同一个参数的值,采用后面覆盖前面的策略,清晰有效 |
7
ysc3839 2022-11-27 00:54:22 +08:00 via Android
@JohnBull #6 你说的这段话没问题,环境变量其中之一的作用确实是能让父进程覆盖子进程的参数。要跳过环境变量实现全局配置的话,确实是用配置文件更好。但是这跟 OP 的需求有什么关系呢? OP 这种需求显然就是不想跳过环境变量,想让子进程使用全局的环境变量。
|
8
JohnBull 2022-11-27 16:11:31 +08:00
@ysc3839 我在 6 楼提出来了:这种场合可以为这个配置项添加命令行参数,或者在 exec 子进程的时候删除特定环境变量,从而让配置文件 /默认值能够显现出来
|
9
julyclyde 2022-11-27 16:48:20 +08:00
并不存在“系统”环境变量这个概念
环境变量都是进程级别的 |
10
ysc3839 2022-11-27 20:24:00 +08:00 via Android
|
11
JohnBull 2022-11-27 22:16:13 +08:00
@ysc3839 什么乱七八糟的啊。你究竟是子进程的开发者还是父进程的开发者?如果你是子进程的开发者,你就应该加上命令行参数或者干脆不采納环境变量而采纳配置文件甚至默认值;如果你是父进程的开发者,你就不应该在这时候设置环境变量。还不清楚吗?再说谁说 shell 不能设置环境变量的啊?
|
12
julyclyde 2022-11-28 08:22:05 +08:00
@ysc3839 是否接受命令行参数,也不影响“不存在‘系统’环境变量这个概念”的事实啊
需要在已有规则下做事。颠覆规则的话需要重新做一套操作系统了,代价不合适的 你的某种意义上的环境变量是依赖于进程启动的传承关系的。从交互式 shell 、登录 shell 启动,和从后台启动的情况都不一样,回头换个情况你又要遇到相同的问题。不要总是妄图从外围解决内部的问题 |
13
lonelyparasol OP 上面两位不要吵了, 我这个需求的初衷是有个程序 A 在一直执行的, 偶尔有新安装的软件会添加系统环境变量.
程序 A 会根据用户需求, 创建进程或者线程去调用这些新安装的软件, 所以需要新创建的进程或线程自己的系统环境变量是最新的. 使用窗口消息 WM_SETTINGCHANGE 和读取配置文件都有局限性, 我也是苦恼了好久. |
14
lonelyparasol OP 用 CreateEnvironmentBlock 方式, 需要知道用户的帐号和密码, 也是有局限性.
目前在尝试用 CMDB 设置计划任务, 看是否能重新加载系统的环境变量 |