首页 > 解决方案 > 为什么我的 program.exe(用 Python 制作)在重新启动后无法使用新的环境变量?

问题描述

我正在 Windows 10 上使用 Python 3.7 开发可执行文件。

我的软件需要安装 2 个程序:sdkmanager 和 build-tools 实用程序。

我的主要问题是使用新修改的环境变量。

要安装构建工具,我需要先安装 SDKmanager。当我的代码安装 SDKManager 时,它正在添加环境变量以使程序“sdkmanager.bat”在环境中可用。

我的软件执行的第一个命令是“sdkmanager --list”。当我的 program.exe 运行此命令时,它显示“此程序无法识别,无法识别内部或外部命令”。这是正常的,因为我的 program.exe 只是更改了环境变量 PATH,它需要重新启动才能使用它。

所以我的program.exe 启动了一个新的program.exe 实例。这第二个 program.exe 检测到第一个 program.exe 并将其杀死,以便仅让 1 个 program.exe 运行。

所以这个 2nd program.exe 假设享受新的环境变量,但事实并非如此。

我尝试了所有可能的代码来启动新的 porgram.exe:

proc = subprocess.Popen("start myprogram.exe", shell=True,stdin=None, stdout=True, stderr=None, close_fds=True)

os.system('start cmd /c  "myprogram.exe"')

proc = os.popen("start cmd /c myprogram.exe")

proc = subprocess.check_call(['myprogram.exe'], shell=True)

proc = subprocess.run(['myprogram.exe'])

ctypes.windll.shell32.ShellExecuteW(None, "runas", 'myprogram.exe', '', None, 1)

etc....

它没有用。每次我的程序无法运行命令“sdkmanager --list”时,它会说“该程序无法识别,无法识别内部或外部命令”。

奇怪的是我正在显示环境变量 PATH 的值,并且可以看到脚本 sdkmanager.bat 的路径。

所以我使用不同的方法来传播新的环境变量:

#Method 1
def RefreshEnvironment():
    #https://gist.github.com/apetrone/5937002
    HWND_BROADCAST = 0xFFFF
    WM_SETTINGCHANGE = 0x001A
    SMTO_ABORTIFHUNG = 0x0002
    sParam = "Environment"
    res1, res2 = win32gui.SendMessageTimeout( HWND_BROADCAST, WM_SETTINGCHANGE, 0, sParam, SMTO_ABORTIFHUNG, 100 )
    bool_res=bool(res1)
    if not res1:
        logger.info(f"result: {bool_res} {res2} from SendMessageTimeout")

#Method 2
def RefreshEnvironment(timeout_ms=2000):
    #https://programtalk.com/python-examples-amp/win32con.HWND_BROADCAST/
    """Broadcast a message to all top-level windows informing them that
    an environment change has occurred. The message must be sent, not posted,
    and times out after `timeout_ms` ms since some top-level windows handle this
    badly. NB This is a static method.
    """

    win32gui.SendMessageTimeout(
        win32con.HWND_BROADCAST, win32con.WM_SETTINGCHANGE,
        0, "Environment",
        win32con.SMTO_ABORTIFHUNG, timeout_ms
    )

但它没有用。

非常奇怪的是,当我通过双击手动重新启动 program.exe 时,它​​可以工作!当我自己运行程序时,program.exe 识别出命令“sdkmanager --list”,而如果 program.exe 自行重新启动,则不会。我不明白。

是否有人已经面临这种情况,您的程序必须重新启动才能享受环境变量?

标签: python-3.xenvironment-variables

解决方案


我的问题是我不太了解环境如何与 python 一起工作。

实际上,有两种环境:

  1. 机器环境。
  2. Python启动时加载的python环境。

我成功地改变了我机器的环境,但是 Python 将它自己的环境保留在它的内存中。因此,即使环境机器中的所有内容都已更新,Python 也会忽略它,即使在重新启动程序之后也是如此。

为了让 Python 享受这些新的环境变量,我不得不使用模块 os.environ 在 Python 环境中加载我的新环境变量。

这是我现在使用的代码,它在我身边工作:

# After I change the environment variable, I use my function 'GetEnvVarSys' to get the environment variable from Windows registry
ANDROID_HOME=GetEnvVarSys("ANDROID_HOME")
JAVA_HOME=GetEnvVarSys("JAVA_HOME")
PATH=GetEnvVarSys("PATH")

# then I pass them to Python os.environment
os.environ['ANDROID_HOME'] = ANDROID_HOME
os.environ['JAVA_HOME'] = JAVA_HOME
os.environ['PATH'] = PATH

推荐阅读