Skip to content

Commit a14b016

Browse files
committed
installer: auto-terminate ssh-agent.exe and friends
This background process is supposed to be auto-started, so it makes sense to auto-terminate it. We need to be careful, though, to report correctly when we could not terminate the process, in which case we ask the user to please do it themselves. Signed-off-by: Johannes Schindelin <[email protected]>
1 parent 32c6d82 commit a14b016

File tree

2 files changed

+61
-6
lines changed

2 files changed

+61
-6
lines changed

installer/install.iss

+14-5
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,8 @@ begin
469469
Caption:=Processes[i].Name+' (PID '+IntToStr(Processes[i].ID);
470470
if Processes[i].Restartable then begin
471471
Caption:=Caption+', closing is optional';
472+
end else if Processes[i].ToTerminate then begin
473+
Caption:=Caption+', will be terminated';
472474
end else begin
473475
Caption:=Caption+', closing is required';
474476
ManualClosingRequired:=True;
@@ -1201,17 +1203,17 @@ end;
12011203
12021204
function ShouldSkipPage(PageID:Integer):Boolean;
12031205
begin
1204-
#ifdef DEBUG_WIZARD_PAGE
1205-
Result:=PageID<>DebugWizardPage
1206-
Exit;
1207-
#endif
12081206
if (ProcessesPage<>NIL) and (PageID=ProcessesPage.ID) then begin
12091207
// This page is only reached forward (by pressing "Next", never by pressing "Back").
12101208
RefreshProcessList(NIL);
12111209
Result:=(GetArrayLength(Processes)=0);
12121210
end else begin
12131211
Result:=False;
12141212
end;
1213+
#ifdef DEBUG_WIZARD_PAGE
1214+
Result:=PageID<>DebugWizardPage
1215+
Exit;
1216+
#endif
12151217
end;
12161218
12171219
procedure CurPageChanged(CurPageID:Integer);
@@ -1273,7 +1275,14 @@ begin
12731275
// It would have been nicer to just disable the "Next" button, but the
12741276
// WizardForm exports the button just read-only.
12751277
for i:=0 to GetArrayLength(Processes)-1 do begin
1276-
if not Processes[i].Restartable then begin
1278+
if Processes[i].ToTerminate then begin
1279+
if not TerminateProcessByID(Processes[i].ID) then begin
1280+
SuppressibleMsgBox('Failed to terminate '+Processes[i].Name+' (pid '+IntToStr(Processes[i].ID)+')'+#13+'Please terminate it manually and press the "Refresh" button.',mbCriticalError,MB_OK,IDOK);
1281+
Result:=False;
1282+
Exit;
1283+
end;
1284+
;
1285+
end else if not Processes[i].Restartable then begin
12771286
SuppressibleMsgBox(
12781287
'Setup cannot continue until you close at least those applications in the list that are marked as "closing is required".'
12791288
, mbCriticalError

installer/modules.inc.iss

+47-1
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,14 @@ const
3737
INVALID_HANDLE_VALUE = -1;
3838
3939
// For OpenProcess().
40+
PROCESS_TERMINATE = $0001;
4041
PROCESS_VM_READ = $0010;
4142
PROCESS_QUERY_INFORMATION = $0400;
43+
SYNCHRONIZE = $00100000;
4244
45+
// For WaitForSingleObject().
46+
WAIT_TIMEOUT = $00000102;
47+
WAIT_FAILED = $ffffffff;
4348
type
4449
HMODULE = DWORD;
4550
LONG = Longint;
@@ -52,7 +57,7 @@ type
5257
ProcessEntry=record
5358
ID:DWORD;
5459
Name:String;
55-
Restartable:Boolean;
60+
Restartable,ToTerminate:Boolean;
5661
end;
5762
ProcessList=array of ProcessEntry;
5863
@@ -532,6 +537,8 @@ begin
532537
Processes[Have].ID:=AppList[i].Process.dwProcessId;
533538
Processes[Have].Name:=ArrayToString(AppList[i].strAppName);
534539
Processes[Have].Restartable:=AppList[i].bRestartable;
540+
if (Pos('ssh-add.exe',Processes[Have].Name)>0) or (Pos('ssh-agent.exe',Processes[Have].Name)>0) then
541+
Processes[Have].ToTerminate:=True;
535542
end;
536543
Result:=Handle;
537544
end;
@@ -654,3 +661,42 @@ begin
654661
Result:=True;
655662
end;
656663
end;
664+
665+
function TerminateProcess(hProcess:THandle;uExitCode:UINT):Boolean;
666+
external '[email protected]';
667+
668+
function WaitForSingleObject(hHandle:THandle;dwMilliseconds:DWORD):DWORD;
669+
external '[email protected]';
670+
671+
function IsProcessRunning(dwProcessId:DWORD):Boolean;
672+
var
673+
ProcList:IdList;
674+
i:Integer;
675+
begin
676+
if not GetProcessList(ProcList) then
677+
Exit;
678+
for i:=0 to GetArraylength(ProcList)-1 do
679+
if dwProcessId=ProcList[i] then begin
680+
Result:=True;
681+
Exit;
682+
end;
683+
Result:=False;
684+
end;
685+
686+
function TerminateProcessByID(dwProcessId:DWORD):Boolean;
687+
var
688+
Process:THandle;
689+
WaitResult:DWORD;
690+
begin
691+
Process:=OpenProcess(SYNCHRONIZE or PROCESS_TERMINATE,False,dwProcessId);
692+
if Process=0 then
693+
Result:=not IsProcessRunning(dwProcessId)
694+
else begin
695+
Result:=TerminateProcess(Process,3)
696+
if not Result then
697+
Exit;
698+
WaitResult:=WaitForSingleObject(Process,5000);
699+
Result:=(WaitResult<>WAIT_TIMEOUT) and (WaitResult<>WAIT_FAILED);
700+
CloseHandle(Process);
701+
end;
702+
end;

0 commit comments

Comments
 (0)