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

什么是系统环境变量

每台计算机针对当前用户和系统中所有用户分别提供了两个环境变量设置,通过计算机属性>环境变量的界面,我们可以查看当前这台计算机上的所有环境变量,这些环境变量都是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这一列,就可以看到系统环境变量都被加载到了进程的环境变量中。

arduino 复制代码
#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手动修改系统环境变量。

访问进程环境变量

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

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

c 复制代码
#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也可以获取到指定环境变量的值,下面我们用代码来演示一下:

arduino 复制代码
#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获取整个环境变量块,并且输出:

c 复制代码
#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的环境变量值

相关推荐
程序员编程指南1 小时前
Qt 网络编程进阶:RESTful API 调用
c语言·网络·c++·qt·restful
程序员编程指南1 小时前
Qt XML 与 JSON 数据处理方法
xml·c语言·c++·qt·json
qyhua2 小时前
Windows 平台源码部署 Dify教程(不依赖 Docker)
人工智能·windows·python
Algebraaaaa2 小时前
【C++基础】指针常量 | 常量指针 | int* p | const int* p | int* const p| const int* const p
c++
祁同伟.2 小时前
【C++】类和对象(中)构造函数、析构函数
开发语言·c++
郝学胜-神的一滴3 小时前
C++ 类型萃取:深入理解与实践
开发语言·c++·程序人生
程序员编程指南3 小时前
Qt 网络编程进阶:网络安全与加密
c语言·网络·c++·qt·web安全
女程序猿!!!3 小时前
网址收集总结
windows
GOATLong4 小时前
传输层协议TCP
c语言·开发语言·网络·c++·网络协议·tcp/ip
天若有情6735 小时前
从一个“诡异“的C++程序理解状态机、防抖与系统交互
开发语言·c++·交互·面向对象·状态机