经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 数据库/运维 » Windows » 查看文章
设置环境变量遇到的难题,cmd管理员方式与普通方式的区别,通过C#代码设置环境变量
来源:cnblogs  作者:黑衫老腰  时间:2019/9/2 9:20:25  对本文有异议

在使用mingw64的过程中,需要手工添加环境变量,作为一个懒人,这怎么可以呢?于是想用命令的方式实现,结果遇到问题了,死活实现不了,

之前用过TDM-GCC,人家的安装完就可以用,还有试用过rust,人家在安装程序中已经明确告诉了会在注册表添加修改路径(HKEY_CURRENT_USER\Environment->Path),也是安装完就可以用,

他们都是怎么实现的?搜遍全网,也没有找到解决方案,下面总结一下我的测试结论:

用户变量在 HKEY_CURRENT_USER\Environment->Path
系统变量在 HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Session Manager\Environment
      或者 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment
ControlSet001:系统真实的配置信息。
CurrentControlSet:运行时配置。windows启动时会从ControlSet001复制一份副本,作为操作系统当前的配置信息。
      我们对于计算机配置所作的修改都是直接写入到 CurrentControlSet,
      在重启过程中,windows会用CurrentControlSet的内容覆盖掉ControlSet001,以保证这两个控件组一致。

----------------------------------------------------------------------------------------------------------------------

在我的电脑->系统设置->环境变量界面,用户变量或系统变量的path字段,手工添加,输入设置的路径,
在注册表HKCU\Environment(用户变量)、ControlSet001或CurrentControlSet(系统变量)会立即出现,且在新打开的命令行窗口立即有效

而在cmd窗口中set设置的环境变量为临时变量,如:set PATH=%PATH%;C:\mingw64
结论:以命令行方式对环境变量的操作只对当前窗口的应用有效,关闭窗口即消失!
----------------------------------------------------------------------------------------------------------------------

使用setx设置为永久环境变量,适用于bat中:
@setx PATH "%PATH%;%~dp0bin" /m
/m:设置计算机环境(需以管理员权限运行),即系统变量,默认设置是用户环境,即用户变量。
尽管使用了/m,%PATH%本身还是会读取所有的变量,即系统变量和用户变量,还会把系统路径变量替换为具体值。
C:\WINDOWS\system32>SETX MYPATH "%PATH%" /m
警告: 正保存的数据被裁断到 1024 字符。
成功: 指定的值已得到保存。
C:\WINDOWS\system32>setx PATH "%PATH%;C:\mingw64" /m
警告: 正保存的数据被裁断到 1024 字符。
成功: 指定的值已得到保存。
结论:可以设置成功系统变量,并进入注册表,但是默认是短字符串类型REG_SZ,而系统的path是长字符串类型REG_EXPAND_SZ;
      系统的REG_EXPAND_SZ类型path被替换为REG_SZ类型path,被裁断造成路径丢失,此方法完全行不通。
------------------------------------------------------------------------------------------------------------------------------
在cmd命令行下使用wmic永久修改Windows环境变量
获取 Temp 环境变量的用户和变量值
    wmic ENVIRONMENT where name="Temp" get UserName,VariableValue
修改 OS 环境变量值为Windows_NT,这会覆盖掉原有的变量值
    wmic ENVIRONMENT where name="os" set VariableValue="Windows_NT"
新增系统环境变量 myTemp,值为 %OS%%SystemDrive%
    wmic ENVIRONMENT create name="myTemp",username="<system>",VariableValue="%OS%%SystemDrive%"
删除 myTemp 环境变量
    wmic ENVIRONMENT where "name='myTemp'" delete
用法说明:
1、where关键字后跟的参数必须是一个连续的字符串,如果参数字符串含有空格需要用英文双引号"将参数括起来,
若字符串中有多个限定词,比如既有 name 又有 username,则需要使用 and 关键字来连接这些限定词。
       
2、在读取环境变量值时不需要管理员权限,但在创建、写入环境变量值时必须具备管理员权限。
修改 PATH 环境变量值,新增路径 C:\tcc
    wmic ENVIRONMENT where "name='PATH' and username='<system>'" set VariableValue="%PATH%;C:\mingw64"
结论:在新打开的命令行窗口有效,
      %PATH%本身还是会读取所有的变量,即系统变量和用户变量,还会把系统路径变量替换为具体值,此方法不可取
------------------------------------------------------------------------------------------------------------------
结论:ControlSet001或CurrentControlSet改一处则另一处同时变
      直接修改注册表ControlSet001或CurrentControlSet(或HKCU\Environment),在系统设置-环境变量界面立即出现,
      但命令行窗口中只有以管理员权限运行才生效,普通模式必须重启才能生效(不重启的话每次打开cmd都得执行set命令才生效)。
      另:图形界面的路径删除后注册表和命令行窗口同时立即起作用,即路径同时消失,
      但注册表删除后,图形界面立即有效即消失,只有管理员命令行窗口立即有效,普通模式路径仍然可用,必须重启才能生效消失
      普通命令行窗口怎么才能立即生效呢,总是慢半拍,是何原因呢?
===================================================================
最近总算找到原因了,原来需要发一个全局的广播:
C\C++: SendMessage(HWND_BROADCAST,WM_SETTINGCHANGE,0,(LPARAM)TEXT("Environment"));
或者 SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM)TEXT("Environment"), SMTO_ABORTIFHUNG, 5000, 0);
 C#里实现代码如下:
  1. const int HWND_BROADCAST = 0xffff;
  2. const int WM_SETTINGCHANGE = 0x001A;
  3. public enum SendMessageTimeoutFlags : uint
  4. {
  5. SMTO_NORMAL = 0x0000,
  6. SMTO_BLOCK = 0x0001,
  7. SMTO_ABORTIFHUNG = 0x0002,
  8. SMTO_NOTIMEOUTIFNOTHUNG = 0x0008
  9. }
  10. [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
  11. public static extern IntPtr SendMessageTimeout(IntPtr hWnd, uint Msg, IntPtr wParam, string lParam,
  12. SendMessageTimeoutFlags flags, uint timeout, out IntPtr result);
  13. static void SetUserPath(string path) //设置用户环境变量
  14. {
  15. RegistryKey registryKey = Registry.CurrentUser.OpenSubKey(@"Environment", true);
  16. Console.WriteLine("Path: {0} {1}", registryKey.GetValue("Path"), registryKey.GetValueKind("Path"));
  17. registryKey.SetValue("Path", registryKey.GetValue("Path") + path, RegistryValueKind.ExpandString);
  18. SendMessageTimeout(new IntPtr(HWND_BROADCAST), WM_SETTINGCHANGE, IntPtr.Zero, "Environment",
  19. SendMessageTimeoutFlags.SMTO_ABORTIFHUNG, 5000, out IntPtr result);
  20. Console.WriteLine("result: {0}", result);
  21. }
  22. static void SetSystemPath(string path) //设置系统环境变量
  23. {
  24. String subKeyPath = @"SYSTEM\CurrentControlSet\Control\Session Manager\Environment";
  25. RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(subKeyPath, true); //需要管理员权限运行
  26. Console.WriteLine("Path: {0} {1}", registryKey.GetValue("Path"), registryKey.GetValueKind("Path"));
  27. registryKey.SetValue("Path", registryKey.GetValue("Path") + path, RegistryValueKind.ExpandString);
  28. SendMessageTimeout(new IntPtr(HWND_BROADCAST), WM_SETTINGCHANGE, IntPtr.Zero, "Environment",
  29. SendMessageTimeoutFlags.SMTO_ABORTIFHUNG, 5000, out IntPtr result);
  30. Console.WriteLine("result: {0}", result);
  31. }
  32. //手动修改环境变量时,系统自动维护其类型,长度较短时为REG_SZ(String),达到一定长度后为REG_EXPAND_SZ(ExpandString)
  33. //REG_SZ型注册表值项的名称是长度固定的文本字符串,最大长度不能超过255个字符;REG_EXPAND_SZ是长度可变的数据字符串。

 调用代码:

  1. SetUserPath(@"C:\tcc");
  2. SetSystemPath(@"C:\tcc"); //需要管理员权限

 

原文链接:http://www.cnblogs.com/chengyb/p/11438682.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号