; Copyleft (c) n/a-n/a Azure Zanculmarktum

!define BUILDDATE "24 mai 2013"
!define APPNAME "Sandboxie"
!define APP "Sandboxie"
!define APPVER "0.0.0.0"
!define VER "1.2"
!define APPEXE "SbieCtrl.exe"
!define APPDIR "Sandboxie"
!define APPEXE64 "SbieCtrl.exe"
!define APPDIR64 "Sandboxie64"
!define RUNASADMIN

; === Define Registry ===
!define REGKEY1 "HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{98E6BD24-2D93-41A5-BC6D-CB7C1507318B}"

; Value:
!define REGKEYVALUE1 "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run"
!define REGVALUE1 "SandboxieControl"

; Shell:
!define REGKEYSHELLROOT1 "HKEY_CURRENT_USER"
!define REGKEYSHELL1 "*"                 # \Software\Classes\*
!define REGSHELL1 "sandbox"              #                    \shell\sandbox

!define REGKEYSHELLROOT2 "HKEY_CURRENT_USER"
!define REGKEYSHELL2 "Folder"            # \Software\Classes\Folder
!define REGSHELL2 "sandbox"              #                         \shell\sandbox

; === Define Directory ===
!define LOCALDIR1 "$SENDTO\Sandboxie"
!define SUBDIR1 "" ; beginning with back-slash

; === Define File ===
!define LOCALFILE1 "$WINDIR\Sandboxie.ini"
!define PORTABLEFILE1 "$EXEDIR\Data\Sandboxie.ini"

!define LOCALFILE2 "$SENDTO\Sandboxie - DefaultBox.lnk"

; === Define Services ===
!define SRC1 "SbieDrv"
!define SRCFILE1 "${SRC1}.sys"
!define PORTABLESRC1 "$PROGRAMDIR\${SRCFILE1}"

!define SRC2 "SbieSvc"
!define SRCFILE2 "${SRC2}.exe"
!define PORTABLESRC2 "$PROGRAMDIR\${SRCFILE2}"

; === Best Compression ===
SetCompress auto
SetCompressor /SOLID lzma
SetCompressorDictSize 32
SetDatablockOptimize on

; === Include ===
!include Include\Launcher.nsh
!include Include\Macros.nsh

; === Set basic information ===
Name "${APPNAME} Portable"
OutFile "..\..\${APP}Portable.exe"
Icon "${APP}.ico"

Function FixVar
	; === Fix variables when running on x64 machine ===
	StrCmp $ARCHITECTURE "x64" "" +3
		StrCpy $PROGRAMDIR "$PROGRAMDIR64"
		StrCpy $PROGRAMEXE "$PROGRAMEXE64"
FunctionEnd

Function Init
	; === Backup local registry keys ===
	StrCmp $ARCHITECTURE "x64" "" +2
		SetRegView 64
	${registry::BackupLocal} "${REGKEY1}"
	StrCmp $ARCHITECTURE "x64" "" +2
		SetRegView 32

	; Value:
	${registry::BackupValue} "${REGKEYVALUE1}" "${REGVALUE1}"

	; Shell:
	${registry::BackupShell} "${REGKEYSHELLROOT1}" "${REGKEYSHELL1}" "${REGSHELL1}"
	${registry::BackupShell} "${REGKEYSHELLROOT2}" "${REGKEYSHELL2}" "${REGSHELL2}"

	; === Backup local directory ===
	${directory::BackupLocal} "${LOCALDIR1}" "${SUBDIR1}"

	; === Backup local file ===
	${file::BackupLocal} "${LOCALFILE1}"
	${file::BackupLocal} "${LOCALFILE2}"

	; === Force to use default settings ===
	CreateDirectory "$SETTINGSDIR"
		IfFileExists "${PORTABLEFILE1}" +2
			File "/oname=${PORTABLEFILE1}" "Sandboxie.ini"
	WriteINIStr "${PORTABLEFILE1}" "GlobalSettings" "FileRootPath" "$SETTINGSDIR\%SANDBOX%"

	; === Restore portable file ===
	${file::RestorePortable} "${PORTABLEFILE1}" "${LOCALFILE1}"

	; === Delete local service ===
	registry::_KeyExists /NOUNLOAD "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Sandboxie"
	Pop $0
	StrCmp $0 "-1" +13 ; skip next 12 lines if key doesn't exist
		ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Sandboxie" "DisplayIcon"
		StrCpy $0 "$0" -10
		ReadRegStr $1 HKEY_LOCAL_MACHINE "SYSTEM\CurrentControlSet\services\SbieSvc" "Language"
		CreateDirectory "$EXEDIR\Data"
			WriteINIStr "$EXEDIR\Data\${APP}PortableRuntimeData.ini" "${APP}Portable" "LocalServiceDirectory" "$0"
			WriteINIStr "$EXEDIR\Data\${APP}PortableRuntimeData.ini" "${APP}Portable" "LocalServiceLanguage" "$1"
		ExecWait `"$PROGRAMDIR\KmdUtil.exe" scandll`
		ExecWait `"$PROGRAMDIR\KmdUtil.exe" stop ${SRC2}`
		ExecWait `"$PROGRAMDIR\KmdUtil.exe" stop ${SRC2}`
		ExecWait `"$PROGRAMDIR\KmdUtil.exe" stop ${SRC1}`
		ExecWait `"$PROGRAMDIR\KmdUtil.exe" delete ${SRC2}`
		ExecWait `"$PROGRAMDIR\KmdUtil.exe" delete ${SRC1}`

	; === Create portable service ===
	ExecWait `"$PROGRAMDIR\KmdUtil.exe" scandll`
	ExecWait `"$PROGRAMDIR\KmdUtil.exe" stop ${SRC2}`
	ExecWait `"$PROGRAMDIR\KmdUtil.exe" install ${SRC1} "${PORTABLESRC1}" type=kernel start=demand "msgfile=$PROGRAMDIR\SbieMsg.dll" altitude=86900`
	ExecWait `"$PROGRAMDIR\KmdUtil.exe" install ${SRC2} "\"${PORTABLESRC2}"\" type=own start=auto "display=Sandboxie Service" group=UIGroup "msgfile=$PROGRAMDIR\SbieMsg.dll"`
	ExecWait `"$PROGRAMDIR\KmdUtil.exe" start ${SRC2}`
	WriteRegDWORD HKEY_LOCAL_MACHINE "SYSTEM\CurrentControlSet\services\SbieSvc" "PreferExternalManifest" 0x1

	; === UserDefaultLang and Language ===
	; Launcher will change app language according Windows language,
	; see also: http://medicinecollections.zat.su/lngcode.html
	ReadINIStr $0 "$EXEDIR\${APP}Portable.ini" "${APP}Portable" "UserDefaultLang"
	StrCmp $0 "" "" +3
		WriteINIStr "$EXEDIR\${APP}Portable.ini" "${APP}Portable" "UserDefaultLang" "true"
		StrCpy $0 "true"
	ReadINIStr $1 "$EXEDIR\${APP}Portable.ini" "${APP}Portable" "LanguageID"
	StrCmp $1 "" "" +3
		WriteINIStr "$EXEDIR\${APP}Portable.ini" "${APP}Portable" "LanguageID" "1033"
		StrCpy $1 "1033"
	StrCmp $0 "true" ChangeLanguage Language
	Language:
		StrCpy $LANGID "$1"
	ChangeLanguage:
		WriteRegDWORD HKEY_LOCAL_MACHINE "SYSTEM\CurrentControlSet\services\SbieSvc" "Language" "$LANGID"
		WriteINIStr "$EXEDIR\${APP}Portable.ini" "${APP}Portable" "LanguageID" "$LANGID"

	; === Add "Run Sandboxed" on right-click of the file and folder ===
	WriteRegStr HKEY_CURRENT_USER "Software\Classes\*\shell\sandbox" "" "Run &Sandboxed"
	WriteRegStr HKEY_CURRENT_USER "Software\Classes\*\shell\sandbox" "Icon" "$PROGRAMDIR\Start.exe"
	WriteRegStr HKEY_CURRENT_USER "Software\Classes\*\shell\sandbox\command" "" `"$PROGRAMDIR\Start.exe" /box:__ask__ "%1" %*`
	WriteRegStr HKEY_CURRENT_USER "Software\Classes\Folder\shell\sandbox" "" "Run &Sandboxed"
	WriteRegStr HKEY_CURRENT_USER "Software\Classes\Folder\shell\sandbox" "Icon" "$PROGRAMDIR\Start.exe"
	WriteRegStr HKEY_CURRENT_USER "Software\Classes\Folder\shell\sandbox\command" "" `"$PROGRAMDIR\Start.exe" /box:__ask__ "$WINDIR\explorer.exe" "%1"`
FunctionEnd

Section "Main"
	Call DefaultVar

	Call FixVar

	Call CheckStart

	; === Check running other instances of app ===
	FindProcDLL::FindProc "SandboxieBITS.exe"
	StrCmp $R0 "1" OtherInstancesRunning

	FindProcDLL::FindProc "SandboxieCrypto.exe"
	StrCmp $R0 "1" OtherInstancesRunning

	FindProcDLL::FindProc "SandboxieDcomLaunch.exe"
	StrCmp $R0 "1" OtherInstancesRunning

	FindProcDLL::FindProc "SandboxieRpcSs.exe"
	StrCmp $R0 "1" OtherInstancesRunning

	FindProcDLL::FindProc "SandboxieWUAU.exe"
	StrCmp $R0 "1" OtherInstancesRunning

		Goto OtherInstancesNotRunning

	OtherInstancesRunning:
		${System::MessageBox} "${MB_OK}|${MB_ICONINFORMATION}" "App is running | PerkedleApps" "Another instances of ${APPNAME} is already running.$\nPlease close other instances of ${APPNAME} before running ${APPNAME} Portable." $0
		Abort

	OtherInstancesNotRunning:

	Call Init

	Call RuntimeData

	Call SplashScreen

	; === Launch ===
	SetOutPath "$PROGRAMDIR" ; lock rename!
	ReadINIStr $0 "$EXEDIR\${APP}Portable.ini" "${APP}Portable" "ExecAsAdmin"
	StrCmp $0 "" "" +2
		WriteINIStr "$EXEDIR\${APP}Portable.ini" "${APP}Portable" "ExecAsAdmin" "false"
	StrCmp $0 "true" ExecWaitAsAdmin ExecWaitAsUser
	ExecWaitAsUser:
		StrCpy $PROGRAMSWITCH "$PROGRAMSWITCH" "" 1 ; remove first space
		StrCmp `$PARAMETERS` `` ExecWaitAsUserWithoutParameters ExecWaitAsUserWithParameters
		ExecWaitAsUserWithoutParameters:
			StdUtils::ExecShellAsUser /NOUNLOAD `$PROGRAMSWITCH` "" "$PROGRAMDIR\$PROGRAMEXE"
			Goto CheckStillRunning
		ExecWaitAsUserWithParameters:
			StdUtils::ExecShellAsUser /NOUNLOAD `$PROGRAMSWITCH $PARAMETERS` "" "$PROGRAMDIR\$PROGRAMEXE"
			Goto CheckStillRunning
	ExecWaitAsAdmin:
		StrCmp `$PARAMETERS` `` ExecWaitAsAdminWithoutParameters ExecWaitAsAdminWithParameters
		ExecWaitAsAdminWithoutParameters:
			ExecWait `"$PROGRAMDIR\$PROGRAMEXE"$PROGRAMSWITCH`
			Goto CheckStillRunning
		ExecWaitAsAdminWithParameters:
			ExecWait `"$PROGRAMDIR\$PROGRAMEXE"$PROGRAMSWITCH $PARAMETERS`
	CheckStillRunning:
		; Wait until app closed:
		FindProcDLL::WaitProcEnd "$PROGRAMEXE" -1 ; FindProcDLL modified by hnedka
		FindProcDLL::WaitProcEnd "SandboxieBITS.exe" -1
		FindProcDLL::WaitProcEnd "SandboxieCrypto.exe" -1
		FindProcDLL::WaitProcEnd "SandboxieDcomLaunch.exe" -1
		FindProcDLL::WaitProcEnd "SandboxieRpcSs.exe" -1
		FindProcDLL::WaitProcEnd "SandboxieWUAU.exe" -1
		FindProcDLL::FindProc "$PROGRAMEXE"
		StrCmp $R0 "1" "" +3
			Sleep 2000
			Goto CheckStillRunning
		FindProcDLL::FindProc "SandboxieBITS.exe"
		StrCmp $R0 "1" "" +3
			Sleep 2000
			Goto CheckStillRunning
		FindProcDLL::FindProc "SandboxieCrypto.exe"
		StrCmp $R0 "1" "" +3
			Sleep 2000
			Goto CheckStillRunning
		FindProcDLL::FindProc "SandboxieDcomLaunch.exe"
		StrCmp $R0 "1" "" +3
			Sleep 2000
			Goto CheckStillRunning
		FindProcDLL::FindProc "SandboxieRpcSs.exe"
		StrCmp $R0 "1" "" +3
			Sleep 2000
			Goto CheckStillRunning
		FindProcDLL::FindProc "SandboxieWUAU.exe"
		StrCmp $R0 "1" "" +3
			Sleep 2000
			Goto CheckStillRunning

	Call Close

	Call CleanUp

	Call TheEnd
SectionEnd

Function Close
	; === Delete portable service ===
	ExecWait `"$PROGRAMDIR\KmdUtil.exe" scandll`
	ExecWait `"$PROGRAMDIR\KmdUtil.exe" stop ${SRC2}`
	ExecWait `"$PROGRAMDIR\KmdUtil.exe" stop ${SRC2}`
	ExecWait `"$PROGRAMDIR\KmdUtil.exe" stop ${SRC1}`
	ExecWait `"$PROGRAMDIR\KmdUtil.exe" delete ${SRC2}`
	ExecWait `"$PROGRAMDIR\KmdUtil.exe" delete ${SRC1}`

	; === Create local service ===
	ReadINIStr $0 "$EXEDIR\Data\${APP}PortableRuntimeData.ini" "${APP}Portable" "LocalServiceDirectory"
	StrCmp $0 "" +9
		ExecWait `"$PROGRAMDIR\KmdUtil.exe" scandll`
		ExecWait `"$PROGRAMDIR\KmdUtil.exe" stop ${SRC2}`
		ExecWait `"$PROGRAMDIR\KmdUtil.exe" install ${SRC1} "$0\${SRCFILE1}" type=kernel start=demand "msgfile=$PROGRAMDIR\SbieMsg.dll" altitude=86900`
		ExecWait `"$PROGRAMDIR\KmdUtil.exe" install ${SRC2} "\"$0\${SRCFILE2}"\" type=own start=auto "display=Sandboxie Service" group=UIGroup "msgfile=$PROGRAMDIR\SbieMsg.dll"`
		ExecWait `"$PROGRAMDIR\KmdUtil.exe" start ${SRC2}`
		WriteRegDWORD HKEY_LOCAL_MACHINE "SYSTEM\CurrentControlSet\services\SbieSvc" "PreferExternalManifest" 0x1
		ReadINIStr $1 "$EXEDIR\Data\${APP}PortableRuntimeData.ini" "${APP}Portable" "LocalServiceLanguage"
			WriteRegDWORD HKEY_LOCAL_MACHINE "SYSTEM\CurrentControlSet\services\SbieSvc" "Language" "$1"

	; === Backup portable file ===
	${file::BackupPortable} "${PORTABLEFILE1}" "${LOCALFILE1}"

	; === Restore local file ===
	${file::RestoreLocal} "${LOCALFILE1}"
	${file::RestoreLocal} "${LOCALFILE2}"

	; === Restore local directory ===
	${directory::RestoreLocal} "${LOCALDIR1}" "${SUBDIR1}"

	; === Restore local registry keys ===
	StrCmp $ARCHITECTURE "x64" "" +2
		SetRegView 64
	${registry::RestoreLocal} "${REGKEY1}"
	StrCmp $ARCHITECTURE "x64" "" +2
		SetRegView 32

	; Value:
	${registry::RestoreValue} "${REGKEYVALUE1}" "${REGVALUE1}"

	; Shell:
	${registry::RestoreShell} "${REGKEYSHELLROOT1}" "${REGKEYSHELL1}" "${REGSHELL1}"
	${registry::RestoreShell} "${REGKEYSHELLROOT2}" "${REGKEYSHELL2}" "${REGSHELL2}"
FunctionEnd

Function CleanUp
	; === Delete registry key if empty ===
	registry::_DeleteKeyEmpty /NOUNLOAD "HKEY_CURRENT_USER\Software\Classes\*\shell"
	registry::_DeleteKeyEmpty /NOUNLOAD "HKEY_CURRENT_USER\Software\Classes\*"
	registry::_DeleteKeyEmpty /NOUNLOAD "HKEY_CURRENT_USER\Software\Classes\Folder\shell"
	registry::_DeleteKeyEmpty /NOUNLOAD "HKEY_CURRENT_USER\Software\Classes\Folder"
FunctionEnd

Function TheEnd
	; === Unload plug-ins ===
	newadvsplash::stop ; unload splash screen
	registry::_Unload ; unload registry plug-in

	; === Remove runtime data ===
	FileClose $RUNTIMEDATA ; unlock file
		Delete "$EXEDIR\Data\${APP}PortableRuntimeData.ini"
FunctionEnd
