StdUtils plug-in: Difference between revisions
Line 355: | Line 355: | ||
== ExecShellAsUser == | == ExecShellAsUser == | ||
The ''${StdUtils.ExecShellAsUser}'' function allows to launch a process with normal user privileges (user level), directly from an ''elevated'' installer instance (admin level). This way it provides a simple/lightweight alternative to the [[UAC plug-in]]. If the function succeeded, it returns either "ok" or "fallback". The former means that the process was crated via COM interface (which is required to allow the new process to '''not''' be elevated), while the latter means that the normal ''ShellExecute'' was used instead. Note that "fallback" is the expected result on systems that do not support UAC (like Windows XP and older). If the function failed, it returns "error". | The ''${StdUtils.ExecShellAsUser}'' function allows you to launch a process with normal user privileges (user level), directly from an ''elevated'' installer instance (admin level). This way it provides a simple/lightweight alternative to the [[UAC plug-in]]. If the function succeeded, it returns either "ok" or "fallback". The former means that the process was crated via COM interface (which is required to allow the new process to '''not''' be elevated), while the latter means that the normal ''ShellExecute'' was used instead. Note that "fallback" is the expected result on systems that do not support UAC (like Windows XP and older). If the function failed, it returns "error". | ||
<highlight-nsis>!include 'StdUtils.nsh' | <highlight-nsis>!include 'StdUtils.nsh' |
Revision as of 00:25, 9 October 2011
Author: Instructor (talk, contrib) |
This plug-in provides access to a number of "standard" functions from C Standard Library, which programmers are used to from their C/C++ compilers (and other languages), but which are not available in NSIS by default. In order to keep the plug-in size as small as possible (~9 KB) and for maximum compatibility, the Visual C++ Run-Time v6.0 (MSVCRT.DLL), which is included with all versions of Windows (since Windows 2000), is used - instead of linking the Visual C++ Run-Time library into the plug-in DLL.
Additionally this plug-in provides wrappers for the SHFileOperation function. Moreover it provides a method for launching programs in a non-elevated way (user context) from an elevated installer (admin mode) on UAC-enabled systems - see this thread for details! Last but not least, a version of ExecShell with "wait for process termination" feature, based on ShellExecuteEx, is provided.
ANSI and Unicode builds available!
Available Functions
!define StdUtils.Time '!insertmacro _StdUtils_Time' #time() !define StdUtils.Rand '!insertmacro _StdUtils_Rand' #rand() !define StdUtils.RandMax '!insertmacro _StdUtils_RandMax' #rand() with maximum !define StdUtils.RandMinMax '!insertmacro _StdUtils_RandMinMax' #rand() with minimum/maximum !define StdUtils.RandList '!insertmacro _StdUtils_RandList' #rand() with list support !define StdUtils.FormatStr '!insertmacro _StdUtils_FormatStr' #sprintf() with one format tag (only %d supported!) !define StdUtils.FormatStr2 '!insertmacro _StdUtils_FormatStr2' #sprintf() with two format tags (only %d supported!) !define StdUtils.FormatStr3 '!insertmacro _StdUtils_FormatStr3' #sprintf() with three format tags (only %d supported!) !define StdUtils.ScanStr '!insertmacro _StdUtils_ScanStr' #sscanf() with one format tag (only %d supported!) !define StdUtils.ScanStr2 '!insertmacro _StdUtils_ScanStr2' #sscanf() with two format tags (only %d supported!) !define StdUtils.ScanStr3 '!insertmacro _StdUtils_ScanStr3' #sscanf() with three format tags (only %d supported!) !define StdUtils.TrimStr '!insertmacro _StdUtils_TrimStr' #Remove whitspaces from string (left and right) !define StdUtils.TrimStrLeft '!insertmacro _StdUtils_TrimStrLeft' #Remove whitspaces from string (left side only) !define StdUtils.TrimStrRight '!insertmacro _StdUtils_TrimStrRight' #Remove whitspaces from string (right side only) !define StdUtils.SHFileMove '!insertmacro _StdUtils_SHFileMove' #SHFileOperation with FO_MOVE !define StdUtils.SHFileCopy '!insertmacro _StdUtils_SHFileCopy' #SHFileOperation with FO_COPY !define StdUtils.ExecShellAsUser '!insertmacro _StdUtils_ExecShlUser' #ShellExecute() with user context (for elevated installers) !define StdUtils.ExecShellWait '!insertmacro _StdUtils_ExecShlWait' #ShellExecuteEx() with process handle to wait for !define StdUtils.WaitForProc '!insertmacro _StdUtils_WaitForProc' #WaitForSingleObject() to wait for process termination !define StdUtils.GetParameter '!insertmacro _StdUtils_GetParameter' #Get the value of a specific commandline paramater !define StdUtils.Unload '!insertmacro _StdUtils_Unload' #Unload DLL for proper clean-up (don't forget!) !define StdUtils.SetVerbose '!insertmacro _StdUtils_SetVerbose' #Verbose mode (for debugging) !macro _StdUtils_Time out StdUtils::Time /NOUNLOAD pop ${out} !macroend !macro _StdUtils_Rand out StdUtils::Rand /NOUNLOAD pop ${out} !macroend !macro _StdUtils_RandMax out max push ${max} StdUtils::RandMax /NOUNLOAD pop ${out} !macroend !macro _StdUtils_RandMinMax out min max push ${min} push ${max} StdUtils::RandMinMax /NOUNLOAD pop ${out} !macroend !macro _StdUtils_RandList count max push ${max} push ${count} StdUtils::RandList /NOUNLOAD !macroend !macro _StdUtils_FormatStr out format val push '${format}' push ${val} StdUtils::FormatStr /NOUNLOAD pop ${out} !macroend !macro _StdUtils_FormatStr2 out format val1 val2 push '${format}' push ${val1} push ${val2} StdUtils::FormatStr2 /NOUNLOAD pop ${out} !macroend !macro _StdUtils_FormatStr3 out format val1 val2 val3 push '${format}' push ${val1} push ${val2} push ${val3} StdUtils::FormatStr3 /NOUNLOAD pop ${out} !macroend !macro _StdUtils_ScanStr out format input default push '${format}' push '${input}' push ${default} StdUtils::ScanStr /NOUNLOAD pop ${out} !macroend !macro _StdUtils_ScanStr2 out1 out2 format input default1 default2 push '${format}' push '${input}' push ${default1} push ${default2} StdUtils::ScanStr2 /NOUNLOAD pop ${out1} pop ${out2} !macroend !macro _StdUtils_ScanStr3 out1 out2 out3 format input default1 default2 default3 push '${format}' push '${input}' push ${default1} push ${default2} push ${default3} StdUtils::ScanStr3 /NOUNLOAD pop ${out1} pop ${out2} pop ${out3} !macroend !macro _StdUtils_TrimStr var push ${var} StdUtils::TrimStr /NOUNLOAD pop ${var} !macroend !macro _StdUtils_TrimStrLeft var push ${var} StdUtils::TrimStrLeft /NOUNLOAD pop ${var} !macroend !macro _StdUtils_TrimStrRight var push ${var} StdUtils::TrimStrRight /NOUNLOAD pop ${var} !macroend !macro _StdUtils_SHFileMove out from to hwnd push '${from}' push '${to}' push ${hwnd} StdUtils::SHFileMove /NOUNLOAD pop ${out} !macroend !macro _StdUtils_SHFileCopy out from to hwnd push '${from}' push '${to}' push ${hwnd} StdUtils::SHFileCopy /NOUNLOAD pop ${out} !macroend !macro _StdUtils_ExecShlUser out file verb args push '${file}' push '${verb}' push '${args}' StdUtils::ExecShellAsUser /NOUNLOAD pop ${out} !macroend !macro _StdUtils_ExecShlWait out file verb args push '${file}' push '${verb}' push '${args}' StdUtils::ExecShellWait /NOUNLOAD pop ${out} !macroend !macro _StdUtils_WaitForProc handle push '${handle}' StdUtils::WaitForProc /NOUNLOAD !macroend !macro _StdUtils_GetParameter out name default push '${name}' push '${default}' StdUtils::GetParameter /NOUNLOAD pop ${out} !macroend !macro _StdUtils_Unload StdUtils::Unload !macroend !macro _StdUtils_SetVerbose on !if "${on}" != "0" StdUtils::EnableVerboseMode /NOUNLOAD !else StdUtils::DisableVerboseMode /NOUNLOAD !endif !macroend
Example
This example tests miscellaneous functions of the StdUtils plug-in:
!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 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 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 Section ${StdUtils.RandList} 50 100 Pop $1 StrCmp $1 EOL +3 DetailPrint "RandList: $1" Goto -3 SectionEnd 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 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 ${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 Section StrCpy $1 " Some Text " StrCpy $0 $1 DetailPrint "String: '$0'" ${StdUtils.TrimStr} $0 DetailPrint "TrimStr: '$0'" StrCpy $0 $1 DetailPrint "String: '$0'" ${StdUtils.TrimStrLeft} $0 DetailPrint "TrimStrLeft: '$0'" StrCpy $0 $1 DetailPrint "String: '$0'" ${StdUtils.TrimStrRight} $0 DetailPrint "TrimStrRight: '$0'" SectionEnd Section ${StdUtils.Unload} SectionEnd
ExecShellAsUser
The ${StdUtils.ExecShellAsUser} function allows you to launch a process with normal user privileges (user level), directly from an elevated installer instance (admin level). This way it provides a simple/lightweight alternative to the UAC plug-in. If the function succeeded, it returns either "ok" or "fallback". The former means that the process was crated via COM interface (which is required to allow the new process to not be elevated), while the latter means that the normal ShellExecute was used instead. Note that "fallback" is the expected result on systems that do not support UAC (like Windows XP and older). If the function failed, it returns "error".
!include 'StdUtils.nsh' RequestExecutionLevel admin ;make sure our installer will get elevated on Vista+ with UAC enabled ShowInstDetails show Section DetailPrint 'ExecShell: "$SYSDIR\mspaint.exe"' ExecShell "open" "$SYSDIR\mspaint.exe" ;this instance of MS Paint will be elevated too! MessageBox MB_TOPMOST "Close Paint and click 'OK' to continue..." SectionEnd Section DetailPrint 'ExecShellAsUser: "$SYSDIR\mspaint.exe"' Sleep 1000 ${StdUtils.ExecShellAsUser} $0 "$SYSDIR\mspaint.exe" "open" "" ;launch a *non-elevated* instance of MS Paint DetailPrint "Result: $0" ;expected result is "ok" on UAC-enabled systems or "fallback" otherwise. Failure indicated by "error" or "timeout". ${StdUtils.Unload} ;please do not forget to unload! SectionEnd
ExecShellWait
The ${StdUtils.ExecShellWait} function works like the built-in ExecShell command, except that you can wait for the process to terminate. If the function failed, it returns "error". If the function succeeded, it will either return a process handle or "no_wait". The latter means that we cannot wait for the process, because ShellExecuteEx did not create a new process (but pass the file to a running instance). Only if a process handle was returned, you can call ${StdUtils.WaitForProc} in order to wait until the process has terminated.
!include 'StdUtils.nsh' RequestExecutionLevel user ShowInstDetails show Section DetailPrint 'ExecShellWait: "$SYSDIR\mspaint.exe"' Sleep 1000 ${StdUtils.ExecShellWait} $0 "$SYSDIR\mspaint.exe" "open" "" ;try to launch the process DetailPrint "Result: $0" ;returns process handle. Might be "no_wait". Failure indicated by "error". StrCmp $0 "error" WaitFailed ;check if process failed to create. StrCmp $0 "no_wait" WaitNotPossible ;check if process can be waited for. Always check this! DetailPrint "Waiting for process. ZZZzzzZZZzzz..." ${StdUtils.WaitForProc} $0 DetailPrint "Process just terminated." Goto WaitDone WaitFailed: DetailPrint "Failed to create process !!!" Goto WaitDone WaitNotPossible: DetailPrint "Can not wait for process." Goto WaitDone WaitDone: ${StdUtils.Unload} ;please do not forget to unload! SectionEnd
GetParameter
With ${StdUtils.GetParameter} you can check for the presence of a specific command-line parameter.
If the parameter was specified with a (non-empty) value, then the parameter's value is return. If the parameter was specified without a value, then an empty string is return. If the parameter has not been specified, then the default value is returned.
Parameters can be passed to the installer like this:
- Installer.exe /Foobar
- Installer.exe /Foobar=SomeValue
- Installer.exe "/Foobar=Some Value With Whitespaces"
!include 'StdUtils.nsh' RequestExecutionLevel user ShowInstDetails show Section ${StdUtils.GetParameter} $R0 "Foobar" "<N/A>" StrCmp "$R0" "<N/A>" 0 +3 DetailPrint "Parameter /Foobar is *not* specified!" Goto Finished StrCmp "$R0" "" 0 +3 ;'Installer.exe [...] /Foobar' DetailPrint "Parameter /Foobar specified without a value." Goto Finished ;'Installer.exe /Foobar=Foo' or 'Installer.exe "/Foobar=Foo Bar"' ${StdUtils.TrimStr} $R0 DetailPrint "Value of parameter /Foobar is: '$R0'" Finished: ${StdUtils.Unload} ;please do not forget to unload! SectionEnd
Download
Download:
StdUtils.2011-10-09.zip (104 KB)
SVN Repository:
http://code.google.com/p/mulder/source/browse/trunk/Utils/nsis_stdutils/