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 whitespaces 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.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.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.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.TimerCreate      #Create a new event-timer that will be triggered periodically
!define StdUtils.TimerDestroy     #Destroy a running timer created with TimerCreate()
!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-defind 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, but without the need to call srand(). Optionally the minimum and/or maximum value can be specified, so a random number in the min to max range will be returned. If no minimum is specified, the minimum defaults to zero. And if no maximum is specified, the maximum defaults to INT_MAX. Note that this function will use RtlGenRandom(), where possible; otherwise it falls back to a method based on rand(). In the latter case, srand() will be initialized with a suitable seed automatically.

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 count of the random numbers and the max value can be specified; the minimum value is zero.

Section
	${StdUtils.RandList} 50 100
	Pop $1
	StrCmp $1 EOL +3
	DetailPrint "RandList: $1"
	Goto -3
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

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 successfull, ${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:

* Using this syntax is not recommended, but it is supported anyway, for consistency with the way that Visual C++ handles command-line arguments!

!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 arbitary item. The most common use for this is pinning (or unpinning) an item to (from) the Taskbar or Startmenu on Windows 7. Despite the fact the Microsoft claimes that there is no API for this, the API does exist and is commonly used (e.g. Firefox' insatller makes use of it too). The function expects three arguments: The directory where the item (e.g. executable file) is located, the name of the item (e.g. executable file) and the resource id of the verbt o be invoked. We need the resource id of the verb, because the verb itself is language-specific, but we certainly do no want to adjust the installer for each system langauge. Resource id's are langauge-independant and you can use the pre-defined constants ${StdUtils.Const.ISV_PinToTaskbar}, ${StdUtils.Const.ISV_UnpinFromTaskbar}, ${StdUtils.Const.ISV_PinToStartmenu} or ${StdUtils.Const.ISV_UnpinFromStartmenu} for convenience. 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 was not found 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 (e.g. file not found or invalid verb_id), then it will return "error".

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.ISV_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.ISV_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 Manifest), not the actual Windows version 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, you already know it. This has the consequence that Windows 8.1 will now identify itself as Windows 8.0! Workarounds exist, such as adding a certain GUID to the program's Manifest, which cannot work with future Windows versions, or trying to read the Windows version from the Registry, which is unreliable. At the same time, the ${StdUtils.GetRealOSVersion} function reveals the actual Windows version on Windows 8.1 (and later), regardless of the application Manifest. Furthermore, 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) plus the Service Pack 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 increase that value, step by step, using the VerifyVersionInfo() function - until the "real" version has been revealed. On Windows 10, the function additionally evaluates the file version of Kernel32.dll to uncover the "real" Windows version. This is required, because, starting with Windows 10, Microsoft has broken the VerifyVersionInfo() function too. Congratulations to Microsoft for reaching a new level of idiocy!

!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" or "Windows 10". 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 went wrong.

Note: This function uses the same algorithm as ${StdUtils.GetRealOSVersion} to determine the real Windows version. Subsequently, 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 retruns "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 retrun "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 retruns "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 retruns "error" if something went wrong.

!include 'StdUtils.nsh'

RequestExecutionLevel user
ShowInstDetails show

Section
	${StdUtils.GetOSEdition} $1
	DetailPrint "Windows Edition is: $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


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!


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 distribiuted under the GNU LGPL v2.1.

StdUtils plug-in for NSIS
Copyright (C) 2004-2015 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