SHMessageBoxCheck
Description
SHMessageBoxCheck basically works like MessageBox but includes a checkbox that gives the user the option not to show the message box again.
For example this can be used to give the user a simple Yes / No / Always Yes / Always No choice, e.g. when asking whether to remove files that weren't part of the original installation or have been modified.
SHMessageBoxCheck is based on the Windows API function of the same name called via the NSIS System Plug-in.
Usage
!include SHMessageBoxCheck.nsh ${SHMessageBoxCheckInit} unique_string ${SHMessageBoxCheck} caption text type ${SHMessageBoxCheckCleanup}
Initialization
To initialize call ${SHMessageBoxCheckInit} unique_string
to create a unique name by which to identify your message box. Microsoft recommends to use a GUID as unique_string
but any reasonably distinct string will do.
Showing a Message Box
To show a message box call ${SHMessageBoxCheck} caption text type
.
caption
and text
are simple strings specifying the caption of the window and the content text.
type
is used to define which buttons are shown and whether to include an image in the message box. For possible choices refer to the the script's code below. To combine two options use the "or" operator, e.g. ${MB_YESNO}|${MB_ICONINFORMATION}
- Return value
The macro returns the user's choice (i.e. the button he/she clicked in the dialog). If the user chooses not to see the dialog again the macro will always return the last choice without displaying a message box.
The return value is stored as the first value on the stack, e.g. a Pop $0
will store the result in the $0
user variable.
Return values are integers. For clarity there are defines (e.g. ${IDOK}
for the OK button) which can be used in comparisons. Please refer to the script's code below for the full list of possible return values.
Finalization
After you're done call ${SHMessageBoxCheckCleanup}
which will reset the state of the message box (i.e. the users choice wether or not to see the message box again will be reset).
Example
!include macros\SHMessageBoxCheck.nsh !include FileFunc.nsh !insertmacro Locate Section Uninstall StrCpy $INSTDIR "C:\Your\Installation\Directory" # initialize SHMessageBoxCheck ${SHMessageBoxCheckInit} "unique_application_string" # locate leftover files ${Locate} "$INSTDIR" "/L=F /M=*.*" "un.DeleteFile" # finalize SHMessageBoxCheck ${SHMessageBoxCheckCleanup} SectionEnd Function un.DeleteFile # show the message box ${SHMessageBoxCheck} "Remove additional files" \ "File `$R9` was not part of initial installation. Delete anyway?" \ ${MB_YESNO}|${MB_ICONQUESTION} # get the result Pop $0 # delete if user clicked "Yes" StrCmp $0 ${IDYES} 0 +2 Delete $R9 Push 0 # required by ${Locate} FunctionEnd
The Script
# SHMessageBoxCheck # Works like MessageBox but includes a checkbox that gives the user the option not to show the message box again. # In that case the return value (first value on the stack) is always set to the last user choice # # See # http://nsis.sourceforge.net/SHMessageBoxCheck (documentation) # https://msdn.microsoft.com/de-de/library/windows/desktop/bb773836.aspx (implementation details) # # types to indicate the buttons displayed in the message box !define MB_OK 0x00000000 !define MB_OKCANCEL 0x00000001 !define MB_ABORTRETRYIGNORE 0x00000002 # not officially supported, use at your own risk! !define MB_YESNOCANCEL 0x00000003 # not officially supported, use at your own risk! !define MB_YESNO 0x00000004 !define MB_RETRYCANCEL 0x00000005 # not officially supported, use at your own risk! !define MB_CANCELTRYCONTINUE 0x00000006 # not officially supported, use at your own risk! !define MB_HELP 0x00004000 # not officially supported, use at your own risk! # types to display an icon in the message box !define MB_ICONHAND 0x00000010 !define MB_ICONQUESTION 0x00000020 # MS bug: Same as MB_ICONEXCLAMATION !define MB_ICONEXCLAMATION 0x00000030 !define MB_ICONINFORMATION 0x00000040 # return values !define IDOK 1 !define IDCANCEL 2 !define IDABORT 3 !define IDRETRY 4 !define IDIGNORE 5 !define IDYES 6 !define IDNO 7 !define IDCONTINUE 11 !define IDTRYAGAIN 10 # the user's previous choice (i.e. the button clicked in the message box) Var _lastReturnValue # The value that the call to SHMessageBoxCheck should return when the user chose not to display the message box again !define _DEFAULT 9999 # Windows XP does not expose the function name, so we have to specify the function by ordinal value !ifdef NSIS_UNICODE !define _SHMessageBoxCheck_Ordinal 191 !else !define _SHMessageBoxCheck_Ordinal 185 !endif !macro SHMessageBoxCheckInit _UNIQUE_STRING # SHMessageBoxCheck stores the user's choice not to display the message box again in the registry, see # HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\DontShowMeThisDialogAgain !ifdef _PSZ_REG_VAL !error "Only call SHMessageBoxCheckInit once and make sure to call SHMessageBoxCheckCleanup before using it again" !else # the unique string used to identify this message (and name of the registry value used to store the checkbox status) !define _PSZ_REG_VAL ${_UNIQUE_STRING} !endif # make sure the registry value is not yet set (for whatever reason) ${SHMessageBoxCheckCleanup} !macroend !define SHMessageBoxCheckInit "!insertmacro SHMessageBoxCheckInit" !macro SHMessageBoxCheckCleanup # delete the registry key that is used to store the checkbox status so we can start fresh next time DeleteRegValue HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\DontShowMeThisDialogAgain" "${_PSZ_REG_VAL}" !macroend !define SHMessageBoxCheckCleanup "!insertmacro SHMessageBoxCheckCleanup" !macro SHMessageBoxCheck _CAPTION _TEXT _TYPE # this would be the simple way (by name) # System::Call "shlwapi::SHMessageBoxCheck(p $HWNDPARENT, t '${_TEXT}', t '${_CAPTION}', i ${_TYPE}, i ${_DEFAULT}, t '${_PSZ_REG_VAL}') i .r0" # for backwards-compatibility we get the process address by specifying the function's ordinal value System::Call "kernel32::GetModuleHandle(t 'shlwapi.dll') p .s" System::Call "kernel32::GetProcAddress(p s, i ${_SHMessageBoxCheck_Ordinal}) p .r0" System::Call "::$0(p $HWNDPARENT, t '${_TEXT}', t '${_CAPTION}', i ${_TYPE}, i ${_DEFAULT}, t '${_PSZ_REG_VAL}') i .r0" # save the user's choice (unless the default value was returned - then don't update and return the saved choice) StrCmp $0 ${_DEFAULT} +2 0 StrCpy $_lastReturnValue $0 # push the return value to the stack Push $_lastReturnValue !macroend !define SHMessageBoxCheck "!insertmacro SHMessageBoxCheck"