- E.1 File Functions Header
- E.1.1 Introduction
- E.1.2 Locate
- E.1.3 GetSize
- E.1.4 DriveSpace
- E.1.5 GetDrives
- E.1.6 GetTime
- E.1.7 GetFileAttributes
- E.1.8 GetFileVersion
- E.1.9 GetExeName
- E.1.10 GetExePath
- E.1.11 GetParameters
- E.1.12 GetOptions
- E.1.13 GetOptionsS
- E.1.14 GetRoot
- E.1.15 GetParent
- E.1.16 GetFileName
- E.1.17 GetBaseName
- E.1.18 GetFileExt
- E.1.19 BannerTrimPath
- E.1.20 DirState
- E.1.21 RefreshShellIcons
E.1 File Functions Header
E.1.1 Introduction
Include header:
- !include "FileFunc.nsh"
Call functions:
- Section Install
- ${GetFileExt} "C:\My Downloads\Index.html" $R0
- ; $R0="html"
- SectionEnd
- Section un.Install
- ${GetParent} "C:\My Downloads\Index.html" $R0
- ; $R0="C:\My Downloads"
- SectionEnd
E.1.2 Locate
- Find files, directories and empty directories with mask and size options.
Syntax:
- ${Locate} "[Path]" "[Options]" "Function"
- "[Path]" ; Disk or Directory
- ;
- "[Options]" ; /L=[FD|F|D|DE|FDE]
- ; /L=FD - Locate Files and Directories (default)
- ; /L=F - Locate Files only
- ; /L=D - Locate Directories only
- ; /L=DE - Locate Empty Directories only
- ; /L=FDE - Locate Files and Empty Directories
- ; /M=[mask]
- ; /M=*.* - Locate all (default)
- ; /M=*.doc - Locate Work.doc, 1.doc ...
- ; /M=Pho* - Locate PHOTOS, phone.txt ...
- ; /M=win???.exe - Locate winamp.exe, winver.exe ...
- ; /M=winamp.exe - Locate winamp.exe only
- ; /S=No:No[B|K|M|G]
- ; /S= - Don't locate file size (faster) (default)
- ; /S=0:0B - Locate only files of 0 Bytes exactly
- ; /S=5:9K - Locate only files of 5 to 9 Kilobytes
- ; /S=:10M - Locate only files of 10 Megabyte or less
- ; /S=1G - Locate only files of 1 Gigabyte or more
- ; /G=[1|0]
- ; /G=1 - Locate with subdirectories (default)
- ; /G=0 - Locate without subdirectories
- ; /B=[0|1]
- ; /B=0 - Banner isn't used (default)
- ; /B=1 - Banner is used. Callback when function
- ; start to search in new directory
- "Function" ; Callback function when found
- Function "Function"
- ; $R9 "path\name"
- ; $R8 "path"
- ; $R7 "name"
- ; $R6 "size" ($R6="" if directory, $R6="0" if file with /S=)
- ; $R0-$R5 are not used (save data in them).
- ; ...
- Push $var ; If $var="StopLocate" Then exit from function
- FunctionEnd
Note:- Error flag if disk or directory isn't exist - Error flag if syntax error - See also: Locate plugin
Example (Find one file):
- Section
- ${Locate} "C:\ftp" "/L=F /M=RPC DCOM.rar /S=1K" "Example1"
- ; 'RPC DCOM.rar' file in 'C:\ftp' with size 1 Kb or more
- IfErrors 0 +2
- MessageBox MB_OK "Error" IDOK +2
- MessageBox MB_OK "$$R0=$R0"
- SectionEnd
- Function Example1
- StrCpy $R0 $R9
- ; $R0="C:\ftp\files\RPC DCOM.rar"
- MessageBox MB_YESNO '$R0$\n$\nFind next?' IDYES +2
- StrCpy $0 StopLocate
- Push $0
- FunctionEnd
Example (Write results to a text file):
- Section
- GetTempFileName $R0
- FileOpen $R1 $R0 w
- ${Locate} "C:\ftp" "/S=:2M /G=0" "Example2"
- ; folders and all files with size 2 Mb or less
- ; don't scan subdirectories
- FileClose $R1
- IfErrors 0 +2
- MessageBox MB_OK "Error" IDOK +2
- Exec '"notepad.exe" "$R0"'
- SectionEnd
- Function Example2
- StrCmp $R6 '' 0 +3
- FileWrite $R1 "Directory=$R9$\r$\n"
- goto +2
- FileWrite $R1 "File=$R9 Size=$R6 Mb$\r$\n"
- Push $0
- FunctionEnd
Example (Write results to an INI file):
- Section
- GetTempFileName $R0
- ${Locate} "C:\ftp" "/L=F /S=0K" "Example3"
- ; all files in 'C:\ftp' with size detect in Kb
- IfErrors 0 +2
- MessageBox MB_OK "Error" IDOK +2
- Exec '"notepad.exe" "$R0"'
- SectionEnd
- Function Example3
- WriteINIStr $R0 "$R8" "$R7" "$R6 Kb"
- Push $0
- FunctionEnd
Example (Delete empty directories):
- Section
- StrCpy $R2 0
- StrCpy $R3 0
- loop:
- StrCpy $R1 0
- ${Locate} "C:\ftp" "/L=DE" "Example4"
- IntOp $R3 $R3 + 1
- IntOp $R2 $R2 + $R1
- StrCmp $R0 StopLocate +2
- StrCmp $R1 0 0 loop
- IfErrors 0 +2
- MessageBox MB_OK 'error' IDOK +2
- MessageBox MB_OK '$R2 directories were removed$\n$R3 loops'
- SectionEnd
- Function Example4
- MessageBox MB_YESNOCANCEL 'Delete empty "$R9"?' IDNO end IDCANCEL cancel
- RMDir $R9
- IntOp $R1 $R1 + 1
- goto end
- cancel:
- StrCpy $R0 StopLocate
- end:
- Push $R0
- FunctionEnd
Example (Move all files into one folder):
- Section
- StrCpy $R0 "C:\ftp" ;Directory move from
- StrCpy $R1 "C:\ftp2" ;Directory move into
- StrCpy $R2 0
- StrCpy $R3 0
- ${Locate} "$R0" "/L=F" "Example5"
- IfErrors 0 +2
- MessageBox MB_OK 'error' IDOK +4
- StrCmp $R3 0 0 +2
- MessageBox MB_OK '$R2 files were moved' IDOK +2
- MessageBox MB_OK '$R2 files were moved$\n$R3 files were NOT moved'
- SectionEnd
- Function Example5
- StrCmp $R8 $R1 +6
- IfFileExists '$R1\$R7' +4
- Rename $R9 '$R1\$R7'
- IntOp $R2 $R2 + 1
- goto +2
- IntOp $R3 $R3 + 1
- Push $0
- FunctionEnd
Example (Copy files with log):
- Section
- StrCpy $R0 "C:\ftp" ;Directory copy from
- StrCpy $R1 "C:\ftp2" ;Directory copy into
- StrLen $R2 $R0
- GetTempFileName $0
- FileOpen $R3 $0 w
- ${Locate} "$R0" "/L=FDE" "Example6"
- FileClose $R3
- IfErrors 0 +2
- MessageBox MB_OK 'error'
- Exec '"notepad.exe" "$0"' ;view log
- SectionEnd
- Function Example6
- StrCpy $1 $R8 '' $R2
- StrCmp $R6 '' 0 +3
- CreateDirectory '$R1$1\$R7'
- goto end
- CreateDirectory '$R1$1'
- CopyFiles /SILENT $R9 '$R1$1'
- IfFileExists '$R1$1\$R7' 0 +3
- FileWrite $R3 "-old:$R9 -new:$R1$1\$R7 -success$\r$\n"
- goto +2
- FileWrite $R3 "-old:$R9 -new:$R1$1\$R7 -failed$\r$\n"
- end:
- Push $0
- FunctionEnd
Example (Recreate directory structure):
- Section
- StrCpy $R0 "C:\ftp" ;Directory structure from
- StrCpy $R1 "C:\ftp2" ;Directory structure into
- StrLen $R2 $R0
- ${Locate} "$R0" "/L=D" "Example7"
- IfErrors 0 +2
- MessageBox MB_OK 'error'
- SectionEnd
- Function Example7
- StrCpy $1 $R9 '' $R2
- CreateDirectory '$R1$1'
- Push $0
- FunctionEnd
Example (Locate with banner - NxS plugin required):
- Section
- nxs::Show /NOUNLOAD `$(^Name) Setup` /top \
- `Setup searching something$\r$\nPlease wait... If you can..` \
- /h 1 /can 1 /end
- ${Locate} "C:\WINDOWS" "/L=F /M=*.inf /B=1" "Example8"
- nxs::Destroy
- SectionEnd
- Function Example8
- StrCmp $R0 $R8 abortcheck
- StrCpy $R0 $R8
- nxs::Update /NOUNLOAD /sub "$R8" /pos 78 /end
- abortcheck:
- nxs::HasUserAborted /NOUNLOAD
- Pop $0
- StrCmp $0 1 0 +2
- StrCpy $0 StopLocate
- StrCmp $R9 '' end
- ;...
- end:
- Push $0
- FunctionEnd
E.1.3 GetSize
- Find the size of a file, files mask or directory.
- Find the sum of the files, directories and subdirectories.
Syntax:
- ${GetSize} "[Path]" "[Options]" $var1 $var2 $var3
- "[Path]" ; Disk or Directory
- ;
- "[Options]" ; /M=[mask]
- ; /M=*.* - Find all (default)
- ; /M=*.doc - Find Work.doc, 1.doc ...
- ; /M=Pho* - Find PHOTOS, phone.txt ...
- ; /M=win???.exe - Find winamp.exe, winver.exe ...
- ; /M=winamp.exe - Find winamp.exe only
- ; /S=No:No[B|K|M|G]
- ; /S= - Don't find file size (faster) (default)
- ; /S=0:0B - Find only files of 0 Bytes exactly
- ; /S=5:9K - Find only files of 5 to 9 Kilobytes
- ; /S=:10M - Find only files of 10 Megabyte or less
- ; /S=1G - Find only files of 1 Gigabyte or more
- ; /G=[1|0]
- ; /G=1 - Find with subdirectories (default)
- ; /G=0 - Find without subdirectories
- ;
- $var1 ; Result1: Size
- $var2 ; Result2: Sum of files
- $var3 ; Result3: Sum of directories
Note:- Error flag if disk or directory isn't exist - Error flag if syntax error - See also: Locate plugin
Examples:
- Section 'Find file size of "$WINDIR\Explorer.exe" in KiB'
- ${GetSize} "$WINDIR" "/M=Explorer.exe /S=0K /G=0" $0 $1 $2
- ; $0="220" KiB
- ; $1="1" files
- ; $2="" directories
- IfErrors 0 +2
- MessageBox MB_OK "Error"
- SectionEnd
- Section 'Find folder size of "C:\Installs\Drivers" in MiB'
- ${GetSize} "C:\Installs\Drivers" "/S=0M" $0 $1 $2
- ; $0="132" MiB
- ; $1="555" files
- ; $2="55" directories
- IfErrors 0 +2
- MessageBox MB_OK "Error"
- SectionEnd
- Section 'Find sum of files and folders in "$WINDIR" (no subfolders)'
- ${GetSize} "$WINDIR" "/G=0" $0 $1 $2
- ; $0="" size
- ; $1="253" files
- ; $2="46" directories
- IfErrors 0 +2
- MessageBox MB_OK "Error"
- SectionEnd
E.1.4 DriveSpace
- Get total, occupied or free space of the drive.
Syntax:
- ${DriveSpace} "[Drive]" "[Options]" $var
- "[Drive]" ; Disk to check
- ;
- "[Options]" ; /D=[T|O|F]
- ; /D=T - Total space (default)
- ; /D=O - Occupied space
- ; /D=F - Free space
- ; /S=[B|K|M|G]
- ; /S=B - size in Bytes (default)
- ; /S=K - size in Kilobytes
- ; /S=M - size in Megabytes
- ; /S=G - size in Gigabytes
- ;
- $var ; Result: Size
Note:- Error flag if disk isn't exist or not ready - Error flag if syntax error
Example:
- Section
- ${DriveSpace} "C:\" "/D=F /S=M" $R0
- ; $R0="2530" megabytes free on drive C:
- SectionEnd
E.1.5 GetDrives
- Find all available drives in the system.
Syntax:
- ${GetDrives} "[Option]" "Function"
- "[Option]" ; [FDD+HDD+CDROM+NET+RAM]
- ; FDD Floppy Disk Drives
- ; HDD Hard Disk Drives
- ; CDROM CD-ROM Drives
- ; NET Network Drives
- ; RAM RAM Disk Drives
- ;
- ; [ALL]
- ; Find all drives by letter (default)
- ;
- "Function" ; Callback function when found
- Function "Function"
- ; $9 "drive letter" (a:\ c:\ ...)
- ; $8 "drive type" (FDD HDD ...)
- ; $R0-$R9 are not used (save data in them).
- ; ...
- Push $var ; If $var="StopGetDrives" Then exit from function
- FunctionEnd
Example1:
- Section
- ${GetDrives} "FDD+CDROM" "Example1"
- SectionEnd
- Function Example1
- MessageBox MB_OK "$9 ($8 Drive)"
- Push $0
- FunctionEnd
Example2:
- Section
- ${GetDrives} "ALL" "Example2"
- SectionEnd
- Function Example2
- MessageBox MB_OK "$9 ($8 Drive)"
- Push $0
- FunctionEnd
Example3 (Get type of drive):
- Section
- StrCpy $R0 "D:\" ;Drive letter
- StrCpy $R1 "invalid"
- ${GetDrives} "ALL" "Example3"
- MessageBox MB_OK "Type of drive $R0 is $R1"
- SectionEnd
- Function Example3
- StrCmp $9 $R0 0 +3
- StrCpy $R1 $8
- StrCpy $0 StopGetDrives
- Push $0
- FunctionEnd
E.1.6 GetTime
- Get local or system time.
- Get file time (access, creation and modification).
Syntax:
- ${GetTime} "[File]" "[Option]" $var1 $var2 $var3 $var4 $var5 $var6 $var7
- "[File]" ; Ignored if "L" or "LS"
- ;
- "[Option]" ; [Options]
- ; L Local time
- ; A last Access file time
- ; C Creation file time
- ; M Modification file time
- ; LS System time (UTC)
- ; AS last Access file time (UTC)
- ; CS Creation file time (UTC)
- ; MS Modification file time (UTC)
- ;
- $var1 ; Result1: day
- $var2 ; Result2: month
- $var3 ; Result3: year
- $var4 ; Result4: day of week name
- $var5 ; Result5: hour
- $var6 ; Result6: minute
- $var7 ; Result7: seconds
Note:- Error flag if file isn't exist - Error flag if syntax error - See also: Time plugin
Examples:
- Section 'Get local time'
- ${GetTime} "" "L" $0 $1 $2 $3 $4 $5 $6
- ; $0="01" day
- ; $1="04" month
- ; $2="2005" year
- ; $3="Friday" day of week name
- ; $4="16" hour
- ; $5="05" minute
- ; $6="50" seconds
- MessageBox MB_OK 'Date=$0/$1/$2 ($3)$\nTime=$4:$5:$6'
- SectionEnd
- Section 'Get file time'
- ${GetTime} "$WINDIR\Explorer.exe" "C" $0 $1 $2 $3 $4 $5 $6
- ; $0="12" day
- ; $1="10" month
- ; $2="2004" year
- ; $3="Tuesday" day of week name
- ; $4="2" hour
- ; $5="32" minute
- ; $6="03" seconds
- IfErrors 0 +2
- MessageBox MB_OK "Error" IDOK +2
- MessageBox MB_OK 'Date=$0/$1/$2 ($3)$\nTime=$4:$5:$6'
- SectionEnd
- Section 'Get system time'
- ${GetTime} "" "LS" $0 $1 $2 $3 $4 $5 $6
- ; $0="01" day
- ; $1="04" month
- ; $2="2005" year
- ; $3="Friday" day of week name
- ; $4="11" hour
- ; $5="05" minute
- ; $6="50" seconds
- MessageBox MB_OK 'Date=$0/$1/$2 ($3)$\nTime=$4:$5:$6'
- SectionEnd
- Section 'Convert time to 12-hour format AM/PM'
- ${GetTime} "" "L" $0 $1 $2 $3 $4 $5 $6
- StrCmp $4 0 0 +3
- StrCpy $4 12
- goto +3
- StrCmp $4 12 +5
- IntCmp $4 12 0 0 +3
- StrCpy $7 AM
- goto +3
- IntOp $4 $4 - 12
- StrCpy $7 PM
- MessageBox MB_OK 'Date=$0/$1/$2 ($3)$\nTime=$4:$5:$6 $7'
- SectionEnd
E.1.7 GetFileAttributes
- Get attributes of file or directory.
Syntax:
- ${GetFileAttributes} "[File]" "[Attributes]" $var
- "[File]" ; File or directory
- ;
- "[Attributes]" ; "ALL" (default)
- ; -all attributes of file combined with "|" to output
- ;
- ; "READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE|
- ; DEVICE|NORMAL|TEMPORARY|SPARSE_FILE|REPARSE_POINT|
- ; COMPRESSED|OFFLINE|NOT_CONTENT_INDEXED|ENCRYPTED"
- ; -file must have specified attributes
- ;
- $var ; Result:
- ; $var=attr1|attr2|... (if used "ALL")
- ; $var=1 file has specified attributes
- ; $var=0 file has no specified attributes
Note:- Error flag is set if file doesn't exist
Example:
- Section
- ${GetFileAttributes} "C:\MSDOS.SYS" "ALL" $R0
- ; $R0=READONLY|HIDDEN|SYSTEM|ARCHIVE
- ${GetFileAttributes} "C:\MSDOS.SYS" "SYSTEM|HIDDEN" $R0
- ; $R0=1
- ${GetFileAttributes} "C:\MSDOS.SYS" "NORMAL" $R0
- ; $R0=0
- SectionEnd
E.1.8 GetFileVersion
- Get version information from executable file.
Syntax:
- ${GetFileVersion} "[Executable]" $var
- "[Executable]" ; Executable file (*.exe *.dll ...)
- $var ; Result: Version number
Note:- Error flag if file doesn't exist - Error flag if file doesn't contain version information
Example:
- ${GetFileVersion} "C:\ftp\program.exe" $R0 ; $R0="1.1.0.12"
E.1.9 GetExeName
- Get installer filename (with valid case for Windows 98/Me).
Syntax:
- ${GetExeName} $var
Example:
- ${GetExeName} $R0 ; $R0="C:\ftp\program.exe"
E.1.10 GetExePath
- Get installer pathname ($EXEDIR with valid case for Windows 98/Me).
Syntax:
- ${GetExePath} $var
Example:
- ${GetExePath} $R0 ; $R0="C:\ftp"
E.1.11 GetParameters
- Get command line parameters.
Syntax:
- ${GetParameters} $var
Example:
- ${GetParameters} $R0 ; $R0="[parameters]"
E.1.12 GetOptions
- Get options from command line parameters.
Syntax:
- ${GetOptions} "[Parameters]" "[Option]" $var
- "[Parameters]" ; command line parameters
- ;
- "[Option]" ; option name
- ;
- $var ; Result: option string
Note:- The error flag is set if the option is not found - The first character in the option string is treated as a parameter delimiter
Example1:
- Section
- ${GetOptions} "/S /T" "/T" $R0
- IfErrors 0 +2
- MessageBox MB_OK "Not found" IDOK +2
- MessageBox MB_OK "Found"
- SectionEnd
Example2:
- Section
- ${GetOptions} "-INSTDIR=C:\Program Files\Common Files -SILENT=yes" "-INSTDIR=" $R0
- ;$R0=C:\Program Files\Common Files
- SectionEnd
Example3:
- Section
- ${GetOptions} '/SILENT=yes /INSTDIR="C:/Program Files/Common Files" /ADMIN=password' "/INSTDIR=" $R0
- ;$R0=C:/Program Files/Common Files
- SectionEnd
Example4:
- Section
- ${GetOptions} `-SILENT=yes -INSTDIR='"C:/Program Files/Common Files"' -ADMIN=password` "-INSTDIR=" $R0
- ;$R0="C:/Program Files/Common Files"
- SectionEnd
E.1.13 GetOptionsS
- Same as GetOptions, but case sensitive.
E.1.14 GetRoot
- Get root directory.
Syntax:
- ${GetRoot} "[FullPath]" $var
Examples:
- ${GetRoot} "C:\Program Files\NSIS" $R0 ; $R0="C:"
- ${GetRoot} "\\SuperPimp\NSIS\Source\exehead\Ui.c" $R0 ; $R0="\\SuperPimp\NSIS"
E.1.15 GetParent
- Get parent directory.
Syntax:
- ${GetParent} "[PathString]" $var
Example:
- ${GetParent} "C:\Program Files\Winamp\uninstwa.exe" $R0 ; $R0="C:\Program Files\Winamp"
E.1.16 GetFileName
- Get last part from directory path.
Syntax:
- ${GetFileName} "[PathString]" $var
Example:
- ${GetFileName} "C:\Program Files\Winamp\uninstwa.exe" $R0 ; $R0="uninstwa.exe"
E.1.17 GetBaseName
- Get file name without extension.
Syntax:
- ${GetBaseName} "[FileString]" $var
Example:
- ${GetBaseName} "C:\ftp\program.exe" $R0 ; $R0="program"
E.1.18 GetFileExt
- Get extension of file.
Syntax:
- ${GetFileExt} "[FileString]" $var
Example:
- ${GetFileExt} "C:\ftp\program.exe" $R0 ; $R0="exe"
E.1.19 BannerTrimPath
- Trim string path for banner.
Syntax:
- ${BannerTrimPath} "[PathString]" "[Option]" $var
- "[PathString]" ;
- ;
- "[Option]" ; [Length][A|B|C|D]
- ;
- ; Length -Maximum string length
- ; A -Trim center path (default)
- ; (C:\root\...\third path)
- ; If A mode not possible Then will be used B mode
- ; B -Trim right path
- ; (C:\root\second path\...)
- ; If B mode not possible Then will be used C mode
- ; C -Trim right string
- ; (C:\root\second path\third p...)
- ; D -Trim right string + filename
- ; (C:\root\second p...\third path)
- ; If D mode not possible Then will be used C mode
- ;
- $var ; Result: Trimmed path
Example:
- Section
- ${BannerTrimPath} "C:\Server\Documents\Terminal\license.htm" "35A" $R0
- ;$R0=C:\Server\...\Terminal\license.htm
- SectionEnd
Example (Banner plugin):
- !include "WinMessages.nsh"
- !include "FileFunc.nsh"
- Section
- Banner::show "Starting..."
- Banner::getWindow
- Pop $R1
- ${Locate} "$WINDIR" "/L=F /M=*.* /B=1" "LocateCallback"
- Banner::destroy
- SectionEnd
- Function LocateCallback
- StrCmp $R0 $R8 code
- StrCpy $R0 $R8
- ${BannerTrimPath} "$R8" "38B" $R8
- GetDlgItem $1 $R1 1030
- SendMessage $1 ${WM_SETTEXT} 0 "STR:$R8"
- code:
- StrCmp $R9 '' end
- ;...
- end:
- Push $0
- FunctionEnd
Example (NxS plugin):
- !include "FileFunc.nsh"
- Section
- nxs::Show /NOUNLOAD `$(^Name) Setup`\
- /top `Setup searching something$\nPlease wait$\nIf you can...`\
- /h 1 /can 1 /end
- ${Locate} "$WINDIR" "/L=F /M=*.* /B=1" "LocateCallback"
- nxs::Destroy
- SectionEnd
- Function LocateCallback
- StrCmp $R0 $R8 abortcheck
- StrCpy $R0 $R8
- ${BannerTrimPath} "$R8" "55A" $R8
- nxs::Update /NOUNLOAD /sub "$R8" /pos 78 /end
- abortcheck:
- nxs::HasUserAborted /NOUNLOAD
- Pop $0
- StrCmp $0 1 0 +2
- StrCpy $0 StopLocate
- StrCmp $R9 '' end
- ;...
- end:
- Push $0
- FunctionEnd
E.1.20 DirState
- Check directory full, empty or not exist.
Syntax:
- ${DirState} "[path]" $var
- "[path]" ; Directory
- $var ; Result:
- ; $var=0 (empty)
- ; $var=1 (full)
- ; $var=-1 (directory not found)
Example:
- ${DirState} "$TEMP" $R0 ; $R0="1" (directory is full)
E.1.21 RefreshShellIcons
- After changing file associations, you can call this function to refresh the shell immediately.
Syntax:
- ${RefreshShellIcons}
Example:
- Section
- WriteRegStr HKCR "Winamp.File\DefaultIcon" "" "$INSTDIR\WINAMP.EXE,2"
- ${RefreshShellIcons}
- SectionEnd