【问题标题】:Interface for modifying Windows environment variables from Python从 Python 修改 Windows 环境变量的接口
【发布时间】:2010-11-08 07:44:13
【问题描述】:

如何通过 Python 脚本持续修改 Windows 环境变量? (这是 setup.py 脚本)

我正在寻找用于此的标准功能或模块。我已经熟悉registry way of doing it,但也欢迎任何与此相关的 cmets。

【问题讨论】:

  • 您是指持久环境变量(如“setx”命令)还是为当前进程更改一个(如“set”命令)?在 ActiveState 上一个配方的事实表明它没有标准模块,除非我认为它是非常新的。
  • 是的,我一直在更新问题
  • 不是真正的重复。该问题专门针对Linux下的bash,而专门针对Windows。另外,这个提问者没有说是父进程的环境还是未来进程的环境需要修改。

标签: python windows environment-variables


【解决方案1】:

使用 setx 几乎没有缺点,特别是如果您尝试附加到环境变量(例如 setx PATH %Path%;C:\mypath),这将在您每次运行时重复附加到路径,这可能是一个问题。更糟糕的是,它不区分机器路径(存储在 HKEY_LOCAL_MACHINE)和用户路径(存储在 HKEY_CURRENT_USER)。您在命令提示符处看到的环境变量由这两个值的串联组成。因此,在调用 setx 之前:

user PATH == u
machine PATH == m
%PATH% == m;u

> setx PATH %PATH%;new

Calling setx sets the USER path by default, hence now:
user PATH == m;u;new
machine PATH == m
%PATH% == m;m;u;new

每次调用 setx 附加到 PATH 时,系统路径不可避免地会在 %PATH% 环境变量中重复。这些更改是永久性的,不会因重新启动而重置,因此会在机器的整个生命周期内累积。

试图在 DOS 中弥补这一点超出了我的能力范围。所以我转向了 Python。我今天想出的解决方案,通过调整注册表来设置环境变量,包括附加到PATH而不引入重复,如下:

from os import system, environ
import win32con
from win32gui import SendMessage
from _winreg import (
    CloseKey, OpenKey, QueryValueEx, SetValueEx,
    HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE,
    KEY_ALL_ACCESS, KEY_READ, REG_EXPAND_SZ, REG_SZ
)

def env_keys(user=True):
    if user:
        root = HKEY_CURRENT_USER
        subkey = 'Environment'
    else:
        root = HKEY_LOCAL_MACHINE
        subkey = r'SYSTEM\CurrentControlSet\Control\Session Manager\Environment'
    return root, subkey


def get_env(name, user=True):
    root, subkey = env_keys(user)
    key = OpenKey(root, subkey, 0, KEY_READ)
    try:
        value, _ = QueryValueEx(key, name)
    except WindowsError:
        return ''
    return value


def set_env(name, value):
    key = OpenKey(HKEY_CURRENT_USER, 'Environment', 0, KEY_ALL_ACCESS)
    SetValueEx(key, name, 0, REG_EXPAND_SZ, value)
    CloseKey(key)
    SendMessage(
        win32con.HWND_BROADCAST, win32con.WM_SETTINGCHANGE, 0, 'Environment')


def remove(paths, value):
    while value in paths:
        paths.remove(value)


def unique(paths):
    unique = []
    for value in paths:
        if value not in unique:
            unique.append(value)
    return unique


def prepend_env(name, values):
    for value in values:
        paths = get_env(name).split(';')
        remove(paths, '')
        paths = unique(paths)
        remove(paths, value)
        paths.insert(0, value)
        set_env(name, ';'.join(paths))


def prepend_env_pathext(values):
    prepend_env('PathExt_User', values)
    pathext = ';'.join([
        get_env('PathExt_User'),
        get_env('PathExt', user=False)
    ])
    set_env('PathExt', pathext)



set_env('Home', '%HomeDrive%%HomePath%')
set_env('Docs', '%HomeDrive%%HomePath%\docs')
set_env('Prompt', '$P$_$G$S')

prepend_env('Path', [
    r'%SystemDrive%\cygwin\bin', # Add cygwin binaries to path
    r'%HomeDrive%%HomePath%\bin', # shortcuts and 'pass-through' bat files
    r'%HomeDrive%%HomePath%\docs\bin\mswin', # copies of standalone executables
])

# allow running of these filetypes without having to type the extension
prepend_env_pathext(['.lnk', '.exe.lnk', '.py'])

不影响当前进程或父shell,但会影响运行后打开的所有cmd窗口,无需重启,可以安全地多次编辑和重新运行,不会引入任何重复。

【讨论】:

【解决方案2】:

使用外部Windows setx 命令可能同样简单:

C:\>set NEWVAR
Environment variable NEWVAR not defined

C:\>python
Python 2.5.4 (r254:67916, Dec 23 2008, 15:10:54) [MSC v.1310 32 bit (Intel)] on
win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.system('setx NEWVAR newvalue')
0
>>> os.getenv('NEWVAR')
>>> ^Z


C:\>set NEWVAR
Environment variable NEWVAR not defined

现在打开一个新的命令提示符:

C:\>set NEWVAR
NEWVAR=newvalue

如您所见,setx 既不为当前会话设置变量,也不为父进程(第一个命令提示符)设置变量。但它确实在注册表中为将来的进程永久设置了变量。

我认为根本没有办法改变父进程的环境(如果有的话,我很想听听!)。

【讨论】:

  • 我曾经创建了一个可怕的hack来修改Windows上调用进程的环境,但它需要调用进程配合:被调用脚本将.bat文件写入磁盘,调用然后处理'exec's it或类似的东西。 tartley.com/?p=966
【解决方案3】:

一定是在一千年前,我试图通过一个程序来改变当前 DOS 会话的环境。问题是:该程序在其自己的 DOS shell 中运行,因此它必须在其父环境中运行。它需要从 DOS 信息块开始,沿着内存控制块链走一圈,才能找到该父环境的位置。一旦我发现了如何做到这一点,我对操作环境变量的需求就消失了。我会给你下面的 Turbo Pascal 代码,但我想至少有三种更好的方法可以做到这一点:

  1. 创建一个批处理文件: (a) 调用一个 Python 脚本(或其他),该脚本生成一个包含适当 SET 命令的临时批处理文件; (b) 调用临时批处理文件(SET 命令在当前 shell 中执行); (c) 删除临时批处理文件。

  2. 创建一个 Python 脚本,将“VAR1=val1\nVAR2=val2\nVAR3=val3\n”之类的内容写入 STDOUT。在批处理文件中以这种方式使用它:

    for /f "delims=|" %%X in ('callYourPythonScript') do set %%X

    等等:变量 VAR1、VAR2 和 VAR3 已被赋予一个值。

  3. 修改 Windows 注册表并广播设置更改,如 Alexander Prokofyev 所述的here

这里是一个仅报告内存位置的程序的 Pascal 代码(您可能需要一本荷兰语词典和一本 Pascal 编程书)。它似乎仍然可以在 Windows XP 下工作,报告我们正在运行 DOS 5.00。这只是一个开始,为了操纵选定的环境,还有很多低级编程要做。而且由于指针结构可能看起来是正确的,我不太确定 1994 年的环境模型现在是否仍然适用......

program MCBKETEN;
uses dos, HexConv;

{----------------------------------------------------------------------------}
{  Programma: MCBKETEN.EXE                                                   }
{  Broncode : MCBKETEN.PAS                                                   }
{  Doel     : Tocht langs de MCB's met rapportage                            }
{  Datum    : 11 januari 1994                                                }
{  Auteur   : Meindert Meindertsma                                           }
{  Versie   : 1.00                                                           }
{----------------------------------------------------------------------------}

type
   MCB_Ptr     = ^MCB;
{  MCB_PtrPtr  = ^MCB_Ptr;  vervallen wegens DOS 2.11 -- zie verderop }
   MCB         = record
                    Signatuur    : char;
                    Eigenaar     : word;
                    Paragrafen   : word;
                    Gereserveerd : array[1..3] of byte;
                    Naam         : array[1..8] of char;
                 end;
   BlokPtr     = ^BlokRec;
   BlokRec     = record
                    Vorige       : BlokPtr;
                    DitSegment,
                    Paragrafen   : word;
                    Signatuur    : string[6];
                    Eigenaar,
                    Omgeving     : word;
                    Functie      : String4;
                    Oorsprong,
                    Pijl         : char;
                    KorteNaam    : string[8];
                    LangeNaam    : string;
                    Volgende     : BlokPtr;
                 end;
   PSP_Ptr     = ^PSP;
   PSP         = record
                    Vulsel1      : array[1..44] of byte;
                    Omgeving     : word;
                    Vulsel2      : array[47..256] of byte;
                 end;

var
   Zone                  : string[5];
   ProgGevonden,
   EindeKeten,
   Dos3punt2             : boolean;
   Regs                  : registers;
   ActMCB                : MCB_Ptr;
   EersteSchakel, Schakel,
   LaatsteSchakel        : BlokPtr;
   ActPSP                : PSP_Ptr;
   EersteProg,
   Meester, Ouder,
   TerugkeerSegment,
   TerugkeerOffset,
   TerugkeerSegment2,
   OuderSegment          : word;
   Specificatie          : string[8];
   ReleaseNummer         : string[2];
   i                     : byte;


{----------------------------------------------------------------------------}
{  PROCEDURES EN FUNCTIES                                                    }
{----------------------------------------------------------------------------}

function Coda (Omgeving : word; Paragrafen : word) : string;

var
   i            : longint;
   Vorige, Deze : char;
   Streng       : string;

begin
   i    := 0;
   Deze := #0;
   repeat
      Vorige := Deze;
      Deze   := char (ptr (Omgeving, i)^);
      inc (i);
   until ((Vorige = #0) and (Deze = #0)) or (i div $10 >= Paragrafen);
   if (i + 3) div $10 < Paragrafen then begin
      Vorige := char (ptr (Omgeving, i)^);
      inc (i);
      Deze   := char (ptr (Omgeving, i)^);
      inc (i);
      if (Vorige = #01) and (Deze = #0) then begin
         Streng := '';
         Deze   := char (ptr (Omgeving, i)^);
         inc (i);
         while (Deze <> #0) and (i div $10 < Paragrafen) do begin
            Streng := Streng + Deze;
            Deze   := char (ptr (Omgeving, i)^);
            inc (i);
         end;
         Coda := Streng;
      end
      else Coda := '';
   end
   else Coda := '';
end {Coda};


{----------------------------------------------------------------------------}
{  HOOFDPROGRAMMA                                                            }
{----------------------------------------------------------------------------}

BEGIN
  {----- Initiatie -----}
   Zone            := 'Lower';
   ProgGevonden    := FALSE;
   EindeKeten      := FALSE;
   Dos3punt2       := (dosversion >= $1403) and (dosversion <= $1D03);
   Meester         := $0000;
   Ouder           := $0000;
   Specificatie[0] := #8;
   str (hi (dosversion) : 2, ReleaseNummer);
   if ReleaseNummer[1] = ' ' then ReleaseNummer[1] := '0';

  {----- Pointer naar eerste MCB ophalen ------}
   Regs.AH := $52;  { functie $52 geeft adres van DOS Info Block in ES:BX }
   msdos (Regs);
{  ActMCB := MCB_PtrPtr (ptr (Regs.ES, Regs.BX - 4))^;  NIET onder DOS 2.11  }
   ActMCB := ptr (word (ptr (Regs.ES, Regs.BX - 2)^), $0000);

  {----- MCB-keten doorlopen -----}
   new (EersteSchakel);
   EersteSchakel^.Vorige := nil;
   Schakel               := EersteSchakel;
   repeat
      with Schakel^ do begin
         DitSegment := seg (ActMCB^);
         Paragrafen := ActMCB^.Paragrafen;
         if DitSegment + Paragrafen >= $A000 then
            Zone    := 'Upper';
         Signatuur  := Zone + ActMCB^.Signatuur;
         Eigenaar   := ActMCB^.Eigenaar;
         ActPSP     := ptr (Eigenaar, 0);
         if not ProgGevonden then EersteProg := DitSegment + 1;
         if Eigenaar >= EersteProg
            then Omgeving := ActPSP^.Omgeving
            else Omgeving := 0;
         if DitSegment + 1 = Eigenaar then begin
            ProgGevonden  := TRUE;
            Functie       := 'Prog';
            KorteNaam[0]  := #0;
            while (ActMCB^.Naam[ ord (KorteNaam[0]) + 1 ] <> #0) and
                  (KorteNaam[0] < #8) do
            begin
               inc (KorteNaam[0]);
               KorteNaam[ ord (KorteNaam[0]) ] :=
                  ActMCB^.Naam[ ord (KorteNaam[0]) ];
            end;
            if Eigenaar = prefixseg then begin
               TerugkeerSegment := word (ptr (prefixseg, $000C)^);
               TerugkeerOffset  := word (ptr (prefixseg, $000A)^);
               LangeNaam        := '-----> Terminate Vector = '     +
                                   WordHex (TerugkeerSegment) + ':' +
                                   WordHex (TerugkeerOffset )        ;
            end
            else
               LangeNaam := '';
         end {if ÆProgØ}
         else begin
            if Eigenaar = $0008 then begin
               if ActMCB^.Naam[1] = 'S' then
                  case ActMCB^.Naam[2] of
                     'D' : Functie := 'SysD';
                     'C' : Functie := 'SysP';
                     else  Functie := 'Data';
                  end {case}
               else        Functie := 'Data';
               KorteNaam := '';
               LangeNaam := '';
            end {if Eigenaar = $0008}
            else begin
               if DitSegment + 1 = Omgeving then begin
                  Functie   := 'Env ';
                  LangeNaam := Coda (Omgeving, Paragrafen);
                  if EersteProg = Eigenaar then Meester := Omgeving;
               end {if ÆEnvØ}
               else begin
                  move (ptr (DitSegment + 1, 0)^, Specificatie[1], 8);
                  if (Specificatie = 'PATH=' + #0 + 'CO') or
                     (Specificatie = 'COMSPEC='         ) or
                     (Specificatie = 'OS=DRDOS'         ) then
                  begin
                     Functie   := 'Env' + chr (39);
                     LangeNaam := Coda (DitSegment + 1, Paragrafen);
                     if (EersteProg = Eigenaar) and
                        (Meester    = $0000   )
                     then
                        Meester := DitSegment + 1;
                  end
                  else begin
                     if Eigenaar = 0
                        then Functie := 'Free'
                        else Functie := 'Data';
                     LangeNaam := '';
                     if (EersteProg = Eigenaar) and
                        (Meester    = $0000   )
                     then
                        Meester := DitSegment + 1;
                  end;
               end {else: not ÆEnvØ};
               KorteNaam := '';
            end {else: Eigenaar <> $0008};
         end {else: not ÆProgØ};

        {----- KorteNaam redigeren -----}
         for i := 1 to length (KorteNaam) do
            if KorteNaam[i] < #32 then KorteNaam[i] := '.';
         KorteNaam := KorteNaam + '        ';

        {----- Oorsprong vaststellen -----}
         if EersteProg = Eigenaar
            then Oorsprong := '*'
            else Oorsprong := ' ';

        {----- Actueel proces (uitgaande Pijl) vaststellen -----}
         if Eigenaar = prefixseg
            then Pijl := '>'
            else Pijl := ' ';
      end {with Schakel^};

     {----- MCB-opeenvolging onderzoeken / schakelverloop vaststellen -----}
      if (Zone = 'Upper') and (ActMCB^.Signatuur = 'Z') then begin
         Schakel^.Volgende := nil;
         EindeKeten        := TRUE;
      end
      else begin
         ActMCB := ptr (seg (ActMCB^) + ActMCB^.Paragrafen + 1, 0);
         if ((ActMCB^.Signatuur <> 'M') and (ActMCB^.Signatuur <> 'Z')) or
            ($FFFF - ActMCB^.Paragrafen < seg (ActMCB^)               )
         then begin
            Schakel^.Volgende := nil;
            EindeKeten        := TRUE;
         end
         else begin
            new (LaatsteSchakel);
            Schakel^.Volgende      := LaatsteSchakel;
            LaatsteSchakel^.Vorige := Schakel;
            Schakel                := LaatsteSchakel;
         end {else: (ÆMØ or ÆZØ) and Æteveel_ParagrafenØ};
      end {else: ÆLowerØ or not ÆZØ};
   until EindeKeten;

  {----- Terugtocht -----}
   while Schakel <> nil do with Schakel^ do begin

     {----- Ouder-proces vaststellen -----}
      TerugkeerSegment2 := TerugkeerSegment + (TerugkeerOffset div $10);
      if (DitSegment              <= TerugkeerSegment2) and
         (DitSegment + Paragrafen >= TerugkeerSegment2)
      then
         OuderSegment := Eigenaar;

     {----- Meester-omgeving markeren -----}
      if DitSegment + 1 = Meester then Oorsprong := 'M';

     {----- Schakel-verloop -----}
      Schakel := Schakel^.Vorige;
   end {while Schakel <> nil};

  {----- Rapportage -----}
   writeln ('Chain of Memory Control Blocks in DOS version ',
            lo (dosversion), '.', ReleaseNummer, ':');
   writeln;
   writeln ('MCB@ #Par Signat PSP@ Env@ Type !! Name     File');
   writeln ('---- ---- ------ ---- ---- ---- -- -------- ',
            '-----------------------------------');
   Schakel := EersteSchakel;
   while Schakel <> nil do with Schakel^ do begin

     {----- Ouder-omgeving vaststellen -----}
      if Eigenaar = OuderSegment then begin
         if not Dos3punt2 then begin
            if (Functie = 'Env ') then begin
               Ouder := DitSegment + 1;
               Pijl  := 'Û';
            end
            else
               Pijl := '<';
         end {if not Dos3punt2}
         else begin
            if ((Functie = 'Env' + chr (39)) or (Functie = 'Data')) and
               (Ouder    = $0000)
            then begin
               Ouder := DitSegment + 1;
               Pijl  := 'Û';
            end
            else
               Pijl := '<';
         end {else: Dos3punt2};
      end {with Schakel^};

     {----- Keten-weergave -----}
      writeln (WordHex (DitSegment)        , ' ',
               WordHex (Paragrafen)        , ' ',
               Signatuur                   , ' ',
               WordHex (Eigenaar)          , ' ',
               WordHex (Omgeving)          , ' ',
               Functie                     , ' ',
               Oorsprong, Pijl             , ' ',
               KorteNaam                   , ' ',
               LangeNaam                        );

     {----- Schakel-verloop -----}
      Schakel := Schakel^.Volgende;
   end {while Schakel <> nil};

  {----- Afsluiting rapportage -----}
   writeln;

   write ('* = First command interpreter at ');
   if ProgGevonden
      then writeln (WordHex (EersteProg), ':0000')
      else writeln ('?');

   write ('M = Master environment        at ');
   if Meester > $0000
      then writeln (WordHex (Meester), ':0000')
      else writeln ('?');

   write ('< = Parent proces             at ');
   writeln (WordHex (OuderSegment), ':0000');

   write ('Û = Parent environment        at ');
   if Ouder > $0000
      then writeln (WordHex (Ouder), ':0000')
      else writeln ('?');

   writeln ('> = Current proces            at ',
            WordHex (prefixseg), ':0000');

   writeln ('    returns                   to ',
            WordHex (TerugkeerSegment), ':', WordHex (TerugkeerOffset));
END.

(ASCII 127 以上,本演示文稿中可能存在一些 ASCII/ANSI 转换问题。)

【讨论】:

    【解决方案4】:

    此 Python 脚本[*] 尝试修改注册表中的 GLOBAL env-vars,如果没有权限回退到用户的注册表,然后通知所有窗口有关更改:

    """
    Show/Modify/Append registry env-vars (ie `PATH`) and notify Windows-applications to pickup changes.
    
    First attempts to show/modify HKEY_LOCAL_MACHINE (all users), and 
    if not accessible due to admin-rights missing, fails-back 
    to HKEY_CURRENT_USER.
    Write and Delete operations do not proceed to user-tree if all-users succeed.
    
    Syntax: 
        {prog}                  : Print all env-vars. 
        {prog}  VARNAME         : Print value for VARNAME. 
        {prog}  VARNAME   VALUE : Set VALUE for VARNAME. 
        {prog}  +VARNAME  VALUE : Append VALUE in VARNAME delimeted with ';' (i.e. used for `PATH`). 
        {prog}  -VARNAME        : Delete env-var value. 
    
    Note that the current command-window will not be affected, 
    changes would apply only for new command-windows.
    """
    
    import winreg
    import os, sys, win32gui, win32con
    
    def reg_key(tree, path, varname):
        return '%s\%s:%s' % (tree, path, varname) 
    
    def reg_entry(tree, path, varname, value):
        return '%s=%s' % (reg_key(tree, path, varname), value)
    
    def query_value(key, varname):
        value, type_id = winreg.QueryValueEx(key, varname)
        return value
    
    def show_all(tree, path, key):
        i = 0
        while True:
            try:
                n,v,t = winreg.EnumValue(key, i)
                print(reg_entry(tree, path, n, v))
                i += 1
            except OSError:
                break ## Expected, this is how iteration ends.
    
    def notify_windows(action, tree, path, varname, value):
        win32gui.SendMessage(win32con.HWND_BROADCAST, win32con.WM_SETTINGCHANGE, 0, 'Environment')
        print("---%s %s" % (action, reg_entry(tree, path, varname, value)))
    
    def manage_registry_env_vars(varname=None, value=None):
        reg_keys = [
            ('HKEY_LOCAL_MACHINE', r'SYSTEM\CurrentControlSet\Control\Session Manager\Environment'),
            ('HKEY_CURRENT_USER', r'Environment'),
        ]
        for (tree_name, path) in reg_keys:
            tree = eval('winreg.%s'%tree_name)
            try:
                with winreg.ConnectRegistry(None, tree) as reg:
                    with winreg.OpenKey(reg, path, 0, winreg.KEY_ALL_ACCESS) as key:
                        if not varname:
                            show_all(tree_name, path, key)
                        else:
                            if not value:
                                if varname.startswith('-'):
                                    varname = varname[1:]
                                    value = query_value(key, varname)
                                    winreg.DeleteValue(key, varname)
                                    notify_windows("Deleted", tree_name, path, varname, value)
                                    break  ## Don't propagate into user-tree.
                                else:
                                    value = query_value(key, varname)
                                    print(reg_entry(tree_name, path, varname, value))
                            else:
                                if varname.startswith('+'):
                                    varname = varname[1:]
                                    value = query_value(key, varname) + ';' + value
                                winreg.SetValueEx(key, varname, 0, winreg.REG_EXPAND_SZ, value)
                                notify_windows("Updated", tree_name, path, varname, value)
                                break  ## Don't propagate into user-tree.
            except PermissionError as ex:
                print("!!!Cannot access %s due to: %s" % 
                        (reg_key(tree_name, path, varname), ex))
            except FileNotFoundError as ex:
                print("!!!Cannot find %s due to: %s" % 
                        (reg_key(tree_name, path, varname), ex))
    
    if __name__=='__main__':
        args = sys.argv
        argc = len(args)
        if argc > 3:
            print(__doc__.format(prog=args[0]))
            sys.exit()
    
        manage_registry_env_vars(*args[1:])
    

    以下是一些使用示例,假设它已保存在您当前路径某处名为setenv.py 的文件中。 请注意,在这些示例中,我没有管理员权限,因此这些更改仅影响我的本地用户的注册表树:

    > REM ## Print all env-vars
    > setenv.py
    !!!Cannot access HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session   Manager\Environment:PATH due to: [WinError 5] Access is denied
    HKEY_CURRENT_USER\Environment:PATH=...
    ...
    
    > REM ## Query env-var:
    > setenv.py PATH C:\foo
    !!!Cannot access HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session   Manager\Environment:PATH due to: [WinError 5] Access is denied
    !!!Cannot find HKEY_CURRENT_USER\Environment:PATH due to: [WinError 2] The system cannot find the file specified
    
    > REM ## Set env-var:
    > setenv.py PATH C:\foo
    !!!Cannot access HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session   Manager\Environment:PATH due to: [WinError 5] Access is denied
    ---Set HKEY_CURRENT_USER\Environment:PATH=C:\foo
    
    > REM ## Append env-var:
    > setenv.py +PATH D:\Bar
    !!!Cannot access HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session   Manager\Environment:PATH due to: [WinError 5] Access is denied
    ---Set HKEY_CURRENT_USER\Environment:PATH=C:\foo;D:\Bar
    
    > REM ## Delete env-var:
    > setenv.py -PATH
    !!!Cannot access HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session   Manager\Environment:PATH due to: [WinError 5] Access is denied
    ---Deleted HKEY_CURRENT_USER\Environment:PATH
    

    [*] 改编自:http://code.activestate.com/recipes/416087-persistent-environment-variables-on-windows/

    【讨论】:

    • 精彩!!!这正是我一直在寻找的!我删除了 args 的东西,并为自己添加了名称和值。但剧本并没有结束。所以我在 except 上添加了 sys.exit() ,因为我有“拒绝访问”消息。我想知道在添加 1 个名称 + 1 个值时在哪里添加 sys.exit() 以防我是管理员?恐怕您的脚本会无休止地运行。我只想在我的脚本中使用你的脚本作为一个函数。我将自己传递 2 变量。 ====> IE: manage_registry_env_vars('ANDROID_HOME', 'C:\Program Files\Android')
    • @Cff 引发的异常类型是什么?在哪里?
    • 是关于win32gui的。不是你的代码。我正在努力。
    【解决方案5】:

    注册表的方式是如果你想为所有东西永久修改它,我猜这就是你想要的,因为它在 setup.py 中。

    暂时只针对您的进程,然后 os.environ 是诀窍。

    【讨论】:

      【解决方案6】:

      在 os 模块中,有 getenv 和 putenv 函数。但是,putenv 似乎无法正常工作,您必须改用 windows 注册表

      this discussion

      【讨论】:

        猜你喜欢
        • 2016-06-25
        • 1970-01-01
        • 2017-07-16
        • 2016-01-06
        • 1970-01-01
        • 1970-01-01
        • 2014-09-30
        • 2012-06-18
        • 2013-08-04
        相关资源
        最近更新 更多