nsis - remove pinned icon from taskbar on uninstall - nsis

I'm working on an app for a company and they requested that if the app is pinned to the taskbar, when uninstalling the app should be unpinned. If I just delete the icon from quicklaunch\user pinned\taskbar then it leaves a blank icon on the taskbar.
I need to somehow actually unpin it. The only thing I've come across is installing winshell plugin (http://nsis.sourceforge.net/WinShell_plug-in) and then calling IStartMenuPinnedList::RemoveFromList (https://msdn.microsoft.com/en-us/library/windows/desktop/bb774817(v=vs.85).aspx)
I'd rather not install a plugin if I don't need to. Does anyone have any suggestions?

NSIS does not have native support for this interface so you have to use a plug-in. If you want to avoid that 3rd-party plug-in (written by me) then you can use the System plug-in instead:
!include "LogicLib.nsh"
!include "Win\COM.nsh" ; NSIS v3+
!macro UnpinShortcut lnkpath
Push $0
Push $1
!insertmacro ComHlpr_CreateInProcInstance ${CLSID_StartMenuPin} ${IID_IStartMenuPinnedList} r0 ""
${If} $0 P<> 0
System::Call 'SHELL32::SHCreateItemFromParsingName(ws, p0, g "${IID_IShellItem}", *p0r1)' "${lnkpath}"
${If} $1 P<> 0
${IStartMenuPinnedList::RemoveFromList} $0 '(r1)'
${IUnknown::Release} $1 ""
${EndIf}
${IUnknown::Release} $0 ""
${EndIf}
Pop $1
Pop $0
!macroend
Section Uninstall
!insertmacro UnpinShortcut "$SMPrograms\MyApp.lnk"
Delete "$SMPrograms\MyApp.lnk"
SectionEnd

Related

How to show the popup message when user tries to install on Unsupported Operating System

When installing the software, I wanted to detect the operating system and if it is "Windows 10 Pro" or "Windows Server 2012" it should pop up a message box and the installation should stop.
I am using the below code snippet. But here even if the operating system is "Windows 10 Pro", message box is not popping up.
ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" "ProductName"
${If} $R0 == "Windows 10 Pro"
MessageBox MB_OK|MB_ICONQUESTION "This operating system is not supported." IDOK
Quit
${EndIf}
Is it the correct way or is there any way we can detect the operating system and show the message box?
I don't really understand why you need these restrictions but here you go:
!include WinVer.nsh
!define /IfNDef PRODUCT_PROFESSIONAL 0x00000030
!define /IfNDef PRODUCT_PROFESSIONAL_N 0x00000031
!define /IfNDef PRODUCT_PRO_WORKSTATION 0x000000A1
!define /IfNDef PRODUCT_PRO_WORKSTATION_N 0x000000A2
!define /IfNDef ERROR_INSTALL_REJECTED 1654
Function .onInit
System::Call 'KERNEL32::GetProductInfo(i6,i1,i0,i0,*i0r1)'
${WinVerGetBuild} $2
${If} ${IsServerOS} ; Windows Server?
${AndIf} $2 U>= 9200 ; Server 2012?
${AndIf} $2 U< 9600 ; and not Server 2012 R2?
Goto die_unsupported_os
${EndIf}
${If} $2 U>= 9800 ; Windows 10?
${AndIfNot} ${IsServerOS} ; Not Windows Server?
${If} $1 = ${PRODUCT_PROFESSIONAL}
${OrIf} $1 = ${PRODUCT_PROFESSIONAL_N}
${OrIf} $1 = ${PRODUCT_PRO_WORKSTATION}
${OrIf} $1 = ${PRODUCT_PRO_WORKSTATION_N}
die_unsupported_os:
MessageBox mb_IconStop|mb_OK "Not allowed to run on this version of Windows for some reason!" /SD IDOK
SetErrorLevel ${ERROR_INSTALL_REJECTED}
Quit
${EndIf}
${EndIf}
FunctionEnd
Note: Windows Insider builds are also identified as Pro so you will end up blocking those as well.

How to stop the uninstallation and pop up a message box when uninstalling in Safe mode using NSIS?

How to stop the uninstallation and pop up a message box (something like as shown below) when uninstalling the installed software using NSIS if the operating system is in Safe mode.
!include LogicLib.nsh
Function un.onInit
!define /IfNDef SM_CLEANBOOT 67
System::Call 'USER32::GetSystemMetrics(i${SM_CLEANBOOT})i.r0'
${If} $0 <> 0
MessageBox mb_IconStop "Safe mode blah blah"
Quit
${EndIf}
FunctionEnd

Check/Prevent Windows Shutdown (NSIS)

To summarize, I need to check and/or prevent a user if he/she decides to shutdown the computer while the installer is running. Now I've researched for a while and came up with the following:
${If} ${AtMostWinXP}
System::Call `kernel32::GetModuleHandle(i0)i.r3`
System::Call `user32::CreateWindowEx(i0,t"STATIC",t"MyApp",i0,i0,i0,i0,i0,i$HWNDPARENT,i0,ir3,i0)i.r1`
${ElseIf} ${AtLeastVista}
System::Call `user32::ShutdownBlockReasonCreate(ir1,w"MyApp is running and still needs to clean up before shutting down!")i.r0`
${EndIf}
However the above snippet isn't working. Am I missing something? I've tried using just:
System::Call `kernel32::GetModuleHandle(i0)i.r3`
System::Call `user32::CreateWindowEx(i0,t"STATIC",t"MyApp",i0,i0,i0,i0,i0,i$HWNDPARENT,i0,ir3,i0)i.r1`
System::Call `user32::ShutdownBlockReasonCreate(ir1,w"MyApp is running and still needs to clean up before shutting down!")i.r0`
As the first two calls are meant for Windows XP and earlier and the third call is meant for Windows Vista or later but is ignored by Windows XP and earlier I believe (I have no evidence to support this theory). This too isn't working.
Also, I can use user32::ShutdownBlockReasonCreate(ir1,w"$(PreventShutdown)")i.r0 instead of using the entire string in the above snippet for different language support, right?
Your code for Windows XP makes no sense, the window needs to handle WM_QUERYENDSESSION to block the shutdown. Luckily NSIS already handles WM_QUERYENDSESSION for you.
Use something like this for Vista and later:
LoadLanguageFile "${NSISDIR}\Contrib\Language Files\English.nlf"
LangString BlockReason ${LANG_ENGLISH} "Installer blah blah"
LoadLanguageFile "${NSISDIR}\Contrib\Language Files\Swedish.nlf"
LangString BlockReason ${LANG_SWEDISH} "Installer bork bork"
!include nsDialogs.nsh ; For WS_CHILD
!define /ifndef WS_POPUP 0x80000000
!include LogicLib.nsh
Function CreateShutdownBlockReason
StrCpy $1 $hwndParent
${If} $1 Z= 0 ; $hwndParent is 0, create a new window for silent installers
System::Call 'USER32::CreateWindowEx(i0, t "STATIC", t "$(^Name)", i ${WS_CHILD}|${WS_POPUP}, i0, i0, i0, i0, p r1, i0, i0, i0)p.r1'
${EndIf}
System::Call 'USER32::ShutdownBlockReasonCreate(p r1, w "$(BlockReason)")'
FunctionEnd
Function .onInit
IfSilent 0 +2
Call CreateShutdownBlockReason ; .onGuiInit is not executed in silent installers
FunctionEnd
Function .onGuiInit
Call CreateShutdownBlockReason
FunctionEnd
I'm not sure if a silent installer will be able to block the shutdown but this is the best you can do without a plug-in.

Load the content of the embedded file into RichEdit control on the custom license page

Requirements / use case:
I have a requirement to implement custom license page in NSIS. The page should look like this: .
On the page I have RichEdit control which has to display the content of a eula.rtf file. This file is available at the compile time and I cannot distribute it separately from the installer, so it has to be somehow embedded into it.
Currently I am using NSIS 2.46 and MUI2. Here is how I create RichEdit control:
nsDialogs::CreateControl /NOUNLOAD "RichEdit20A" ${WS_VISIBLE}|${WS_CHILD}|${WS_TABSTOP}|${WS_VSCROLL}|${ES_MULTILINE}|${ES_WANTRETURN} ${WS_EX_STATICEDGE} 1.32u 56.62u 295.54u 63.38u ""
Pop $hCtl_test_rtLicense
Problem description:
I know that the default MUI2 license page makes use of LicenseData and/or LicenseLangString. As far as I know, in this case the .rtf file is embedded into the installer. Unfortunately I cannot figure out how to load the content from the embedded .rtf file into my RichEdit control, even though I looked through the License.nsh coming with NUI2 and through the NSIS source code as well.
And unfortunately the plugins and scripts I found (LoadRtf plugin, NsRichEdit plugin, this script and one or two more) can only load .rtf file into the RichEdit control at runtime.
Question:
How to load the content from the embedded .rtf file into the RichEdit on the custom page?
If it is not possible, is there any other way to implement my requirement?
The only thing I could think of is wrapping my current installer into another thin NSIS installer which would silently deploy the .rtf file alongside with the current installer. This feels very messy, so I would rather not do that..
The only way to do this is at run-time. To use one of the solutions you linked to you would just extract the .rtf file and call the plugin:
InitPluginsDir ; Initialize $PluginsDir, it is deleted automatically when installer quits
File "/oname=$PluginsDir\lic.rtf" "MyLicense.rtf"
# Call plugin here passing in "$PluginsDir\lic.rtf" as the file to load
Or if you don't want to use 3rd-party plugins:
Page Custom MyPage
Page InstFiles
!include LogicLib.nsh
!include nsDialogs.nsh
!define SF_RTF 2
!define EM_STREAMIN 1097
Function LoadRichRtf
System::Store S
Pop $0 ; hwnd
Pop $1 ; path to rtf
FileOpen $1 $1 r
System::Get "(i, i .R0, i .R1, i .R2)iss"
Pop $2
System::Call "*(*i 0, i 0, k r2)i.r3"
System::Call "USER32::SendMessage(ir0, i${EM_STREAMIN}, i${SF_RTF}, ir3)i.s"
loop:
Pop $0
StrCmp $0 "callback1" 0 done
System::Call 'KERNEL32::ReadFile(ir1, iR0, iR1, iR2, i0)'
Push 0 # callback's return value
System::Call "$2"
Goto loop
done:
System::Free $2
System::Free $3
FileClose $1
System::Store L
FunctionEnd
Var hCtl_test_rtLicense
Function MyPage
nsDialogs::Create 1018
Pop $0
nsDialogs::CreateControl /NOUNLOAD "RichEdit20A" ${WS_VISIBLE}|${WS_CHILD}|${WS_TABSTOP}|${WS_VSCROLL}|${ES_MULTILINE}|${ES_WANTRETURN} ${WS_EX_STATICEDGE} 1.32u 56.62u 295.54u 63.38u ""
Pop $hCtl_test_rtLicense
File "/oname=$PluginsDir\lic.rtf" "c:\some\local\path\License_en_US.rtf"
Push "$PluginsDir\lic.rtf"
Push $hCtl_test_rtLicense
Call LoadRichRtf
nsDialogs::Show
FunctionEnd

Changing the selection in the components page of NSIS based on the OS on which we are installing

I am finding it difficult to change the selection in the components page of nsis.
The requirement is during installation i get a license agreement page ,if the user agrees then he/she will click on I AGREE ,after the user clicks on I AGREE ,i want to know on which OS the
setup is being installed that is it can be either on a Windows Embedded OS or WinXp/Win7.
So if it is Windows Embedded OS i want to change the installation package and if it is not Windows Embedded OS then the installation package will be different.
I am using MUI ver1 not MUI2 in my project.
Please let me know how this can be achieved.
To test for the OS where the setup is running, you can use macros defined Winver.nsh with those provided with LogicLib.nsh to make elegant tests like this
;Dont't forget to include
!include "LogicLib.nsh" # use of various logic statements
!include "WinVer.nsh" # LogicLib extension for OS tests
A platform test example:
${if} ${AtLeastWin95}
${AndIf} ${AtMostWinME}
;here we are on a pre-win2k
;do something
${elseIf} ${isWin2008}
${orIf} ${AtLeastWin2008R2}
;this is post-win7
;do other thing
${endif}
To change at runtime the components to install, you can use the macros from Sections.nsh:
;if you have
Section "Sample Database" SecApplicationDB
;...
SectionEnd
;you can select or un select by code:
!insertmacro SelectSection ${SecApplicationDB}
;or
!insertmacro UnselectSection ${SecApplicationDB}
WinVer.nsh does not support checking for Embedded NT but you can perform the check yourself:
!include Sections.nsh
!include MUI.nsh
!ifndef VER_SUITE_EMBEDDEDNT
!define VER_SUITE_EMBEDDEDNT 0x00000040
!endif
!insertmacro MUI_PAGE_LICENSE "${__FILE__}"
!insertmacro MUI_PAGE_COMPONENTS
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_LANGUAGE English
Section "Embedded" SID_EMBED
SectionIn RO
SectionEnd
Section "Normal" SID_NORMAL
SectionIn RO
SectionEnd
Function .onInit
System::Call '*(i156,&i152)i.r1'
System::Call 'KERNEL32::GetVersionExA(ir1)'
System::Call '*$1(&i152,&i2.r2)'
System::Free $1
IntOp $2 $2 & ${VER_SUITE_EMBEDDEDNT}
${If} $2 <> 0
!insertmacro SelectSection ${SID_EMBED}
!insertmacro UnselectSection ${SID_NORMAL}
${Else}
!insertmacro UnselectSection ${SID_EMBED}
!insertmacro SelectSection ${SID_NORMAL}
${EndIf}
FunctionEnd

Resources