跨语言共享环境变量

Posted

技术标签:

【中文标题】跨语言共享环境变量【英文标题】:Sharing environment variables across languages 【发布时间】:2020-02-26 17:14:01 【问题描述】:

我正在编写一个由使用不同语言(即 Java、C#、C++)编写的多个模块组成的应用程序。 我遇到了一种奇怪的行为,我在一个模块(例如 C#)中设置的环境变量没有传播到其他模块。 据我了解,问题是由于 Windows 中的环境变量是通过运行时库中的 _environ 结构访问的,而不是通过进程描述符,因此使用不同运行时的库具有不同的环境变量。

特别是对于 C#,这个问题似乎只有在我在 Release 中编译和运行代码时才会出现,而在 Debug 中编译代码就可以了。

下面的代码使用 C# 和 C++ 编写的两个非常简单的模块重现了该问题。我用 VS2015 Professional 编译了代码。 C# 代码使用 runtime v4.0 和 .NET framework v4.5.2 编译

C# 可执行文件

using System;
using System.Runtime.InteropServices;

namespace ConsoleApplication1

    class Program
    
        [DllImport("cpp_lib.dll", CharSet = CharSet.Unicode)]
        public static extern void print_path();

        static void Main(string[] args)
        
            var path = Environment.GetEnvironmentVariable("PATH");
            path += ";D:\\Temp";
            Environment.SetEnvironmentVariable("PATH", path);
            // Print the path from C#
            Console.WriteLine("Path from C#: " + Environment.GetEnvironmentVariable("PATH"));
            // Print the path from c++
            print_path();
        
    

C++ 库

#include <iostream>
#include <Windows.h>

extern "C" 

  __declspec(dllexport) void print_path() 
    std::cout << "PATH seen in C++: " << getenv("PATH") << std::endl;
  


如前所述,在 Debug 中运行代码会从 C# 和 C++ 打印相同的路径,但在 Release 中运行代码会导致从 c++ 打印的 PATH 缺少 D:\Temp 文件夹

【问题讨论】:

【参考方案1】:

用户环境变量是每个进程的,更改不会传播到其他进程。

在您的示例PATH 中更改系统环境变量。您需要修改注册表项HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment 下的值,然后广播WM_SETTINGCHANGE 消息。希望看到更改的应用程序必须处理广播。

来源:https://docs.microsoft.com/en-us/windows/win32/procthread/environment-variables

【讨论】:

是什么让您认为涉及多个流程? 这是一个单进程应用程序。 C# 应用程序导入 C++ dll。两者都生活在同一个进程中 @MarcoGiglio 对此感到抱歉。我认为这仍然适用:"...调用 SetEnvironmentVariable 对系统环境变量没有影响..." 事实上,我们正在更改进程环境变量。当然这不会影响其他进程和系统。【参考方案2】:

事实证明,Windows 提供了更多获取环境变量的函数。 从文档 “getenv 和 _putenv 使用全局变量 _environ 指向的环境的副本来访问环境。” 而 GetEnvironmentVariable “从环境块中检索指定变量的内容调用进程。” 从这些陈述来看,GetEnvironmentVariable 看起来是最安全的选择,用 GetEnvironmentVariable 替换 getenv 确实可以解决问题。

参考资料:

https://social.msdn.microsoft.com/Forums/en-US/c27a6623-6f57-4c7e-be9b-6dd35d362872/sharing-environment-variables-across-languages?forum=windowsgeneraldevelopmentissues

https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/getenv-wgetenv?view=vs-2019

https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getenvironmentvariable

【讨论】:

以上是关于跨语言共享环境变量的主要内容,如果未能解决你的问题,请参考以下文章

跨 terraform 环境共享资源

使用纱线工作区在monorepo中跨项目共享配置变量?

linux系统可执行文件添加环境变量使其跨终端和目录执行

java并发常识

在JAVA中ArrayList如何保证线程安全

访问jenkins共享库代码中的环境变量