簡體   English   中英

Inno Setup - 卸載程序時從 PATH 環境變量中刪除路徑

[英]Inno Setup - Remove path from PATH environment variable while uninstalling a program

我編寫了一個 Inno Setup 腳本,它安裝程序並使用安裝程序的目錄更新PATH環境變量。

我想更新PATH環境變量,以恢復其以前的安裝狀態。

安裝路徑由用戶在安裝程序運行時選擇。

這是腳本,它使用來自How do I modify the PATH environment variable when running an Inno Setup Installer?

[Setup]
ChangesEnvironment=yes

[Registry]
Root: HKLM; \
    Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; \
    ValueType: expandsz; ValueName: "PATH"; ValueData: "{olddata};{app}"; \
    Check: NeedsAddPath('{app}')
Root: HKLM; \
    Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; \
    ValueName: "PATH"; ValueData: "{app}"; Flags: uninsdeletevalue
[Code]
function NeedsAddPath(Param: string): boolean;
var
  OrigPath: string;
begin
  if not RegQueryStringValue(HKEY_LOCAL_MACHINE,
    'SYSTEM\CurrentControlSet\Control\Session Manager\Environment',
    'Path', OrigPath)
  then begin
    Result := True;
    exit;
  end;
  { look for the path with leading and trailing semicolon }
  { Pos() returns 0 if not found }
  Result := Pos(';' + Param + ';', ';' + OrigPath + ';') = 0;
end;

看一下代碼,可以注意到以下指令:

Root: HKLM; \
    Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; \
    ValueName: "PATH"; ValueData: "{app}"; Flags: uninsdeletevalue

我使用了該指令,(在我看來)適用於我的示例,閱讀Inno Setup。 如何卸載注冊表值?

uninsdeletevalue的使用應該是卸載程序時刪除的值,而實際上我運行卸載程序的時候,整個PATH變量都被刪除了,但是我需要將PATH環境變量恢復到之前的安裝值。 我認為在運行安裝程序之前可以讀取它的值,但我不知道如何在卸載階段使用它。

有人可以幫我提供一個代碼示例嗎?

僅在使用[Registry]部分條目進行卸載時,您無法讓 Inno Setup 記住安裝時的值並恢復它。

雖然您可以對其進行編碼,但無論如何這都不是一個好方法,因為PATH可能會在安裝后發生更改,並且您將丟棄任何此類更改。


您必須在PATH中搜索您的路徑並僅刪除該路徑。

const
  EnvironmentKey = 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment';

procedure RemovePath(Path: string);
var
  Paths: string;
  P: Integer;
begin
  if not RegQueryStringValue(HKLM, EnvironmentKey, 'Path', Paths) then
  begin
    Log('PATH not found');
  end
    else
  begin
    Log(Format('PATH is [%s]', [Paths]));

    P := Pos(';' + Uppercase(Path) + ';', ';' + Uppercase(Paths) + ';');
    if P = 0 then
    begin
      Log(Format('Path [%s] not found in PATH', [Path]));
    end
      else
    begin
      if P > 1 then P := P - 1;
      Delete(Paths, P, Length(Path) + 1);
      Log(Format('Path [%s] removed from PATH => [%s]', [Path, Paths]));

      if RegWriteStringValue(HKLM, EnvironmentKey, 'Path', Paths) then
      begin
        Log('PATH written');
      end
        else
      begin
        Log('Error writing PATH');
      end;
    end;
  end;
end;

procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
  if CurUninstallStep = usUninstall then
  begin
    RemovePath(ExpandConstant('{app}'));
  end;
end;

如果以前的版本已經安裝,包含錯誤的卸載例程,然后用新的安裝程序更新,問題似乎仍然存在。 無論如何,路徑都被刪除了,即使注冊表部分不再有標志。 所以我的任務是編寫一個新的安裝程序,在更新錯誤版本時確保卸載后路徑仍然存在。

我最接近 Martin Prikryl 的方法,但記錄顯示我需要在卸載開始時保存路徑(usUninstall)並在結束時重寫它(usPostUninstall),否則它不會堅持。 此外,在處理 usPostUninstall 步驟時,環境已經在沒有路徑的情況下錯誤刷新,因此我添加了從另一篇文章中獲取的手動環境刷新。

這是對我有用的最終結果:

var
  Paths: string;

const
  EnvironmentKey = 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment';
  SMTO_ABORTIFHUNG = 2;
  WM_WININICHANGE = $001A;
  WM_SETTINGCHANGE = WM_WININICHANGE;

type
  WPARAM = UINT_PTR;
  LPARAM = INT_PTR;
  LRESULT = INT_PTR;

function SendTextMessageTimeout(hWnd: HWND; Msg: UINT;
  wParam: WPARAM; lParam: PAnsiChar; fuFlags: UINT;
  uTimeout: UINT; out lpdwResult: DWORD): LRESULT;
  external 'SendMessageTimeoutA@user32.dll stdcall';  

procedure SaveOldPath();
begin
  if not RegQueryStringValue(HKEY_LOCAL_MACHINE, EnvironmentKey, 'Path', Paths) then
  begin
    Log('PATH not found');
  end else begin
    Log(Format('Old Path saved as [%s]', [Paths]));
  end;
end;

procedure RemovePath(Path: string);
var
  P: Integer;
begin
  Log(Format('Prepare to remove from Old PATH [%s]', [Paths]));

  P := Pos(';' + Uppercase(Path) + ';', ';' + Uppercase(Paths) + ';');
  if P = 0 then
  begin
    Log(Format('Path [%s] not found in PATH', [Path]));
  end
    else
  begin
    Delete(Paths, P - 1, Length(Path) + 1);
    Log(Format('Path [%s] removed from PATH => [%s]', [Path, Paths]));

    if RegWriteExpandStringValue(HKEY_LOCAL_MACHINE, EnvironmentKey, 'Path', Paths) then
    begin
      Log('PATH written');
    end
      else
    begin
      Log('Error writing PATH');
    end;
  end;
end;

procedure RefreshEnvironment;
var
  S: AnsiString;
  MsgResult: DWORD;
begin
  S := 'Environment';
  SendTextMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0,
    PAnsiChar(S), SMTO_ABORTIFHUNG, 5000, MsgResult);
end;

procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
  if CurUninstallStep =  usUninstall then
  begin
    SaveOldPath();
  end;
  if CurUninstallStep = usPostUninstall then
  begin
    RemovePath(ExpandConstant('{app}'));
    RefreshEnvironment();
  end;
end;

這些從 PATH 中刪除變量的解決方案有很大幫助,但對我來說Delete(Paths, P - 1, Length(Path) + 1); 當我的安裝程序的路徑在開始時。 然后刪除功能將不起作用。

對我有用的簡單修改是Delete(Paths, P, Length(Path) + 1);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM