ilovecomputer66 发表于 2023-6-21 09:23

C# 通过注册表修改系统环境变量后,究竟怎么做才能不重启生效(试过网上各种办法无效)

本帖最后由 ilovecomputer66 于 2023-6-21 09:47 编辑

首先,如果是手工在系统环境变量设置界面,手工修改,只要点击了确定就会立即生效,无需重启电脑,而且连重启exploer.exe都不需要

但是我用C#通过修改注册表修改了环境变量,却无法生效。。。用尽网上说的下面各种办法,都不行

1、网上有说,用C#提供的Environment.SetEnvironmentVariable("JAVA_HOME", "%JAVA_HOME_17%", EnvironmentVariableTarget.Machine);   就能生效

    首先,他根本不会生效。另外这个函数本来就有缺陷,它不支持 %xx% 这样引用其他环境变量的,因为这种,在注册表中叫 ExpendString类型,而这个函数设置的只能是string。

2、网上说   调用   SendMessage((IntPtr)HWND_BROADCAST, WM_SETTINGCHANGE, IntPtr.Zero, IntPtr.Zero);   可以刷新,结果没用
3、网上说调用      SHChangeNotify(0x08000000, 0x0000, IntPtr.Zero, IntPtr.Zero);    可以刷新,结果没用
4、网上说重启 exploer.exe 就可以,结果胡说八道,根本没用
5、网上说在CMD下执行 set xxx = xxx 能直接生效,结果发现连环境变量都设不了,恐怕只是在当前临时CMD中设置一个变量而已

so,系统环境变量设置界面,究竟还做了啥,使得能立即生效的? 求大佬指点

EnterpriseSolu 发表于 2023-6-21 10:36

The environment variables are cached when a process starts.Unless the process itself changes them they will not be visible until the process restarts.In your case the batch file (running in a separate process) will update the env vars but the main process won't be able to see the changes.There isn't a workaround short of making the same changes in the main process.However if all you want to do is confirm that the env vars were changed then you can run another process that confirms the env vars were changed properly.All new processes would get the new env vars.

给你找到原因了

EnterpriseSolu 发表于 2023-6-21 10:37

来自这里,
https://social.msdn.microsoft.com/Forums/vstudio/en-US/acf2d0f3-143e-4ba5-acdc-76a70a5c9830/environment-variables-refresh?forum=csharpgeneral
When an application is started it "inherits" the environment of the calling process.The environment variables aren't cached, they're copied.GetEnvironmentVariable makes repeated requests to the system for that environment variable for the process; but it's for that process, not the parent.   There's no way to see changes to process environment variables of the parent process unless it has explicitly given you access to them, something which the command prompt does/can not do.



You could write a small console app that you could use for setting user-wide environment variables using Environment.SetEnvironmentVariable(string variable, string value, EnvironmentVariableTarget target) (where EnvironmentVariableTarget is User) and then get those environment variables with GetEnvironmentVariable(String, EnvironmentVariableTarget target).I don't recommend that; if you have to go to the trouble of writing another app to set env. variables, it's probably better to use accepted inter-process communications methods available in .NET.

今天是周五吗 发表于 2023-6-21 10:47

如果是要指定 “%%“ 那确实需要REG_EXPAND_SZ 这种类型才可以
如果是第三方加载dll这种场景 更改完环境变量可以杀掉所有的 rundll32.exe进程 再重启资源管理器

ilovecomputer66 发表于 2023-6-21 11:48

今天是周五吗 发表于 2023-6-21 10:47
如果是要指定 “%%“ 那确实需要REG_EXPAND_SZ 这种类型才可以
如果是第三方加载dll这种场景 更改完环境 ...

我试过用C#代码改完后,重启explorer,可以在新开的系统CMD中,获取java- version,仍旧是返回旧的

但只要打开系统环境变量设置界面,点击确定(什么都不改,就是只点确定),然后在新开CMD就发现java -version已经刷新了。而这个过程windows完全没有重启explorer

可见,你说的这种方法做不到。而windows本身也没有用你这种方法来做

我感觉还有有另外的通知函数,通知去改变了

ilovecomputer66 发表于 2023-6-21 11:51

EnterpriseSolu 发表于 2023-6-21 10:36
The environment variables are cached when a process starts.Unless the process itself changes them...

那为什么在系统环境变量设置界面,修改的就可以呢?
我感觉还有有另外的通知函数,通知去改变了
它这个回复,我感觉也没有触及根本,即windows怎么做到的在系统环境变量设置界面,修改的就可以立马生效,也没见windows重启explorer什么的

EnterpriseSolu 发表于 2023-6-21 12:00

“我感觉还有有另外的通知函数,通知去改变了”
你可以用Sysinternals_Suite的process monitor去探测背后的动作

BLUE7777777 发表于 2023-6-21 12:24

曾经我用PowerShell试验Java配置成功过,但是没有想到C#操作,回头验证下!

ilovecomputer66 发表于 2023-6-21 13:16

本帖最后由 ilovecomputer66 于 2023-6-21 13:17 编辑

EnterpriseSolu 发表于 2023-6-21 12:00
“我感觉还有有另外的通知函数,通知去改变了”
你可以用Sysinternals_Suite的process monitor去探测背 ...
你确定可以么?为什么我用它监测不到呢?(或者我方法不对),兄弟可否试下你那里真的可以??

而且这个软件我一直在用,但我一直看它功能是监控文件读写、注册表变动。系统内部的通知函数啥的,它怎么能监测呢?这种系统压根不可能对外暴露还能被随便一个软件想hook就hook吧

pdone 发表于 2023-6-21 13:18

可以尝试一下重启资源管理器后是否生效。
在C#中,可以使用Process类来启动和停止进程。要重启资源管理器,可以使用以下代码:

```C#
using System.Diagnostics;

// 获取资源管理器进程
Process[] processes = Process.GetProcessesByName("explorer");

// 停止资源管理器进程
foreach (Process process in processes)
{
    process.Kill();
}

// 启动资源管理器进程
Process.Start("explorer.exe");
```
这段代码首先使用GetProcessesByName方法获取所有名为“explorer”的进程,然后使用Kill方法停止这些进程。最后,使用Start方法启动资源管理器进程。请注意,这段代码需要管理员权限才能停止和启动资源管理器进程。
页: [1] 2 3 4
查看完整版本: C# 通过注册表修改系统环境变量后,究竟怎么做才能不重启生效(试过网上各种办法无效)