http://muldersoft.com/ | http://sourceforge.net/projects/muldersoft/ | http://nsis.sourceforge.net/Category:Plugins Earth Heals Herself


StdUtils - Swiss Army Knife for NSIS

This plug-in provides access to a number of "standard" functions from the C Standard Library, which programmers are used to from C/C++ and other "high level" languages, but which are not normally available in NSIS. In order to keep the plug-in size as small as possible and for maximum compatibility, the Visual C++ Runtime v6.0 "MSVCRT.DLL" is used, which is an integral part of all versions of Windows (since Windows 2000). This means that the C++ Runtime neither needs to be shipped as a separate DLL nor does it need to be linked statically into the plug-in.

Many additional functions, not directly related to the C Standard Library, have been added over the years: For example, this plug-in provides a number convenience functions to deal with strings, such as trimming whitespace or validating a given file name. There also are some functions to conveniently access the command-line parameters that have been passed to the installer. Furthermore, there is a wrapper for the SHFileOperation function, which can be used to copy or move files using the Windows Shell, as well as a function to efficiently append the contents of one file to another file. Moreover, the plug-in provides a method for launching programs in a non-elevated way (aka "user mode") from an installer that is running in elevated context (aka "admin mode"). In addition to that, there is a set of functions that can be used to detect the real Windows version that the installer is running on, which still work correctly/reliably on Windows 8.1 (and later) where Microsoft has broken the GetVersionEx() system function. And, as if this wasn't enough, the plug-in can compute the cryptographic hash of a given file or text message, using various state-of-the-art hash functions, including SHA-{1,2,3}. Last but not least, the plug-in provides a variant of ExecShell with "wait for process termination" feature, based on ShellExecuteEx, as well as a function for invoking "shell verbs" – useful for programmatically pinning shortcuts to the Taskbar.

Overall I use this plug-in as my "Swiss Army Knife" for all the small things I needed in my NSIS-based installers but that NSIS didn't provide out-of-the-box. ANSI and Unicode builds are provided. Supports all Windows versions, starting with Windows XP.


Table of Contents:

Available Functions

The following functions are provided by the StdUtils plug-in:

!define StdUtils.Time             #time(), as in C standard library
!define StdUtils.GetMinutes       #GetSystemTimeAsFileTime(), returns the number of minutes
!define StdUtils.GetHours         #GetSystemTimeAsFileTime(), returns the number of hours
!define StdUtils.GetDays          #GetSystemTimeAsFileTime(), returns the number of days
!define StdUtils.Rand             #rand(), as in C standard library
!define StdUtils.RandMax          #rand(), as in C standard library, with maximum value
!define StdUtils.RandMinMax       #rand(), as in C standard library, with minimum/maximum value
!define StdUtils.RandList         #rand(), as in C standard library, with list support
!define StdUtils.RandBytes        #Generates random bytes, returned as Base64-encoded string
!define StdUtils.FormatStr        #sprintf(), as in C standard library, one '%d' placeholder
!define StdUtils.FormatStr2       #sprintf(), as in C standard library, two '%d' placeholders
!define StdUtils.FormatStr3       #sprintf(), as in C standard library, three '%d' placeholders
!define StdUtils.ScanStr          #sscanf(), as in C standard library, one '%d' placeholder
!define StdUtils.ScanStr2         #sscanf(), as in C standard library, two '%d' placeholders
!define StdUtils.ScanStr3         #sscanf(), as in C standard library, three '%d' placeholders
!define StdUtils.TrimStr          #Remove whitspaces from string, left and right
!define StdUtils.TrimStrLeft      #Remove whitspaces from string, left side only
!define StdUtils.TrimStrRight     #Remove whitspaces from string, right side only
!define StdUtils.RevStr           #Reverse a string, e.g. "reverse me" <-> "em esrever"
!define StdUtils.ValidFileName    #Test whether string is a valid file name - no paths allowed
!define StdUtils.ValidPathSpec    #Test whether string is a valid full(!) path specification
!define StdUtils.ValidDomainName  #Test whether string is a valid host name or domain name
!define StdUtils.StrToUtf8        #Convert string from Unicode (UTF-16) or ANSI to UTF-8 bytes
!define StdUtils.StrFromUtf8      #Convert string from UTF-8 bytes to Unicode (UTF-16) or ANSI
!define StdUtils.SHFileMove       #SHFileOperation(), using the FO_MOVE operation
!define StdUtils.SHFileCopy       #SHFileOperation(), using the FO_COPY operation
!define StdUtils.AppendToFile     #Append contents of an existing file to another file
!define StdUtils.ExecShellAsUser  #ShellExecute() as NON-elevated user from elevated installer
!define StdUtils.InvokeShellVerb  #Invokes a "shell verb", e.g. for pinning items to the taskbar
!define StdUtils.ExecShellWaitEx  #ShellExecuteEx(), returns the handle of the new process
!define StdUtils.WaitForProcEx    #WaitForSingleObject(), e.g. to wait for a running process
!define StdUtils.GetParameter     #Get the value of a specific command-line option
!define StdUtils.TestParameter    #Test whether a specific command-line option has been set
!define StdUtils.ParameterCnt     #Get number of command-line tokens, similar to argc in main()
!define StdUtils.ParameterStr     #Get the n-th command-line token, similar to argv[i] in main()
!define StdUtils.GetAllParameters #Get complete command-line, but without executable name
!define StdUtils.GetRealOSVersion #Get the *real* Windows version number, even on Windows 8.1+
!define StdUtils.GetRealOSBuildNo #Get the *real* Windows build number, even on Windows 8.1+
!define StdUtils.GetRealOSName    #Get the *real* Windows version, as a "friendly" name
!define StdUtils.GetOSEdition     #Get the Windows edition, i.e. "workstation" or "server"
!define StdUtils.GetOSReleaseId   #Get the Windows release identifier (on Windows 10)
!define StdUtils.GetOSReleaseName #Get the Windows release (on Windows 10), as a "friendly" name
!define StdUtils.VerifyOSVersion  #Compare *real* operating system to an expected version number
!define StdUtils.VerifyOSBuildNo  #Compare *real* operating system to an expected build number
!define StdUtils.HashText         #Compute hash from text string (CRC32, MD5, SHA1/2/3, BLAKE2)
!define StdUtils.HashFile         #Compute hash from file (CRC32, MD5, SHA1/2/3, BLAKE2)
!define StdUtils.NormalizePath    #Simplifies the path to produce a direct, well-formed path
!define StdUtils.GetParentPath    #Get parent path by removing the last component from the path
!define StdUtils.SplitPath        #Split the components of the given path
!define StdUtils.GetDrivePart     #Get drive component of path
!define StdUtils.GetDirectoryPart #Get directory component of path
!define StdUtils.GetFileNamePart  #Get file name component of path
!define StdUtils.GetExtensionPart #Get file extension component of path
!define StdUtils.TimerCreate      #Create a new event-timer that will be triggered periodically
!define StdUtils.TimerDestroy     #Destroy a running timer created with TimerCreate()
!define StdUtils.ProtectStr       #Protect a given String using Windows' DPAPI
!define StdUtils.UnprotectStr     #Unprotect a string that was protected via ProtectStr()
!define StdUtils.GetLibVersion    #Get the current StdUtils library version (for debugging)
!define StdUtils.SetVerbose       #Enable or disable "verbose" mode (for debugging)

Please see the descriptions below for details on the individual functions!


Installation

Depending on whether you are using the Unicode or the ANSI (non-Unicode) variant of NSIS, you must copy either Plugins\Release_Unicode\StdUtils.dll or Plugins\Release_ANSI\StdUtils.dll into the Plugins sub-directory inside your NSIS installation. Using the Unicode version is highly recommended these days! Also, in both cases, you must copy Include\StdUtils.nsh into the Include sub-directory inside your NSIS installation. Please note that NSIS v2.x does not officially support Unicode, but you can (and should!) use Unicode NSIS. Unicode support will officially be added to NSIS v3.x, which currently is still in development stage. Therefore, the Unicode version of this plug-in has been developed and tested with Unicode NSIS v2.x, not with NSIS v3.x. Support for NSIS v3.x is going to be added as soon as it will be released.

Hint: The release package now also contains a "tiny" version of this plug-in. That version has about 1/3 the size of the "normal" (full) version, but lacks support for hash computation. The "tiny" version is provided as Unicode build only!


General Usage

In order to use the StdUtils plug-in in your script, simply include StdUtils.nsh and then use the pre-defined ${StdUtils.FunctionName} macros like this:

!include 'StdUtils.nsh'

Section
	${StdUtils.Rand} $1
	DetailPrint "Random number obtained via StdUtils::Rand is: $1"
SectionEnd

Note: We highly recommend to not call the plug-in functions directly. Instead, use the pre-defined macros, which ensures that the plug-in functions are used in the "proper" way.

For more details, please have a look at the example scripts located in the StdUtils\Examples\StdUtils directory!


Function Reference

In this chapter the individual functions provided by the StdUtils plug-in are described in detail.


Time Functions

${StdUtils.Time} user_var(output)

Returns the number of seconds that have elapsed since 00:00, Jan 1, 1970 (UTC), also known as "Unix time", just like the time() function:

!include 'StdUtils.nsh'

RequestExecutionLevel user
ShowInstDetails show

Section
	${StdUtils.Time} $1
	DetailPrint "Time: $1"
	Sleep 500
	${StdUtils.Time} $1
	DetailPrint "Time: $1"
	Sleep 500
	${StdUtils.Time} $1
	DetailPrint "Time: $1"
SectionEnd


${StdUtils.GetMinutes} user_var(output)
${StdUtils.GetHours} user_var(output)
${StdUtils.GetDays} user_var(output)

Retrieves the current system date and time, using the GetSystemTimeAsFileTime() function. Returns the number of minutes, hours or days since 00:00, January 1, 1601 (UTC).

!include 'StdUtils.nsh'

RequestExecutionLevel user
ShowInstDetails show

Section
	${StdUtils.GetMinutes} $1
	DetailPrint "UTC time in minutes: $1"
	${StdUtils.GetHours} $1
	DetailPrint "UTC time in hours: $1"
	${StdUtils.GetDays} $1
	DetailPrint "UTC time in days: $1"
SectionEnd

Pseudorandom Number Generator (PRNG)

${StdUtils.Rand} user_var(output)
${StdUtils.RandMax} user_var(output) max
${StdUtils.RandMinMax} user_var(output) min max

Returns a pseudo-random integral number, similar to the rand() function. Optionally, the minimum and maximum value can be specified via the min and max parameters; the max parameter must not exceed INT_MAX; the min parameter must not deceed INT_MIN; and max must be greater than or equal to min. The random numbers returned are guaranteed to be in the range from min to max, with both endpoints of the interval included. If the minimum is not specified, it defaults to 0; and if the maximum is not specified, it defaults to INT_MAX. Note that this function will use the RtlGenRandom() API, whenever possible; otherwise it falls back to a method based on rand(). In the latter case, srand() will be initialized with a suitable seed automatically. If the function was called with invalid parameter, it returns "einval" and sets the error flag.

Section
	${StdUtils.Rand} $1
	DetailPrint "Random: $1"
	${StdUtils.Rand} $1
	DetailPrint "Random: $1"
	${StdUtils.Rand} $1
	DetailPrint "Random: $1"
	${StdUtils.Rand} $1
	DetailPrint "Random: $1"
	${StdUtils.Rand} $1
	DetailPrint "Random: $1"
	${StdUtils.Rand} $1
	DetailPrint "Random: $1"
SectionEnd

Section
	${StdUtils.RandMax} $1 42
	DetailPrint "Random Max: $1"
	${StdUtils.RandMax} $1 42
	DetailPrint "Random Max: $1"
	${StdUtils.RandMax} $1 42
	DetailPrint "Random Max: $1"
	${StdUtils.RandMax} $1 42
	DetailPrint "Random Max: $1"
	${StdUtils.RandMax} $1 42
	DetailPrint "Random Max: $1"
	${StdUtils.RandMax} $1 42
	DetailPrint "Random Max: $1"
SectionEnd

Section
	${StdUtils.RandMinMax} $1 -4 -2
	DetailPrint "Random Min/Max: $1"
	${StdUtils.RandMinMax} $1 -4 -2
	DetailPrint "Random Min/Max: $1"
	${StdUtils.RandMinMax} $1 -4 -2
	DetailPrint "Random Min/Max: $1"
	${StdUtils.RandMinMax} $1 -4 -2
	DetailPrint "Random Min/Max: $1"
	${StdUtils.RandMinMax} $1 -4 -2
	DetailPrint "Random Min/Max: $1"
	${StdUtils.RandMinMax} $1 20 21
	DetailPrint "Random Min/Max: $1"
SectionEnd


${StdUtils.RandList} count max

Pushes a list of pseudo-random numbers onto the stack. The string "EOL" is pushed beforehand and thus will indicate the end of the list when popping the numbers off the stack. The quantity of the random numbers in the list can be controlled via the count parameter. Each number is guaranteed to be in the range from 0 to max, with both endpoints of the interval included. Also, each number appears at most once in the list. If the function was called with invalid parameters, it returns "einval" and sets the error flag.

Section
	${StdUtils.RandList} 50 100
	Pop $1
	StrCmp $1 EOL +3
	DetailPrint "RandList: $1"
	Goto -3
SectionEnd


${StdUtils.RandBytes} user_var(output) count

Generates a sequence of pseudo-random bytes. The length of the sequence, in bytes, can be controlled by the count parameter. The generated bytes are encoded and returned as a Base64 string – the length of the returned string is about (count/3)×4 characters. If the specified count is invalid, then "einval" is returned; if the length of the Base64-encoded string would exceed to maximum string length supported by NSIS, then "too_long" is returned; and if other errors occur, then "error" is returned. Also, if anything goes wrong, the error flag is set.

Section
	${StdUtils.RandBytes} $1 100
	DetailPrint "100 random bytes: $1"
	${StdUtils.RandBytes} $1 100
	DetailPrint "100 random bytes: $1"
	${StdUtils.RandBytes} $1 100
	DetailPrint "100 random bytes: $1"
SectionEnd

String Functions

${StdUtils.FormatStr} user_var(output) format_str val1
${StdUtils.FormatStr2} user_var(output) format_str val1 val2
${StdUtils.FormatStr3} user_var(output) format_str val1 val2 val3

Returns a formatted string, similar to the sprintf() function. Only the %d placeholder is currently supported. There are versions for one, two and three placeholders:

Section
	${StdUtils.FormatStr} $1 "Hello World is %05d woha!" 89
	DetailPrint "FormatStr: $1"
	${StdUtils.FormatStr2} $1 "Hello World is %05d and %05d woha!" 89 384
	DetailPrint "FormatStr: $1"
	${StdUtils.FormatStr3} $1 "Hello World is %05d and %05d or even %05d woha!" 89 384 2384
	DetailPrint "FormatStr: $1"
	${StdUtils.FormatStr} $1 "Hello World is %09000d." 89
	DetailPrint "FormatStr: $1"
SectionEnd


${StdUtils.ScanStr} user_var(output) format_str input default
${StdUtils.ScanStr2} user_var(output1) user_var(output2) format_str input default1 default2
${StdUtils.ScanStr3} user_var(output1) user_var(output2) user_var(output3) format_str input default1 default2 default3

Parses input from a string according to a format specification similar to the sscanf() function. Only the %d placeholder is currently supported. There are versions for one, two and three placeholders:

Section
	${StdUtils.ScanStr} $0 "Der Test sagt %d ist toll!" "Der Test sagt 571 ist toll!" 42
	DetailPrint "ScanStr: $0"
	${StdUtils.ScanStr} $0 "Der Hund sagt %d ist toll!" "Der Test sagt 571 ist toll!" 42
	DetailPrint "ScanStr: $0"
SectionEnd

Section
	${StdUtils.ScanStr2} $0 $1 "Der Test sagt %d sowie %d ist toll!" "Der Test sagt 571 sowie 831 ist toll!" 42 43
	DetailPrint "ScanStr2: $0, $1"
	${StdUtils.ScanStr2} $0 $1 "Der Test sagt %d sowie %d ist toll!" "Der Test sagt 571 horch 831 ist toll!" 42 43
	DetailPrint "ScanStr2: $0, $1"
	${StdUtils.ScanStr2} $0 $1 "Der Test sagt %d sowie %d ist toll!" "Der Hund sagt 571 horch 831 ist toll!" 42 43
	DetailPrint "ScanStr2: $0, $1"
SectionEnd

Section
	${StdUtils.ScanStr3} $0 $1 $2 "Der Test sagt %d sowie %d ist toll! Und %d." "Der Test sagt 571 sowie 831 ist toll! Und 325" 42 43 44
	DetailPrint "ScanStr3: $0, $1, $2"
	${StdUtils.ScanStr3} $0 $1 $2 "Der Test sagt %d sowie %d ist toll! Und %d." "Der Test sagt 571 sowie 831 ist toll! OMG 325" 42 43 44
	DetailPrint "ScanStr3: $0, $1, $2"
	${StdUtils.ScanStr3} $0 $1 $2 "Der Test sagt %d sowie %d ist toll! Und %d." "Der Test sagt 571 horch 831 ist toll! OMG 325" 42 43 44
	DetailPrint "ScanStr3: $0, $1, $2"
	${StdUtils.ScanStr3} $0 $1 $2 "Der Test sagt %d sowie %d ist toll! Und %d." "Der Hund sagt 571 horch 831 ist toll! OMG 325" 42 43 44
	DetailPrint "ScanStr3: $0, $1, $2"
SectionEnd


${StdUtils.TrimStr} user_var(input/output)
${StdUtils.TrimStrLeft} user_var(input/output)
${StdUtils.TrimStrRight} user_var(input/output)

Trims a string by removing all leading and/or trailing whitespace characters. A characters is considered to be a "whitespace" character by this function, if (and only if) it is accepted by either iscntrl() or isspace(). The function operates in-place.

Section
	StrCpy $1 "        Some Text        "
	DetailPrint "String: '$1'"
	StrCpy $0 $1
	${StdUtils.TrimStr} $0
	DetailPrint "TrimStr: '$0'"
	StrCpy $0 $1
	${StdUtils.TrimStrLeft} $0
	DetailPrint "TrimStrLeft: '$0'"
	StrCpy $0 $1
	${StdUtils.TrimStrRight} $0
	DetailPrint "TrimStrRight: '$0'"

	StrCpy $1 "Some Text"
	DetailPrint "String: '$1'"
	StrCpy $0 $1
	${StdUtils.TrimStr} $0
	DetailPrint "TrimStr: '$0'"
	StrCpy $0 $1
	${StdUtils.TrimStrLeft} $0
	DetailPrint "TrimStrLeft: '$0'"
	StrCpy $0 $1
	${StdUtils.TrimStrRight} $0
	DetailPrint "TrimStrRight: '$0'"

	StrCpy $1 ""
	DetailPrint "String: '$1'"
	StrCpy $0 $1
	${StdUtils.TrimStr} $0
	DetailPrint "TrimStr: '$0'"
	StrCpy $0 $1
	${StdUtils.TrimStrLeft} $0
	DetailPrint "TrimStrLeft: '$0'"
	StrCpy $0 $1
	${StdUtils.TrimStrRight} $0
	DetailPrint "TrimStrRight: '$0'"

	StrCpy $1 "   "
	DetailPrint "String: '$1'"
	StrCpy $0 $1
	${StdUtils.TrimStr} $0
	DetailPrint "TrimStr: '$0'"
	StrCpy $0 $1
	${StdUtils.TrimStrLeft} $0
	DetailPrint "TrimStrLeft: '$0'"
	StrCpy $0 $1
	${StdUtils.TrimStrRight} $0
	DetailPrint "TrimStrRight: '$0'"

	StrCpy $1 "$\tFoobar$\r$\n"
	DetailPrint "String: '$1'"
	StrCpy $0 $1
	${StdUtils.TrimStr} $0
	DetailPrint "TrimStr: '$0'"
	StrCpy $0 $1
	${StdUtils.TrimStrLeft} $0
	DetailPrint "TrimStrLeft: '$0'"
	StrCpy $0 $1
	${StdUtils.TrimStrRight} $0
	DetailPrint "TrimStrRight: '$0'"
SectionEnd


${StdUtils.RevStr} user_var(input/output)

Reverses the character order of a specified string in-place. For example, it converts "reverse me" to "em esrever", or vice versa.

Section
	StrCpy $0 "ABC"
	DetailPrint "String: $0"
	${StdUtils.RevStr} $0
	DetailPrint "RevStr: $0"

	StrCpy $0 "ABCD"
	DetailPrint "String: $0"
	${StdUtils.RevStr} $0
	DetailPrint "RevStr: $0"

	StrCpy $0 "Just a very long text with no specific meaning at all!"
	DetailPrint "String: $0"
	${StdUtils.RevStr} $0
	DetailPrint "RevStr: $0"
SectionEnd


${StdUtils.ValidFileName} user_var(output) input
${StdUtils.ValidPathSpec} user_var(output) input

The ${StdUtils.ValidFileName} function checks whether the given input is a valid file name, and the ${StdUtils.ValidPathSpec} function checks whether the given input is a valid fully-qualified path. Both functions return "ok", if the given string is valid, or "invalid" otherwise.

Note: File names must not contain any <>:"/\|?* characters or any characters accepted by iscntrl(). For paths the same limitations apply, except that a path may contain / and \ characters. Additionally, the first character in a path must be accepted by isalpha() and the second character in a path must be a : character. However, the : character must not appear at any other location in the path. Furthermore, the last character in a file name or path must not be a . or whitespace character. Last but not least, an empty string is never accepted as a valid file name or path.

Section
	${StdUtils.ValidFileName} $0 "My Document.txt"
	DetailPrint 'ValidFileName("My Document.txt") = $0'

	${StdUtils.ValidFileName} $0 "Is this a valid name?"
	DetailPrint 'ValidFileName("Is this a valid name?") = $0'

	${StdUtils.ValidPathSpec} $0 "C:\Folder\File.foo"
	DetailPrint 'ValidPathSpec("C:\Folder\File.foo") = $0'
SectionEnd


${StdUtils.ValidDomainName} user_var(output) input

The ${StdUtils.ValidDomainName} function checks whether the given input is a valid domain name. This can be a fully qualified domain name (FQDN) or just a single hostname. If the given string is a valid domain name, the function returns "ok"; otherwise it returns "invalid".

Note: A valid domain name consist of one or more labels. If multiple labels are present, each consecutive pair of labels is separated by a single dot (.) character; leading or trailing dots are forbidden. Also, each label consist of one or more characters. The only characters allowed in a label are the upper-case letters A to Z, the lower-case letters a to z, the digits 0 to 9 as well as thy hyphen character (-). Last but not least, a label must not start or end with a hyphen character. There generally is no distinction between upper-case and lower-case letters.

Section
	${StdUtils.ValidDomainName} $0 "localhost"
	DetailPrint 'ValidDomainName: "localhost" --> $0'

	${StdUtils.ValidDomainName} $0 "de.wikipedia.org"
	DetailPrint 'ValidDomainName: "de.wikipedia.org" --> $0'

	${StdUtils.ValidDomainName} $0 "Ö La Palöma"
	DetailPrint 'ValidDomainName: "Ö La Palöma" --> $0'

	${StdUtils.ValidDomainName} $0 "-foo-"
	DetailPrint 'ValidDomainName: "-foo-" --> $0'

	${StdUtils.ValidDomainName} $0 ".bar."
	DetailPrint 'ValidDomainName: ".bar." --> $0'
SectionEnd


${StdUtils.StrToUtf8} user_var(output) text
${StdUtils.StringFromUtf8} user_var(output) trnc data

The ${StdUtils.StrToUtf8} function converts the given string text from either UTF-16 (Unicode version) or the current ANSI codepage (ANSI version) to the UTF-8 format. The resulting UTF-8 byte sequence, including the terminating NULL character, is returned as a Base64-encoded string. If the length of the Base64-encoded string exceeds the maximum NSIS string length, then "too_long" is returned; and if other errors have occurred, then "error" is returned. Furthermore, if anything went wrong, the the error flag is set.

The ${StdUtils.StrFromUtf8} function converts the given UTF-8 byte sequence data to a normal string in either UTF-16 format (Unicode version) or the current ANSI codepage (ANSI version). The given input is expected to be valid UTF-8 data, encoded as a Base64 string. Also, the given input sequence is supposed to end with a NULL terminator. The trnc parameter controls the behavior of the function, in case that the length of the decoded string exceeds the maximum NSIS string length: If the parameter is set to 1, then the string is truncated; if the parameter is set to 0, then the function fails. If the length of the decoded string exceeds the maximum NSIS string length, then "too_long" is returned; and if other errors have occurred, then "error" is returned. Furthermore, if anything went wrong, the the error flag is set.

Section
	ClearErrors

	${StdUtils.StrToUtf8} $1 "The five boxing wizards jump quickly."
	DetailPrint 'UTF-8: "$1"'
	IfErrors 0 +3
	DetailPrint "Whoops, failed unexpectedly!"
	Abort
	
	${StdUtils.StrFromUtf8} $2 0 "$1"
	DetailPrint 'Plain: "$2"'
	IfErrors 0 +3
	DetailPrint "Whoops, failed unexpectedly!"
	Abort
SectionEnd

Shell File Operation

${StdUtils.SHFileMove} user_var(output) from to hwnd
${StdUtils.SHFileCopy} user_var(output) from to hwnd

Copies or moves a file system object (e.g. a file or a complete folder) from path from to path to, by using the SHFileOperation() function. The function requires a window handle hwnd and usually the NSIS variable $HWNDPARENT is used for this purpose.

Section
	InitPluginsDir
	SetOutPath "$PLUGINSDIR\TestDirA"
	File "${NSISDIR}\Contrib\Graphics\Checks\*.*"
	SetOutPath "$PLUGINSDIR\TestDirA\SubDir"
	File "${NSISDIR}\Contrib\Graphics\Header\*.*"
	CreateDirectory "$PLUGINSDIR\SubDirX"
	CreateDirectory "$PLUGINSDIR\SubDirY"

	${StdUtils.SHFileCopy} $0 "$PLUGINSDIR\TestDirA" "$PLUGINSDIR\SubDirX\TestDirB" $HWNDPARENT
	DetailPrint "SHFileCopy: $0"
	${StdUtils.SHFileMove} $0 "$PLUGINSDIR\TestDirA" "$PLUGINSDIR\SubDirY\TestDirC" $HWNDPARENT
	DetailPrint "SHFileMove: $0"
	ExecShell "explore" "$PLUGINSDIR"
SectionEnd

Section
	MessageBox MB_ICONINFORMATION "The next three operations are going to fail!$\nBut only one will be verbose..."

	${StdUtils.SHFileCopy} $0 "$PLUGINSDIR\TestDirXYZ" "$PLUGINSDIR\SubDirX\TestDirZ" $HWNDPARENT
	DetailPrint "SHFileCopy: $0"

	${StdUtils.SetVerbose} 1
	${StdUtils.SHFileCopy} $0 "$PLUGINSDIR\TestDirXYZ" "$PLUGINSDIR\SubDirX\TestDirZ" $HWNDPARENT
	DetailPrint "SHFileCopy: $0"

	${StdUtils.SetVerbose} 0
	${StdUtils.SHFileCopy} $0 "$PLUGINSDIR\TestDirXYZ" "$PLUGINSDIR\SubDirX\TestDirZ" $HWNDPARENT
	DetailPrint "SHFileCopy: $0"
SectionEnd

AppendToFile

${StdUtils.AppendToFile} user_var(output) from dest offset maxlen

Appends the contents of the existing source file specified by from to the output file specified by dest. If the output file does not exist yet, it will be created; otherwise the data is appended to the back-end of the existing file. Furthermore, offset specifies the number of bytes to be skipped in the source file, before the copying begins. If the offset is equal to or greater than the size of the source file, then no data is copied, which is not considered an error. Specify an offset of 0 in order to start copying right at the beginning of the source file. Finally, maxlen specifies the maximum number of bytes to be copied. Copying will stop when either the end of the source file is reached or when the specified maximum number of bytes have been copied. Set maxlen to 0, if you want to copy the source file all the way to the end. If the function succeeds, it will return the number of bytes that have actually been copied. Note, however, that if more than MAX_INT (2,147,483,647) bytes have been copied, the return value will still be at most MAX_INT. If anything went wrong, e.g. a file could not be opened or a read/write operation failed, "error" is returned.

Note: This function is implemented via native Win32 file I/O functions. It also uses a sufficiently large buffer (currently 8 KB) to speed up the copying process. This should be a lot faster than copying the data "byte by byte", using the built-in FileReadByte and FileWriteByte functions.

Section
	${StdUtils.AppendToFile} $0 "$EXEDIR\SourceFile1.bin" "$OUTDIR\OutputFile.bin" 0 0
	DetailPrint "AppendToFile: $0"

	${StdUtils.AppendToFile} $0 "$EXEDIR\SourceFile2.bin" "$OUTDIR\OutputFile.bin" 0 0
	DetailPrint "AppendToFile: $0"
SectionEnd

Create Process Functions

${StdUtils.ExecShellAsUser} user_var(output) file verb args

The ${StdUtils.ExecShellAsUser} function allows for launching a child process with normal user privileges (user level), directly from an elevated installer instance (admin level). This is in contrast to the built-in Exec, ExecWait and ExecShell instructions, which all cause the child process to be elevated too. Consequently, the ${StdUtils.ExecShellAsUser} function provides a simple and more lightweight alternative to the UAC plug-in. The function expects three arguments: The path to the file to be executed, the verb that shall be used to execute the file (e.g. "open") and the argument string args to be passed to the new process. The last two arguments are optional and can be specified as empty strings (""). If the function succeeded, then it returns either "ok" or "fallback". Otherwise it returns either "einval", "timeout", "not_found" or "error".

Please note that "einval" indicates that the function was called with invalid parameters, "not_found" indicates that the specified file doesn't exist, and "timeout" indicates that the function encountered a deadlock. Furthermore, note that "ok" indicates that the process was created using the IShellDispatch2 COM interface, which is the default behaviour on modern systems (allows the new process to not be elevated), while "fallback" indicates that the normal ShellExecute() method was used, which is the expected behaviour on legacy systems without UAC support.

!include 'StdUtils.nsh'

; make sure the installer will get elevated rights on UAC-enabled system (Vista+)
RequestExecutionLevel admin
ShowInstDetails show

Section
	DetailPrint 'ExecShell: "$SYSDIR\mspaint.exe"'
	; this instance of MS Paint will be *elevated*, just like the installer!
	ExecShell "open" "$SYSDIR\mspaint.exe"
	MessageBox MB_TOPMOST "Close Paint and click 'OK' to continue..."
SectionEnd

Section
	DetailPrint 'ExecShellAsUser: "$SYSDIR\mspaint.exe"'
	Sleep 1000
	; now launch a *non-elevated* instance of MS Paint by using ExecShellAsUser
	${StdUtils.ExecShellAsUser} $0 "$SYSDIR\mspaint.exe" "open" ""
	; expected result is "ok" on UAC-enabled systems or "fallback" otherwise
	DetailPrint "Result: $0"
SectionEnd


${StdUtils.ExecShellWaitEx} user_var(output_1) user_var(output_2) file verb args
${StdUtils.WaitForProcEx} user_var(output) handle

The ${StdUtils.ExecShellWaitEx} function works like the built-in ExecShell command, except that you can wait for the process to terminate. The function expects three arguments: The path to the file to be executed, the verb that shall be used to execute the file (e.g. "open") and the arguments to be passed to the new process. The last two arguments are optional and can be specified as empty strings (""). Furthermore, the function returns two values: The first value is either "ok", "no_wait" or "error", while the second value provides additional info. "ok" indicates that the process was created successfully and can be waited for, "no_wait" indicates that we cannot wait for the process (because ShellExecuteEx did not create a new process, but passed the file/URL to a running instance) and "error" indicates that something went wrong.

If the first return value is "ok", the second return value contains the handle of the new process. If the first return value is "error", the second return value contains the Win32 error code. And if the first return value is "no_wait", the second return value is zero. Only if "ok" and a process handle were returned, you can call ${StdUtils.WaitForProcEx} in order to wait until the process has terminated. This means that you must always carefully check the first return value of ${StdUtils.ExecShellWaitEx} before you pass the second return value to ${StdUtils.WaitForProcEx}. The behavior of ${StdUtils.WaitForProcEx} is undefined if you pass something that isn't a valid process handle! If successful, ${StdUtils.WaitForProcEx} returns the exit code of the process after it has terminated. The function returns "error" if something went wrong.

!include 'StdUtils.nsh'

RequestExecutionLevel user
ShowInstDetails show

Section
	DetailPrint 'ExecShellWait: "$SYSDIR\mspaint.exe"'
	Sleep 1000
	${StdUtils.ExecShellWaitEx} $0 $1 "$SYSDIR\mspaint.exe" "open" "" ;try to launch the process

	DetailPrint "Result: $0 -> $1" ;returns "ok", "no_wait" or "error".
	StrCmp $0 "error" ExecFailed ;check if process failed to create
	StrCmp $0 "no_wait" WaitNotPossible ;check if process can be waited for - always check this!
	StrCmp $0 "ok" WaitForProc ;make sure process was created successfully
	Abort

	WaitForProc:
	DetailPrint "Waiting for process. ZZZzzzZZZzzz..."
	${StdUtils.WaitForProcEx} $2 $1
	DetailPrint "Process just terminated (exit code: $2)"
	Goto WaitDone

	ExecFailed:
	DetailPrint "Failed to create process (error code: $1)"
	Goto WaitDone

	WaitNotPossible:
	DetailPrint "Can not wait for process."
	Goto WaitDone

	WaitDone:
SectionEnd

Command-line Parameter Functions

${StdUtils.TestParameter} user_var(output) name
${StdUtils.GetParameter} user_var(output) name default

With the ${StdUtils.TestParameter} function you can check for the presence of the command-line parameter specified by name. If that parameter is present on the command-line, the function returns true, otherwise it returns false. Additionally, the ${StdUtils.GetParameter} function can be used to get the value of the command-line parameter specified by name. If that parameter is present on the command-line, then the function returns the corresponding value. This might be an empty string! If the parameter is not present, then the default value is returned.

Hint: If the same parameter appears on the command-line multiple times, only the first occurrence will be returned. If the parameter value is too long to fit into an NSIS string, it will be truncated as needed. In any case, the parameter value will automatically be trimmed by this function.

Parameters are passed to the installer using the following syntax:

If the value contains spaces, it needs to be wrapped in double quote (") characters:

Note: The parameter name may contain any graphical characters, as defined by isgraph(), except for the equality character (=). Also, the parameter name must not start with a minus (-), slash (/) or backslash (\) character. The prefix, i.e. / or --, is not part of the parameter name!

!include 'StdUtils.nsh'

RequestExecutionLevel user
ShowInstDetails show

Section
	${StdUtils.TestParameter} $R0 "Foobar"
	StrCmp "$R0" "true" 0 +3
	DetailPrint 'Command-line parameter /Foobar is specified!'
	Goto +2
	DetailPrint 'Command-line parameter /Foobar is *not* specified!'
SectionEnd

Section
	${StdUtils.GetParameter} $R0 "Foobar" "<MyDefault>"
	DetailPrint 'Value of command-line parameter /Foobar is: "$R0"'
SectionEnd


${StdUtils.ParameterCnt} user_var(output)
${StdUtils.ParameterStr} user_var(output) index

The ${StdUtils.ParameterCnt} function returns then number of command-line tokens. This is equivalent to the argc parameter passed to the main() function. Note that this value may be zero, in which case no command-line tokens are available. If something went wrong, "error" is returned. Accordingly, the ${StdUtils.ParameterStr} function returns the n-th command-line token. This is equivalent to the n-th element of the argv array passed to the main() function. Note that the token may be an empty string. Also note that this function uses zero-based indexing. Thus, an index of 0 returns the first token, an index of 1 returns the second token, and so on. The index must be in the [0,N) range (i.e. N not included), where N is the value returned by ${StdUtils.ParameterCnt}. If something went wrong, e.g. index is out of range, the function returns "error".

Hint: In contrast to the main() function, where the first token (index = 0) always contains the executable name, the ${StdUtils.ParameterCnt} and ${StdUtils.ParameterStr} functions will omit the executable name. Simply use the built-in $EXEFILE or $EXEPATH constants instead!

!include 'StdUtils.nsh'

RequestExecutionLevel user
ShowInstDetails show

Section
	StrCpy $R0 0                                    #Init counter to zero
	${StdUtils.ParameterCnt} $R1                    #Get number of command-line tokens
	IntCmp $R1 0 0 0 LoopNext                       #Any tokens available?
	DetailPrint 'No command-line tokens!'           #Print some info
	Goto LoopExit                                   #Exit
LoopNext:
	${StdUtils.ParameterStr} $R2 $R0                #Read next command-line token
	DetailPrint 'Command-line token #$R0 is "$R2"'  #Print command-line token
	IntOp $R0 $R0 + 1                               #counter += 1
	IntCmp $R0 $R1 0 LoopNext                       #Loop while more tokens available
LoopExit:
SectionEnd


${StdUtils.GetAllParameters} user_var(output) truncate

Furthermore you can use ${StdUtils.GetAllParameters} to get the complete command-line string, but without the executable name. This is useful, for example, to forward all command-line parameters to an embedded installer. The truncate parameters controls the behavior of this function, if the command-line is too long to fit into an NSIS string. With truncate set to 1, the command-line will be truncated to a length of NSIS_MAX_STRLEN characters. With truncate set to 0, the function returns "too_long", if the command-line doesn't fit into an NSIS string.

!include 'StdUtils.nsh'

RequestExecutionLevel user
ShowInstDetails show

Section
	${StdUtils.GetAllParameters} $R0 0
	DetailPrint "Complete command-line: '$R0'"

	${StdUtils.GetAllParameters} $R0 1
	DetailPrint "Truncated command-line: '$R0'"
SectionEnd

InvokeShellVerb

${StdUtils.InvokeShellVerb} user_var(output) path file verb_id

The ${StdUtils.InvokeShellVerb} function can be used to invoke a so-called "Shell Verb" on an arbitrary item. The most common use for this is (un)pinning an item to/from the Taskbar or the Startmenu, on Windows 7 and later. The function expects three arguments: The directory where the item (e.g. executable file or shortcut) is located, the name of the item, and the id of the shell verb to be invoked. We need the id of the verb, because the verb's name (string), which is used to select the desired verb from the list of available verbs, is language-specific; it depends on the Windows system language. However, we certainly do not want to make our installer specific to a certain system language. Resource id's, on the other hand, are language-independent. By using resource id's, we can load the actual verb name (string) at runtime. Note that while this function works on Windows 7 (and later) only, it still is perfectly safe to call on older versions of Windows. If the function succeeded, then it returns "ok"; if the function is called with invalid parameters, then it returns "einval"; if the requested verb could not be found, if the request verb is unavailable for the specified item, or if the specified item does not exist, then "not_found" will be returned; if this function is used on Windows versions prior to Windows 7 (e.g. Vista or XP), then it will return "unsupported"; and if the function failed for another reason, then it will return "error".

Supported shell verbs IDs are:

Hint: If you are getting the "not_found" error for a verb that is supposed to exists, then it's probably because the desired action isn't currently available for the item (e.g. it could be that you are trying to pin an item that already is pinned).

!include 'StdUtils.nsh'

RequestExecutionLevel user ;no elevation needed for this test
ShowInstDetails show

Section
	IfFileExists "$SYSDIR\mspaint.exe" +3
	MessageBox MB_ICONSTOP 'File does not exist:$\n"$SYSDIR\mspaint.exe"$\n$\nExample cannot run!'
	Quit
SectionEnd

Section
	DetailPrint "Going to pin MSPaint..."
	${StdUtils.InvokeShellVerb} $0 "$SYSDIR" "mspaint.exe" ${StdUtils.Const.ShellVerb.PinToTaskbar}
	DetailPrint "Result: $0"

	StrCmp "$0" "ok" 0 +3
	MessageBox MB_TOPMOST "Paint should have been pinned to Taskbar now!"
	Goto +2
	MessageBox MB_TOPMOST "Failed to pin, see log for details!"
SectionEnd

Section
	DetailPrint "Going to un-pin MSPaint..."
	${StdUtils.InvokeShellVerb} $0 "$SYSDIR" "mspaint.exe" ${StdUtils.Const.ShellVerb.UnpinFromTaskbar}
	DetailPrint "Result: $0"

	StrCmp "$0" "ok" 0 +3
	MessageBox MB_TOPMOST "Paint should have been un-pinned from Taskbar now!"
	Goto +2
	MessageBox MB_TOPMOST "Failed to un-pin, see log for details!"
SectionEnd

OS Version Functions

${StdUtils.GetRealOSVersion} user_var(out_major) user_var(out_minor) user_var(out_spack)

The ${StdUtils.GetRealOSVersion} function returns the real Windows NT version installed on the computer. Note that starting with Windows 8.1 (Windows NT 6.3), Microsoft has broken the GetVersion() and GetVersionEx() functions! These function will now return the Windows version that the calling application has been compiled for (as indicated by the program's Compat Manifest), not the actual Windows version that we are running on! So these functions are effectively a NOP now – you don't need to call the Win32 API to determine which Windows version your own program has been compiled for, as you already know it. This has the consequence that Windows 8.1 and Windows 10 will now identify themselves as Windows 8.0, unless the calling application has been specifically compiled for Windows 8.1 or 10. Bummer!

Workarounds to "reveal" the actual Windows version exist. For example, one may try guestimating the real Windows version from certain Registry entries or from the file versions of certain system libraries. But, while these methods may seem to work in most cases, they still are dubious. It is also possible to obtain the real Windows version via WMI (Windows Management Instrumentation), but this is complex and requires a lot of COM hackery. At the same time, the provided ${StdUtils.GetRealOSVersion} function manages to reveal the actual Windows version strictly by using "official" Win32 API calls. Also, this function works regardless of the application Manifest, i.e. it will continue to work correctly in future Windows versions! Finally, this function still returns the correct Windows version, when the installer runs in "compatibility mode".

The function will return the major and minor Windows NT version (e.g. "6.3" on Windows 8.1, or "10.0" on Windows 10) plus the corresponding Service Pack version spack. It returns "error", if something went wrong.

Note: This function uses an iterative approach: It first calls GetVersionEx() to get the "fake" Windows version. Then it tries to refine the Windows version, step by step, using the VerifyVersionInfo() function - until the "real" version has been revealed. Furthermore, because the VerifyVersionInfo() function has been broken too on Windows 10 (facepalm!), we now try to call the "native" functions RtlGetVersion() and RtlVerifyVersion() directly from NTDLL.DLL, instead of using the "crippled" counterparts from KERNEL32.DLL.

!include 'StdUtils.nsh'

RequestExecutionLevel user
ShowInstDetails show

Section
	${StdUtils.GetRealOSVersion} $1 $2 $3
	DetailPrint "Real Windows NT Version: $1,$2 (Service Pack: $3)"
SectionEnd


${StdUtils.GetRealOSBuildNo} user_var(out)

The ${StdUtils.GetRealOSBuildNo} function returns the real Windows NT build number installed on the computer. The function will return the Windows NT build number (e.g. "7600" on Windows 7 RTM). It returns "error", if something went wrong.

Note: This function uses the same algorithm as ${StdUtils.GetRealOSVersion} to determine the real Windows build number, so it will give the expected result on Windows 8.1 and later.

!include 'StdUtils.nsh'

RequestExecutionLevel user
ShowInstDetails show

Section
	${StdUtils.GetRealOSBuildNo} $1
	DetailPrint "Real Windows NT Build No.: $1"
SectionEnd


${StdUtils.GetRealOSName} user_var(out)

${StdUtils.GetRealOSName} is a convenience function that returns the installed Windows version as a friendly name string. Currently the return value can be "Windows NT 4.0", "Windows 2000", "Windows XP", "Windows XP (x64)", "Windows Vista", "Windows 7", "Windows 8", "Windows 8.1", "Windows 10" or any corresponding server edition. If an unknown Windows version is encountered, e.g. some future version that is not yet supported, the function will return "unknown". And it will return "error", if something else went wrong.

Note: This function uses the same algorithm as ${StdUtils.GetRealOSVersion} and ${StdUtils.GetOSEdition}to determine the real Windows version. The real version will be converted to a friendly name, so it will give the expected result on Windows 8.1 and later.

!include 'StdUtils.nsh'

RequestExecutionLevel user
ShowInstDetails show

Section
	${StdUtils.GetRealOSName} $1
	DetailPrint "Real Windows NT Friendly Name: $1"
SectionEnd


${StdUtils.VerifyOSVersion} user_var(out) expected_major expected_minor expected_spack

${StdUtils.VerifyOSVersion} is a convenience function to compare the installed Windows version against some expected one. The expected Windows NT version (e.g. "6.2" for Windows 8.0) is specified by the expected_major, expected_minor and expected_spack parameters. The function returns "ok" when the installed Windows version matches the expected one exactly; it returns "older" when the installed version is older than expected; it returns "newer" when the installed version is newer than expected; and it returns "error" if something went wrong.

Note: This function uses the same algorithm as ${StdUtils.GetRealOSVersion} to determine the real Windows version that will be compared to the expected version, so it will give the expected result on Windows 8.1 and later.

!include 'StdUtils.nsh'

RequestExecutionLevel user
ShowInstDetails show

Section
	${StdUtils.VerifyOSVersion} $1 5 1 0
	DetailPrint "Check for Windows XP (RTM): $1"

	${StdUtils.VerifyOSVersion} $1 5 1 3
	DetailPrint "Check for Windows XP (SP3): $1"

	${StdUtils.VerifyOSVersion} $1 6 1 0
	DetailPrint "Check for Windows 7 (RTM): $1"

	${StdUtils.VerifyOSVersion} $1 6 1 1
	DetailPrint "Check for Windows 7 (SP1): $1"

	${StdUtils.VerifyOSVersion} $1 6 2 0
	DetailPrint "Check for Windows 8.0: $1"

	${StdUtils.VerifyOSVersion} $1 6 3 0
	DetailPrint "Check for Windows 8.1: $1"
SectionEnd


${StdUtils.VerifyOSBuildNo} user_var(out) expected_build

${StdUtils.VerifyOSBuildNo} is a convenience function to compare the installed Windows version against some expected version. The expected Windows NT build number is specified by expected_build (e.g. "7600" on Windows 7 RTM). The function will return "ok" when the installed Windows build matches the expected one exactly; it returns "older" when the installed build is older than the expected one; it returns "newer" when the installed version is newer than the expected one; and it returns "error" if something went wrong.

Note: This function uses the same algorithm as ${StdUtils.GetRealOSVersion} to determine the real Windows build number that will be compared to the expected build number, so it will give the expected result on Windows 8.1 and later.

!include 'StdUtils.nsh'

RequestExecutionLevel user
ShowInstDetails show

Section
	${StdUtils.VerifyOSBuildNo} $1 2600
	DetailPrint "Check for Build #2600, Windows XP: $1"

	${StdUtils.VerifyOSBuildNo} $1 7600
	DetailPrint "Check for Build #7600, Windows 7 (RTM): $1"

	${StdUtils.VerifyOSBuildNo} $1 7601
	DetailPrint "Check for Build #7601, Windows 7 (SP1): $1"

	${StdUtils.VerifyOSBuildNo} $1 9600
	DetailPrint "Check for Build #9600, Windows 8.1: $1"
SectionEnd


${StdUtils.GetOSEdition} user_var(out)

${StdUtils.GetOSEdition} returns the Windows edition, i.e. either "workstation" or "server". It returns "error" if something went wrong.

!include 'StdUtils.nsh'

RequestExecutionLevel user
ShowInstDetails show

Section
	${StdUtils.GetOSEdition} $1
	DetailPrint "Windows Edition is: $1"
SectionEnd


${StdUtils.GetOSReleaseId} user_var(out)

The ${StdUtils.GetOSReleaseId} function returns the release id of Windows 10 (e.g. "1803"). Starting with Windows 10, the release id has superseded the minor version – which now is always zero – as well as the service pack number – which now is always zero. Older operating systems versions (before Windows 10) do not support the release id. The function returns "unavail" when an older operating systems version (before Windows 10) is detected. It returns "error", if anything else went wrong.

!include 'StdUtils.nsh'

RequestExecutionLevel user
ShowInstDetails show

Section
	${StdUtils.GetOSReleaseId} $1
	DetailPrint "Windows 10 release Id: v$1"
SectionEnd


${StdUtils.GetOSReleaseName} user_var(out)

${StdUtils.GetOSReleaseName} is a convenience function that returns the release id of Windows 10 as a friendly name (e.g. "Redstone 4"). This function should not be used to detect a specific Windows 10 release (use ${StdUtils.GetOSReleaseId} for that purpose). The function returns "unknown", if an unknown (e.g. future or pre-release) Windows 10 release is encountered, it returns "unavail" when an older operating systems version (before Windows 10) is detected, and it returns "error", if anything else went wrong.

!include 'StdUtils.nsh'

RequestExecutionLevel user
ShowInstDetails show

Section
	${StdUtils.GetOSReleaseName} $1
	DetailPrint "Windows 10 release name: $\"$1$\""
SectionEnd

List of Windows NT versions:

Friendly NameServer EditionNT VersionBuild No.
Windows NT 4.0-4.01381
Windows 2000-5.02195
Windows XP-5.12600
Windows XP (x64)Windows Server 20035.23790
Windows VistaWindows Server 20086.06000 - 6002
Windows 7Windows Server 2008 R26.17600 - 7601
Windows 8Windows Server 20126.29200
Windows 8.1Windows Server 2012 R26.39600
Windows 10Windows Server 201610.010240-17134

List of Windows 10 releases:

Release IdFriendly NameBuild No.
1507RTM (Threshold 1)10240
1511November Update (Threshold 2) 10586
1607Anniversary Update (Redstone 1) 14393
1703Creators Update (Redstone 2) 15063
1709Fall Creators Update (Redstone 3) 16299
1803April 2018 Update (Redstone 4)17134


Cryptographic Hash Functions

${StdUtils.HashText} user_var(out) type text

The ${StdUtils.HashText} function computes the cryptographic hash of the message given by text, using the hash function specified by type. Currently CRC32, MD5, SHA-1, the SHA-2 family as well as the SHA-3 family are supported (using RHash implementation). See below for details! If the function succeeds, it will return the hash value, as a hexadecimal string. The length of the result depends on the chosen hash function. If an invalid hash function was specified, the function returns "invalid". And, if anything else went wrong, it returns "error".

Note: For improved consistency between the ANSI and Unicode installers, the Unicode version of this function will convert the given message to UTF-8 before hash computation!

!include 'StdUtils.nsh'

RequestExecutionLevel user
ShowInstDetails show

Section
	${StdUtils.HashText} $0 "SHA3-224" "The quick brown fox jumps over the lazy dog"
	DetailPrint 'SHA3-224("The quick brown fox jumps over the lazy dog") = "$0"'

	${StdUtils.HashText} $0 "SHA3-256" "The quick brown fox jumps over the lazy dog"
	DetailPrint 'SHA3-256("The quick brown fox jumps over the lazy dog") = "$0"'

	${StdUtils.HashText} $0 "SHA3-384" "The quick brown fox jumps over the lazy dog"
	DetailPrint 'SHA3-384("The quick brown fox jumps over the lazy dog") = "$0"'

	${StdUtils.HashText} $0 "SHA3-512" "The quick brown fox jumps over the lazy dog"
	DetailPrint 'SHA3-512("The quick brown fox jumps over the lazy dog") = "$0"'
SectionEnd


${StdUtils.HashFile} user_var(out) type path

The ${StdUtils.HashText} function computes the cryptographic hash of the contents of the file specified by path, using the hash function specified by type. Currently CRC32, MD5, SHA-1, the SHA-2 family as well as the SHA-3 family are supported (using RHash implementation). See below for details! If the function succeeds, it will return the hash value, as a hexadecimal string. The length of the result depends on the chosen hash function. If an invalid hash function was specified, the function returns "invalid". And, if anything else went wrong, it returns "error".

!include 'StdUtils.nsh'

RequestExecutionLevel user
ShowInstDetails show

Section
	${StdUtils.HashFile} $0 "SHA3-224" "$WINDIR\Explorer.exe"
	DetailPrint 'SHA3-224($WINDIR\Explorer.exe) = "$0"'

	${StdUtils.HashFile} $0 "SHA3-256" "$WINDIR\Explorer.exe"
	DetailPrint 'SHA3-256($WINDIR\Explorer.exe) = "$0"'

	${StdUtils.HashFile} $0 "SHA3-384" "$WINDIR\Explorer.exe"
	DetailPrint 'SHA3-384($WINDIR\Explorer.exe) = "$0"'

	${StdUtils.HashFile} $0 "SHA3-512" "$WINDIR\Explorer.exe"
	DetailPrint 'SHA3-512($WINDIR\Explorer.exe) = "$0"'
SectionEnd

List of supported hash functions:

Hash FunctionHash Length in Bit (in Byte)Algorithm Identifier
CRC*32 (4)CRC-32
MD5*128 (16)MD5-128
SHA-1*160 (20)SHA1-160
SHA-2224 (28)SHA2-224
256 (32)SHA2-256
384 (48)SHA2-384
512 (64)SHA2-512
SHA-3224 (28)SHA3-224
256 (32)SHA3-256
384 (48)SHA3-384
512 (64)SHA3-512
BLAKE2224 (28)BLAKE2-224
256 (32)BLAKE2-256
384 (48)BLAKE2-384
512 (64)BLAKE2-512

* Please do not use these hash functions for security critical code nowadays, as they they have known collisions!


Path Utility Functions

${StdUtils.NormalizePath} user_var(out) path

The ${StdUtils.NormalizePath} function normalizes the given path. The function will remove any navigation elements (such as . or ..) in order to produce a direct, well-formed path. Also, if a relative path is given the function, that path will be expanded to an absolute path, based on the current working directory. Furthermore, any forward slash (/) in the path will be replaced by a backslash (\). Last but not least, multiple backslash characters in a row will be replaced by a single backslash character and any trailing backslash characters are removed.

This function does not care whether the given path points to a file or to a directory. The given path does not need to point to an existing file-system object. The function does not check whether the target file-system object exists. If the function fails, an empty string ("") will be returned.

!include 'StdUtils.nsh'

RequestExecutionLevel user
ShowInstDetails show

Section
	StrCpy $0 "C:\Foo\\Bar/Test\.\..\Test\."
	${StdUtils.NormalizePath} $1 "$0"
	DetailPrint 'NormalizePath: "$0" -> "$1"'
SectionEnd


${StdUtils.GetParentPath} user_var(out) path

The ${StdUtils.GetParentPath} function returns the parent path of the given path. If the given path points to a file, the function will return the path of directory where the file is located. If the given path points to a directory, the function will return the path of the directory that is located one level above the given directory. In any case, the given path will first be normalized, according to the ${StdUtils.NormalizePath} function, and then the last (rightmost) path-component will be chopped off.

The given path does not need to point to an existing file-system object. The function does not check whether the target file-system object exists. If the function fails, an empty string ("") will be returned. If the given path already points to the drive's root directory, the function will fail.

!include 'StdUtils.nsh'

RequestExecutionLevel user
ShowInstDetails show

Section
	StrCpy $0 "C:\Foo\Bar\Test\Honk\Sponk"
DoLoop:
	${StdUtils.GetParentPath} $1 "$0"
	DetailPrint 'GetParentPath: "$0" -> "$1"'
	StrCpy $0 "$1"
	StrCmp "$0" "" 0 DoLoop
SectionEnd


${StdUtils.SplitPath} user_var(out_drive) user_var(out_dir) user_var(out_fname) user_var(out_ext) path

The ${StdUtils.SplitPath} function splits the given path into the separate components. These components are drive letter, directory path, file name, and file extension. Each component is returned separately.

The given path does not need to point to an existing file-system object. The function does not check whether the target file-system object exists. If a certain component is missing in the given path, an empty string ("") will be returned for that component.

!include 'StdUtils.nsh'

RequestExecutionLevel user
ShowInstDetails show

Section
	StrCpy $0 "C:\Windows\System32\kernel32.dll"
	${StdUtils.SplitPath} $1 $2 $3 $4 "$0"
	DetailPrint 'SplitPath [1]: "$0" -> "$1"' # "C:"
	DetailPrint 'SplitPath [2]: "$0" -> "$2"' # "\Windows\System32\"
	DetailPrint 'SplitPath [3]: "$0" -> "$3"' # "kernel32"
	DetailPrint 'SplitPath [4]: "$0" -> "$4"' # ".dll"
SectionEnd


${StdUtils.GetDrivePart} user_var(out) path
${StdUtils.GetDirectoryPart} user_var(out) path
${StdUtils.GetFileNamePart} user_var(out) path
${StdUtils.GetExtensionPart} user_var(out) path

The ${StdUtils.GetDrivePart}, ${StdUtils.GetDirectoryPart}, ${StdUtils.GetFileNamePart} and ${StdUtils.GetExtensionPart} functions return the drive letter, directory path, file name, and file extension component of the given path, respectively.

The given path does not need to point to an existing file-system object. The function does not check whether the target file-system object exists. If a certain component is missing in the given path, an empty string ("") will be returned for that component.

!include 'StdUtils.nsh'

RequestExecutionLevel user
ShowInstDetails show

Section
	${StdUtils.GetDrivePart} $1 "C:\Windows\System32\kernel32.dll"
	DetailPrint 'GetDrivePart: "$1"'     # "C:"
	
	${StdUtils.GetDirectoryPart} $1 "C:\Windows\System32\kernel32.dll"
	DetailPrint 'GetDirectoryPart: "$1"' # "\Windows\System32\"
	
	${StdUtils.GetFileNamePart} $1 "C:\Windows\System32\kernel32.dll"
	DetailPrint 'GetFileNamePart: "$1"'  # "kernel32"
	
	${StdUtils.GetExtensionPart} $1 "C:\Windows\System32\kernel32.dll"
	DetailPrint 'GetExtensionPart: "$1"' # ".dll"
SectionEnd

Cryptographic Functions

${StdUtils.ProtectStr} user_var(out) dpsc salt text
${StdUtils.UnprotectStr} user_var(out) trnc salt data

The ${StdUtils.ProtectStr} function protects (encrypts) the given text string using the DPAPI (Windows Data Protection). The dpsc parameter can be set to "CU" (current user) or "LM" (local machine), which will encrypt the string in such a way that it can only be decrypted again by the current user or on the local machine, respectively. The optional salt parameter can be used to pass a user-defined salt value; pass an empty string ("") in order to disable the user-defined salt. If a user-defined salt value is passed, it will be used as additional entropy to encrypt the input string. In that case, the exactly same salt value must be passed again in order to decrypt the string! On success, the encrypted data is returned as a Base64-encoded string. If invalid parameters have been passed, then "einval" is returned; if the string could not be encrypted (DPAPI error), then "encr_failed" is returned; if the length of the encoded data exceeds the maximum NSIS string length, then "too_long" is returned; and if other errors have occurred, then "error" is returned. Furthermore, if anything went wrong, the the error flag is set.

The ${StdUtils.UnprotectStr} function unprotects (decrypts) the given encrypted data using the DPAPI. The encrypted data is expected to be passed as a Base64-encoded string. The trnc parameter controls the behavior of the function, in case that the length of the decrypted string exceeds the maximum NSIS string length: If the parameter is set to 1, then the string is truncated; if the parameter is set to 0, then the function fails. The salt parameter can be used to pass a user-defined salt value. If the string has been encrypted using a user-defined salt, then the exactly same salt value must be passed here again; if no user-defined salt has been used to encrypt the string, then an empty string ("") must be passed. On success, the function returns the plaintext string. If invalid parameters have been passed, then "einval" is returned; if the string could not be encrypted (DPAPI error), then "decr_failed" is returned; if the length of the encoded data exceeds the maximum NSIS string length, then "too_long" is returned; and if other errors have occurred, then "error" is returned. Furthermore, if anything went wrong, the the error flag is set.

Note: ProtectStr converts the given plaintext string from UTF-16 (Unicode version) or from the current ANSI codepage (ANSI version) to a NULL-terminated UTF-8 byte sequence. The resulting UTF-8 bytes are then encrypted using the DPAPI. Accordingly, UnprotectStr interprets the decrypted bytes returned by the DPAPI as an UTF-8 sequence. The UTF-8 sequence is expected to be NULL-terminated! The function then converts the UTF-8 sequence to either UTF-16 (Unicode version) or to the current ANSI codepage (ANSI version).

!include 'StdUtils.nsh'

RequestExecutionLevel user
ShowInstDetails show

Section
	ClearErrors
	
	${StdUtils.ProtectStr} $1 "CU" "a7gzLbdwdbk4" "Five quacking Zephyrs jolt my wax bed."
	DetailPrint 'ProtectedStr: "$1"'
	
	IfErrors 0 +3
	DetailPrint "Whoops, encryption has failed!"
	Abort
	
	${StdUtils.UnprotectStr} $2 0 "a7gzLbdwdbk4" "$1"
	DetailPrint 'UnprotectedStr: "$2"'
	
	IfErrors 0 +3
	DetailPrint "Whoops, decryption has failed!"
	Abort
SectionEnd

Window Timer Functions

${StdUtils.TimerCreate} user_var(out) callback interval
${StdUtils.TimerDestroy} user_var(out) timer_id

The ${StdUtils.TimerCreate} function creates a new window timer, using the SetTimer API, which is going to periodically execute the NSIS function specified by callback. The interval (delay), in milliseconds, is specified by interval. If the timer was created successfully, the function returns a unique timer id. And, if anything went wrong, it returns "error". The ${StdUtils.TimerDestroy} function stops and destroys the timer specified by timer_id. Every timer that has been created successfully must be destroyed before the installer unloads the plug-in DLL!

Important: The SetTimer function works by appending WM_TIMER messages to the message queue of the thread which has created the timer. These messages will be dispatched to the window procedure, which eventually calls the callback function (TIMERPROC). Consequently, the thread, which creates the timer, must be running a message loop – otherwise the timer is never going to fire! For NSIS this means that the timer must be created (and destroyed) from the "main" GUI thread. You probably want to do this in the .onGUIInit and .onGUIEnd functions.

!include 'StdUtils.nsh'

RequestExecutionLevel user
ShowInstDetails show

Var TimerId
Var MyCount

Function MyCallback
	IntOp $MyCount $MyCount + 1
	DetailPrint "Timer event has been triggered! (#$MyCount)"
FunctionEnd

Function .onGUIInit
	${StdUtils.TimerCreate} $TimerId MyCallback 1500
	StrCmp $TimerId "error" 0 +2
	MessageBox MB_ICONSTOP "Failed to create timer!"
FunctionEnd

Function .onGUIEnd
	StrCmp $TimerId "error" 0 +2
	Return
	${StdUtils.TimerDestroy} $0 $TimerId
	StrCmp $0 "ok" +2
	MessageBox MB_ICONSTOP "Failed to destroy timer!"
FunctionEnd

Section
	DetailPrint "Hello, world!"
SectionEnd

Debugging Functions

${StdUtils.GetLibVersion} user_var(out_ver) user_var(out_tst)

The ${StdUtils.GetLibVersion} function returns the version of the StdUtils library that is being used. The version string (in the "w.x.y.z" format) is returned in out_ver; the build time-stamp is returned in out_tst.


${StdUtils.SetVerbose} on

The ${StdUtils.SetVerbose} function enables or disables verbose error messages. Set on to '1' to enable verbose outputs or set it to '0' to disable verbose outputs. Verbose outputs are disabled by default. Do not enabled them for release versions of your installer!


License

The StdUtils plug-in for NSIS was created by LoRd_MuldeR <mulder2@gmx.de>. It is distributed under the GNU LGPL v2.1.

StdUtils plug-in for NSIS
Copyright (C) 2004-2018 LoRd_MuldeR <mulder2@gmx.de>

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.

The author of the StdUtils plug-in Library for NSIS adds the following clarification to the GNU Lesser General Public License version 2.1: Installer programs (executables) created with NSIS (Nullsoft Scriptable Install System) that make use of the StdUtils plug-in Library (strictly through the NSIS plug-in interface) and that contain/distribute verbatim copies of the StdUtils plug-in Library are considered a "work that uses the Library"; they do not represent a derivative of the Library.


Acknowledgment

This plug-in has been inspired, partly, by the InvokeShellVerb plug-in, created by Robert Strong.

This plug-in has been inspired, partly, by the ShellExecAsUser plug-in, created by installer32.

Special thanks to Afrow UK for providing his excellent plug-ins (his code helped me to understand how to write NSIS plug-ins).


The following third-party code has been incorporated into StdUtils plug-in:


Download and Sources

The source codes for the StdUtils plug-in are available from the code repository at:


You can download pre-compiled binaries (i.e. ready-to-use DLL files) of the plug-in from here:


Help & Support

For help and support, please use the "NSIS Discussion" sub-forum of the Winamp forums:
http://forums.winamp.com/forumdisplay.php?f=65

If you have any feature requests or bug reports, please submit them directly to our GitHub bug-tracker:
https://github.com/lordmulder/stdutils/issues

Also you may wish to check the official NSIS Wiki for the latest information and updates:
http://nsis.sourceforge.net/StdUtils_plug-in


Version History



http://muldersoft.com/ | http://sourceforge.net/projects/muldersoft/ | http://nsis.sourceforge.net/Category:Plugins Earth Heals Herself