Skip to content

Commit 244ae34

Browse files
fix(installer): uninstall official Node on install
A standard-user install cannot put NVM ahead of a system Node PATH entry. Ignore is removed. Adopt and Drop both uninstall with UAC, and a failed uninstall stops setup. Fixes #1425 Co-authored-by: Cursor
1 parent 2190da7 commit 244ae34

1 file changed

Lines changed: 58 additions & 46 deletions

File tree

‎installer/officialnode.iss‎

Lines changed: 58 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
{ Official Node.js adopt / drop / ignore. Included from setup.iss [Code]. }
1+
{ Official Node.js adopt / drop. Included from setup.iss [Code]. }
22

33
function OfficialNodeParam(): String;
44
var
55
Raw: String;
66
begin
77
Raw := LowerCase(Trim(ExpandConstant('{param:OFFICIALNODE}')));
8-
if (Raw = 'adopt') or (Raw = 'drop') or (Raw = 'ignore') then
8+
if (Raw = 'adopt') or (Raw = 'drop') then
99
Result := Raw
1010
else
11-
Result := 'ignore';
11+
Result := 'adopt';
1212
end;
1313

1414
function IsNvmManagedPath(const PathValue: String): Boolean;
@@ -338,12 +338,10 @@ begin
338338
Result := OfficialNodeAction;
339339
if OfficialNodePage = nil then
340340
Exit;
341-
if OfficialNodePage.Values[0] then
342-
Result := 'adopt'
343-
else if OfficialNodePage.Values[1] then
341+
if OfficialNodePage.Values[1] then
344342
Result := 'drop'
345343
else
346-
Result := 'ignore';
344+
Result := 'adopt';
347345
end;
348346

349347
procedure CreateOfficialNodePage();
@@ -357,7 +355,7 @@ begin
357355
Description :=
358356
OfficialNodeSummary() + #13#10 +
359357
'Location: ' + OfficialNodePath + #13#10#13#10 +
360-
'Adopt copies this version and your global modules into NVM. Drop uninstalls official Node.js without copying. Ignore leaves it installed and puts NVM first on PATH.';
358+
'The existing Node.js installation overrides NVM for Windows and must be removed. Removing it may require elevated privileges.';
361359

362360
OfficialNodePage := CreateInputOptionPage(
363361
wpLicense,
@@ -367,16 +365,13 @@ begin
367365
True,
368366
False
369367
);
370-
OfficialNodePage.Add('Adopt — copy into NVM and keep official Node.js');
371-
OfficialNodePage.Add('Drop — uninstall official Node.js (do not copy)');
372-
OfficialNodePage.Add('Ignore — leave official Node.js, NVM PATH first');
368+
OfficialNodePage.Add('Adopt — copy into NVM and uninstall the existing installation');
369+
OfficialNodePage.Add('Drop — uninstall the existing installation (do not copy)');
373370

374-
if OfficialNodeAction = 'adopt' then
375-
OfficialNodePage.Values[0] := True
376-
else if OfficialNodeAction = 'drop' then
371+
if OfficialNodeAction = 'drop' then
377372
OfficialNodePage.Values[1] := True
378373
else
379-
OfficialNodePage.Values[2] := True;
374+
OfficialNodePage.Values[0] := True;
380375
end;
381376

382377
function AdoptOfficialNodeVersion(): Boolean;
@@ -453,6 +448,23 @@ begin
453448
AppendInstallLog('AdoptOfficialNode: nvm use ' + UseVer);
454449
end;
455450

451+
function UninstallResultOk(const Started: Boolean; const ResultCode: Integer): Boolean;
452+
begin
453+
Result := Started and ((ResultCode = 0) or (ResultCode = 3010) or (ResultCode = 1641));
454+
end;
455+
456+
procedure NoteUninstallFailure(const Started: Boolean; const ResultCode: Integer; const FailureText: String);
457+
begin
458+
OfficialNodeDropFailed := True;
459+
if (not Started) and (ResultCode = 1223) then
460+
OfficialNodeDropError := 'The admin prompt was canceled.'
461+
else if not Started then
462+
OfficialNodeDropError := 'Could not start the uninstaller (system error ' + IntToStr(ResultCode) + ').'
463+
else
464+
OfficialNodeDropError := FailureText + ' (exit ' + IntToStr(ResultCode) + ').';
465+
AppendInstallLogWarn('DropOfficialNode: ' + OfficialNodeDropError);
466+
end;
467+
456468
function DropOfficialNodeInstall(): Boolean;
457469
var
458470
ResultCode: Integer;
@@ -474,11 +486,9 @@ begin
474486
ewWaitUntilTerminated,
475487
ResultCode
476488
);
477-
if (not Ok) or (ResultCode <> 0) then
489+
if not UninstallResultOk(Ok, ResultCode) then
478490
begin
479-
OfficialNodeDropFailed := True;
480-
OfficialNodeDropError := 'Silent MSI uninstall failed (exit ' + IntToStr(ResultCode) + ').';
481-
AppendInstallLogWarn('DropOfficialNode: msiexec ' + OfficialNodeDropError);
491+
NoteUninstallFailure(Ok, ResultCode, 'Silent MSI uninstall failed');
482492
Exit;
483493
end;
484494
Result := True;
@@ -494,11 +504,9 @@ begin
494504
if Pos('/qn', LowerCase(Args)) = 0 then
495505
Args := Args + ' /qn /norestart';
496506
Ok := ShellExec('runas', ExpandConstant('{cmd}'), '/C ' + Args, '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
497-
if (not Ok) or (ResultCode <> 0) then
507+
if not UninstallResultOk(Ok, ResultCode) then
498508
begin
499-
OfficialNodeDropFailed := True;
500-
OfficialNodeDropError := 'MSI uninstall string failed (exit ' + IntToStr(ResultCode) + ').';
501-
AppendInstallLogWarn('DropOfficialNode: ' + OfficialNodeDropError);
509+
NoteUninstallFailure(Ok, ResultCode, 'MSI uninstall string failed');
502510
Exit;
503511
end;
504512
Result := True;
@@ -508,11 +516,9 @@ begin
508516
if Trim(OfficialNodeUninstallString) <> '' then
509517
begin
510518
Ok := ShellExec('runas', ExpandConstant('{cmd}'), '/C ' + OfficialNodeUninstallString, '', SW_SHOWNORMAL, ewWaitUntilTerminated, ResultCode);
511-
if (not Ok) or (ResultCode <> 0) then
519+
if not UninstallResultOk(Ok, ResultCode) then
512520
begin
513-
OfficialNodeDropFailed := True;
514-
OfficialNodeDropError := 'Official uninstall failed (exit ' + IntToStr(ResultCode) + ').';
515-
AppendInstallLogWarn('DropOfficialNode: ' + OfficialNodeDropError);
521+
NoteUninstallFailure(Ok, ResultCode, 'Official uninstall failed');
516522
Exit;
517523
end;
518524
Result := True;
@@ -524,6 +530,23 @@ begin
524530
AppendInstallLogWarn('DropOfficialNode: ' + OfficialNodeDropError);
525531
end;
526532

533+
procedure AbortInstallBecauseOfficialNodeRemains();
534+
var
535+
MessageText: String;
536+
begin
537+
MessageText :=
538+
'The existing Node.js installation could not be removed.' + #13#10#13#10 +
539+
OfficialNodeDropError + #13#10#13#10 +
540+
'Exit the NVM for Windows installer, remove the existing Node.js version, then run the installer again.' + #13#10#13#10 +
541+
'Node.js is still at:' + #13#10 +
542+
OfficialNodePath + #13#10#13#10 +
543+
'Removing it may require elevated privileges.';
544+
AppendInstallLogWarn('ApplyOfficialNodeChoice: ' + OfficialNodeDropError);
545+
if not WizardSilent then
546+
MsgBox(MessageText, mbError, MB_OK);
547+
Abort;
548+
end;
549+
527550
procedure ApplyOfficialNodeChoice();
528551
begin
529552
if not OfficialNodeDetected then
@@ -532,15 +555,17 @@ begin
532555
OfficialNodeAction := SelectedOfficialNodeAction();
533556
AppendInstallLog('ApplyOfficialNodeChoice: action=' + OfficialNodeAction + ' path=' + OfficialNodePath);
534557

535-
if OfficialNodeAction = 'adopt' then
558+
if OfficialNodeAction = 'drop' then
559+
DropOfficialNodeInstall()
560+
else
536561
begin
537562
if not AdoptOfficialNodeVersion() then
538563
OfficialNodeCopyFailed := True;
539-
Exit;
564+
DropOfficialNodeInstall();
540565
end;
541566

542-
if OfficialNodeAction = 'drop' then
543-
DropOfficialNodeInstall();
567+
if OfficialNodeDropFailed then
568+
AbortInstallBecauseOfficialNodeRemains();
544569
end;
545570

546571
procedure WarnIfOfficialNodeIncomplete();
@@ -554,21 +579,8 @@ begin
554579
begin
555580
MessageText :=
556581
OfficialNodeSummary() + #13#10#13#10 +
557-
'NVM copied nothing (or the copy failed). Official Node.js is still at:' + #13#10 +
558-
OfficialNodePath + #13#10#13#10 +
559-
'NVM itself finished installing. Adopt again later or install the version with nvm install.';
560-
MsgBox(MessageText, mbInformation, MB_OK);
561-
Exit;
562-
end;
563-
564-
if OfficialNodeDropFailed then
565-
begin
566-
MessageText :=
567-
'NVM did not uninstall official Node.js.' + #13#10#13#10 +
568-
OfficialNodeDropError + #13#10#13#10 +
569-
'Official Node.js is still at:' + #13#10 +
570-
OfficialNodePath + #13#10#13#10 +
571-
'Uninstall it from Apps & features, or run msiexec /x on the Node.js product.';
582+
'NVM could not copy this version. The existing Node.js installation was removed.' + #13#10#13#10 +
583+
'Install that version later with nvm install.';
572584
MsgBox(MessageText, mbInformation, MB_OK);
573585
end;
574586
end;

0 commit comments

Comments
 (0)