Escape ARP Job With New Process

From NSIS Wiki
Jump to navigationJump to search
Author: Anders (talk, contrib)


This function tries to set the JOB_OBJECT_LIMIT_BREAKAWAY_OK flag on the job object the Add/Remove programs application creates for an uninstall process so the user can interact with the ARP applet even when there are running child processes created by the uninstaller.

WARNING: This code has only been tested on XP SP2, before using this code you should check Windows2000 and Vista to make sure one has access to the job object on these systems (and that the name of the object is the same)

WARNING2: This code uses System::Store to try to preserve the registers, but the WinVer macros do not use the /NOUNLOAD flag, you might want to use SetPluginUnload alwaysoff , or replace the ${AtLeastWin2000} macro

!include WinVer.nsh
Function un.ExecExitARPJob ;_exec
System::Store /NOUNLOAD S
pop $R1
StrCpy $9 0 ;hJob
StrCpy $R0 1 ;error?
${If} ${AtLeastWin2000}
	System::Call /NOUNLOAD 'kernel32::OpenJobObject(i 2,i 0,t "ARP Job")i.r9 ?e' ;JOB_OBJECT_SET_ATTRIBUTES=2
	pop $R0
	${If} $9 != 0
		StrCpy $R0 1 ;reset error
		System::Alloc /NOUNLOAD 112
		pop $4
		${IfThen} $4 = 0 ${|} goto again ${|}
		System::Call /NOUNLOAD "*$4(i,i,i,i,i 0x800)" ;JOB_OBJECT_LIMIT_BREAKAWAY_OK=0x800
		System::Call /NOUNLOAD 'kernel32::SetInformationJobObject(i $9,i 9,i $4,i 112)i.r0' ;JobObjectExtendedLimitInformation=9
		System::Free /NOUNLOAD $4
		System::Call /NOUNLOAD '*(i,i,i,i)i.r1'
		System::Alloc /NOUNLOAD 72
		pop $4
		System::Call /NOUNLOAD "*$4(i 72)"
		System::Call /NOUNLOAD 'kernel32::CreateProcess(i0,t R1,i0,i0,i0,i 0x01000000,i0,i0,i $4,i $1)i.r0 ?e' ;CREATE_BREAKAWAY_FROM_JOB=0x1000000
		pop $R0
		System::Free /NOUNLOAD $4
		System::Call /NOUNLOAD "*$1(i.r3,i.r4,i,i)"
		System::Free /NOUNLOAD $1
		${IfThen} $0 = 0 ${|} goto again ${|}
		System::Call /NOUNLOAD 'kernel32::CloseHandle(i $3)'
		System::Call /NOUNLOAD 'kernel32::CloseHandle(i $4)'
		StrCpy $R0 0
		${EndIf}
	${EndIf}
again:
${If} $R0 != 0
	ClearErrors
	Exec '$R1'
	${Unless} ${Errors} 
		StrCpy $R0 0
		${EndIf}
	${EndIf}
${IfThen} $9 != 0 ${|} System::Call /NOUNLOAD "kernel32::CloseHandle(i $9)" ${|}
;push $R0 ;push result to stack, 0 on success
System::Store L
FunctionEnd
 
Section Uninstall
push "notepad.exe"
call un.ExecExitARPJob
SectionEnd