Windows编程----进程:环境变量

news/2025/3/11 4:15:56/文章来源:https://www.cnblogs.com/caoruipeng/p/18759311

什么是系统环境变量

每台计算机针对当前用户和系统中所有用户分别提供了两个环境变量设置,通过计算机属性>环境变量的界面,我们可以查看当前这台计算机上的所有环境变量,这些环境变量都是key-value键值对。具体如下:

上面看到的环境变量其实是存储在注册表中的,

系统环境变量存储在计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment路径下,

用户环境变量存储在计算机\HKEY_CURRENT_USER\Environment路径下

如下两张图分别是注册表中环境变量的值:

什么是进程环境变量

我们知道,进程本质上就是一块很大的地址空间。这个地址空间分为很多个内存区。包含代码区、DLL程序集代码区、全局变量区域、线程堆栈区等。那么进程环境变量(注意这个和上面提到的系统环境变量不同)本质上也是分配在进程内存空间上的一个字符串。这个字符串的格式如下:

=::=::\0Var1=Value1\0 Var2=Value2\0 Var3=Value3\0 ... VarN=ValueN\0\0

字符串中每个环境变量的格式为key=value,变量之间用\0区分。同时环境变量字符串必须以两个\0结束。也就是以\0\0结尾。注意:对于环境变量开始的=::=::\我们可以忽略,以=号开头的所有环节变量都会被忽略掉。

默认情况下,当进程启动的时候,会将系统环境变量加载到进程的环境变量中,我们可以使用ProcessExplorer这个工具查看进程的环境变量。我们运行下面这个简单的C++控制台程序,然后打开ProcessExplorer工具找到指定进程,然后右键Properties查看属性,选中Environment这一列,就可以看到系统环境变量都被加载到了进程的环境变量中。

#include <iostream>
#include <Windows.h>
int main()
{while (true) {Sleep(1000);}return 0;
}

从上图可以很明显看到系统环境变量都被加载到了进程环境变量,同时这里有几个点需要我们注意:

1、用户变量和系统变量如果名称一致的时候,会以用户变量为准(Path变量除外),比如说,我们看到用户变量和系统变量中都有TEMP这个环境变量,并且它们的值是不同的,在用户变量中取值为:C:\Users\caoruipeng\AppData\Local\Temp,但是在系统变量中取值为:C:\Users\caoruipeng\AppData\Local\Temp,在最终的进程环境变量中,我们可以很明显看到TEMP的值为C:\Users\caoruipeng\AppData\Local\Temp。具体如下图:

2、Path这个环境变量比较特殊,用户变量和系统变量中都有这个变量,但是程序不会按照上面的规则直接以用户变量中的变量值为准。而是将两个变量的变量值合并在一起作为最终的环境变量值,不同路径之间用分号区分。具体我们可以自己查看。

3、当我们新增了用户变量和环境变量之后,一般需要重启机器或者注销重启才能使环境变量生效,这也是为什么有时候我们新增了环境变量,但是在程序中并没有读取到那个环境变量的原因。

4、进程环境变量只是系统环境变量的副本,对进程环境变量的修改并不会影响到系统环境变量。除非用户通过GUI手动修改系统环境变量。

访问进程环境变量

程序可以通过GetEnvironmentVariable 和SetEnvironmentVariable获取或者设置环境变量的值。注意:SetEnvironmentVariable函数只会修改当前进程的环境变量,而不会修改系统环境变量或其他进程的环境变量。也就是说,使用 SetEnvironmentVariable 设置的环境变量只在当前进程及其子进程中有效。

下面的代码,我们获取到环境变量OneDrive的值,然后修改这个环境变量的值,并重新打印出来。

#include <iostream>
#include <Windows.h>int main()
{// 定义环境变量名LPCWSTR envVarName = L"OneDrive";// 分配缓冲区,接受环境变量值std::wstring envVarValue(1024, L'\0');// 获取环境变量值的长度DWORD bufferSize = GetEnvironmentVariable(envVarName, &envVarValue[0], 1024);// 输出环境变量值std::wcout << envVarName << L" = " << envVarValue << std::endl;// 修改环境变量的值LPCWSTR newEnvVarValue = L"NewValue";if (SetEnvironmentVariable(envVarName, newEnvVarValue) == 0) {std::cerr << "Failed to set environment variable." << std::endl;return 1;}// 再次获取并输出修改后的环境变量值envVarValue.assign(1024, L'\0');bufferSize = GetEnvironmentVariable(envVarName, &envVarValue[0], 1024);std::wcout << envVarName << L" = " << envVarValue << std::endl;return 0;
}

调试程序之后,执行结果如下:可以看到,正确的输出了环境变量OneDrive的值为C:\Users\caoruipeng\OneDrive。

重置环境变量

上面我们提到,进程启动的时候,会将系统环境变量全部加载到了内存中,如果我们不需要这些系统环境变量的话。可以通过SetEnvironmentStrings可以设置当前进程的环境变量块,通过GetEnvironmentStrings可以获取我们设置的环境变量块,当然通过GetEnvironmentVariable也可以获取到指定环境变量的值,下面我们用代码来演示一下:

#include <iostream>
#include <Windows.h>
int main()
{    // 定义新的环境块LPCWSTR newEnvStrings = L"VAR1=Value1\0VAR2=Value2\0\0";// 设置新的环境块SetEnvironmentStringsW((LPWCH)newEnvStrings);while (true) {Sleep(1000);}return 0;
}

运行控制台程序之后,我们重新在ProcessExplorer中查看进程的环境变量,就会发现进程的环境变量只剩下两个VAR1和VAR2,和我们程序中设置的一样。请看下图:

下面的代码我们首先设置整个进程的环境变量块,然后通过GetEnvironmentStrings获取整个环境变量块,并且输出:

 

#include <iostream>
#include <Windows.h>int main()
{// 定义新的环境块LPCWSTR newEnvStrings = L"VAR1=Value1\0VAR2=Value2\0\0";// 设置新的环境块SetEnvironmentStringsW((LPWCH)newEnvStrings);// 获取当前进程的环境块LPWCH envStrings = GetEnvironmentStringsW();// 遍历并输出所有环境变量LPWCH current = envStrings;while (*current) {std::wcout << current << std::endl;current += wcslen(current) + 1;}// 定义环境变量名LPCWSTR envVarName = L"VAR1";// 分配缓冲区,接受环境变量值std::wstring envVarValue(1024, L'\0');// 获取环境变量值的长度DWORD bufferSize = GetEnvironmentVariable(envVarName, &envVarValue[0], 1024);std::wcout << envVarName << L" = " << envVarValue << std::endl;// 释放环境块FreeEnvironmentStringsW(envStrings);return 0;
}

调试程序之后,执行结果如下:可以看到GetEnvironmentVariable可以成功获取到VAR1的环境变量值

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/895511.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

软工作业二:个人项目

| 这个作业属于哪个课程 | 软件工程 | | 这个作业要求在哪里 | 作业要求 | | 这个作业的目标 | 设计一个论文查重算法,给出一个原文文件和一个在这份原文上经过了增删改的抄袭版论文的文件,在答案文件中输出其重复率。 | 一、使用说明📝 1.使用环境:c++;Visual studio 20…

[T.1] 团队项目:团队成员介绍

组一辈子杰队项目 内容这个作业属于哪个课程 2025年春季软件工程(罗杰、任健)这个作业的要求在哪里 [T.1] 团队项目:团队成员介绍我在这个课程的目标是 学习软件工程理论与实践,完成一款高质量的软件项目这个作业在哪个具体方面帮助我实现目标 确定分工,团队破冰,初步确定…

阿里二面:10亿级分库分表,如何丝滑扩容、如何双写灰度?阿里P8方案+ 架构图,看完直接上offer!

本文的 原始地址 ,传送门 本文的 原始地址 ,传送门 尼恩说在前面 在40岁老架构师 尼恩的读者交流群(50+)中,最近有小伙伴拿到了一线互联网企业如阿里、滴滴、极兔、有赞、希音、百度、网易、美团的面试资格,遇到很多很重要的面试题:每天新增100w订单,如何的分库分表? 1…

递归?动态规划?几道题帮你理清楚基本思路!—— 一维动态规划解析

动态规划定义 动态规划(Dynamic Programming,简称 DP)是解决最优化问题的一种重要算法思想。它通过将原问题分解为多个子问题,逐步求解子问题,最终合并子问题的解来解决原问题。动态规划在解决具有重叠子问题和最优子结构性质的问题上非常高效,常用于路径规划、背包问题、…

ABAP-后台Job相关(转)

定义JOB 查看作业日志 查看JOB变式动态日期变式设置 如果有其他的动态参数设置,建议程序中调用JOBDATA:lv_job_name LIKE tbtco-jobname, "作业名lv_job_nr LIKE tbtco-jobcount, "作业号lv_job_released TYPE c,lv_job_start_so…

在Android Studio上完成一个简单的添加项目(累死了!)

所花时间:7h 代码量(行):430 博客量:5 了解的知识点: 真的累死娃了快 昨天需要完成从web端转向Andriod端的小项目,对于已经明白的来说这是挺容易的(我现在是这样觉得的), 但是昨天什么都不知道,从哪里开始都不了解,只能问AI,一开始是依托于IDEA上进行项目搭建和实…

逆向新手 WriteUp

WriteUp 题目信息 名称:逆向新手.exe 分类:Reverse 描述:找到程序的flag题目链接: https://pan.baidu.com/s/1u8bGbKcUF6_gLaw63L3jyA?pwd=h8r5 提取码: h8r5解题思路 首先用DIE对文件查壳,发现是一个无壳的32位程序。于是直接用32位IDA对文件进行反汇编,得到如下伪代码:…

P3243 [HNOI2015] 菜肴制作(图论)

P3243 [HNOI2015] 菜肴制作 题目描述 知名美食家小 A 被邀请至 ATM 大酒店,为其品评菜肴。ATM 酒店为小 A 准备了 \(n\) 道菜肴,酒店按照为菜肴预估的质量从高到低给予 \(1\) 到 \(n\) 的顺序编号,预估质量最高的菜肴编号为 \(1\)。 由于菜肴之间口味搭配的问题,某些菜肴必…

第一章课后作业

r = float(input("请输入圆的半径:")) area = 3.1415r r print(area)str1 = input("请输入一个人的名字:") str2 = input("请输入一个国家的名字:") print("世界这么大,{}想去{}看看.".format(str1,str2))n = input("请输入整…

Landsat遥感影像分幅条带介绍与矢量下载:WRS的Path与Row

本文介绍Landsat系列卫星的分幅规则,并提供WRS的矢量文件下载~本文介绍Landsat系列卫星的分幅规则,并提供WRS的矢量文件下载。WRS,即Worldwide Reference System,是Landsat系列卫星全球影像标记符号系统,用以区分全球各区域对应的Landsat系列卫星影像编号;其用“Path”与…

Manus爆火,是硬核还是营销?

Manus是一款引发热议的通用Agent产品,凭借强大任务处理能力及营销手段备受关注,其爆火带动了开源复刻潮,并为垂直领域智能体开发提供灵感,如图数据库智能体Chat2Graph。相信这两天小伙伴们应该被Manus刷屏了,铺天盖地的体验解读文章接踵而来,比如「数字生命卡兹克」凌晨爆…