NSIS - retrieving the start menu folder not working as expected - nsis

In my NSIS script, the MUI_STARTMENU_GETFOLDER macro is not working as expected - instead of giving me the folder that the user actually entered, it gives me the default that I set earlier. Near the beginning of my script I have:
Var StartMenuFolder ; Define variable to hold start menu folder
!define MUI_STARTMENUPAGE_DEFAULTFOLDER "${PRODUCT_PUBLISHER}\${PRODUCT_NAME}" ; Set default start menu folder
!insertmacro MUI_PAGE_STARTMENU Application $StartMenuFolder
I can access $StartMenuFolder in installer (but NOT uninstaller) Sections by use of !insertmacro MUI_STARTMENU_GETFOLDER Application $StartMenuFolder. In uninstaller sections and macros, instead of returning the actual start menu folder, it returns the default folder I specified above.

The MUI_STARTMENU_GETFOLDER macro assumes that you used the MUI_STARTMENUPAGE_REGISTRY_* defines and the MUI_STARTMENU_WRITE_* macros during install (All MUI_STARTMENU_GETFOLDER does is read the registry entry written by the installer (The entry is written in MUI_STARTMENU_WRITE_END if the MUI_STARTMENUPAGE_REGISTRY_* defines are set correctly))

Related

How to run aspnet_regiis.exe in a deferred custom action and pass the value of INSTALLDIR property?

I have a custom action (RunEncryption2) that I'm using for encrypting a configuration file by using aspnet_regiis.exe. The custom action type that I'm using is an EXE with path referencing a directory (initial type 34) using deferred execution in system context (so the final type is 3106). The file that I want to encrypt is on INSTALLDIR, so I have a Set Property custom action (SetRunEncryption2, type 51) where I'm setting RunEncryption2=[INSTALLDIR]. My two custom actions look like this:
SetRunEncryption2
Property Name: RunEncryption2
Property Value: [INSTALLDIR]
RunEncryption2
Working Directory: WindowsFolder
File Name & Command line: [WindowsFolder]Microsoft.NET\Framework\v4.0.30319\aspnet_regiis.exe -pef "connectionStrings" "[CustomActionData]" -prov "DataProtectionConfigurationProvider"
When the installer runs, I get no error, however the file gets no encryption at all. When I review the log, I get the following:
MSI (s) (34:C0) [17:32:11:356]: Executing op: CustomActionSchedule(Action=RunEncryption2,ActionType=3106,Source=C:\WINDOWS\,Target=C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\aspnet_regiis.exe -pef "connectionStrings" "" -prov "DataProtectionConfigurationProvider",CustomActionData=C:\Test\)
From the log I can see that the CustomActionData property has been set correctly, however it hasn't been included as part of the command.
At this point the only way I have to make the command work is passing a hard-coded value of INSTALLDIR, otherwise it doesn't seem to work.
I have tried:
Not using CustomActionData, instead passing the value of INSTALLDIR as part of my command line directly.
Using a "Path in Property value" custom action with similar results.
When I run option 1 above, I get a 1722 error on the log:
MSI (s) (C4:50) [12:49:46:968]: Note: 1: 1722 2: RunEncryption2 3: C:\WINDOWS\ 4: C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\aspnet_regiis.exe -pef "connectionStrings" "C:\Test\" -prov "DataProtectionConfigurationProvider"
Error 1722. There is a problem with this Windows Installer package. A program run as part of the setup did not finish as expected. Contact your support personnel or package vendor. Action RunEncryption2, location: C:\WINDOWS\, command: C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\aspnet_regiis.exe -pef "connectionStrings" "C:\Test\" -prov "DataProtectionConfigurationProvider"
MSI (s) (C4:50) [12:49:56:841]: Product: TestEncryption -- Error 1722. There is a problem with this Windows Installer package. A program run as part of the setup did not finish as expected. Contact your support personnel or package vendor. Action RunEncryption2, location: C:\WINDOWS\, command: C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\aspnet_regiis.exe -pef "connectionStrings" "C:\Test\" -prov "DataProtectionConfigurationProvider"
Does anyone know how can I do to correctly execute this command and dynamically pass the value of INSTALLDIR?
Finally found the problem was not in the custom action passing the properties, but in the way that aspnet_iisreg is expecting the parameters.
INSTALLDIR is passing the string with a trailing slash (e. gr. c:\Test\), when I hard coded the installation path I was passing c:\Test instead.
The solution consisted in creating another custom action that removes the trailing slash and stores the value in a new property, this then can be used as parameter for aspnet_iisreg.
By the way, as Michael Urman mentioned, there was no need to use CustomActionData. Thanks.

NSIS Access Control Read Only

I have a C program with an installer created by an NSIS script. The issue is one of the files that the installer adds needs to be read only. For this problem I am trying to use the AccessControl plugin. I include the plugin directory with the following line:
!addplugindir "AccessControl\Unicode\Plugins"
At the bottom of my install section I have attempted these lines with no success:
AccessControl::GrantOnFile "$INSTDIR\file.txt" "BUILTINUSERS" "GenericRead + Delete"
AccessControl::GrantOnFile "$INSTDIR\file.txt" "(BU)" "GenericRead + Delete"
AccessControl::GrantOnFile "$INSTDIR\file.txt" "(S-1-5-32-545)" "GenericRead + Delete"
AccessControl::GrantOnFile "$INSTDIR\file.txt" "(S-1-1-0)" "GenericRead + Delete"
There is no error displayed when the script is compiled but after running the installer the file can still be written over. I have had no success from any of these sources.
http://nsis.sourceforge.net/AccessControl_plug-in
http://avidinsight.uk/2014/01/nsis-access-control-problem-with-built-in-users-group/
How do you set directory permissions in NSIS?
http://nsis.sourceforge.net/Talk:AccessControl_plug-in
On a final note I am using Windows 8.
GrantOnFile appends to the existing ACL for the file and never restricts anything. Use SetOnFile to start a new ACL or in your case, use DenyOnFile to deny access for specific groups.
You should also Pop after each call to these functions, the popped string will be "ok" or a error message.

command AutoCloseWindow not valid in Section

Section userSoftware
MessageBox MB_YESNO|MB_ICONQUESTION "Insert user software DVD in to drive and click Yes to install User Software or click No to Proceed" /SD IDNO IDYES yes IDNO no
yes:
AutoCloseWindow true
SetRebootFlag false
Call installUserSoftware
no:
;do nothing
SectionEnd
Section: "userSoftware"
Error: command AutoCloseWindow not valid in Section
This is the error I am getting with AutoCloseWindow. All I am trying to do is after installing the server software if user selects to install Client software, installation of server software should disappear without asking user to hit finish button.
Code I gave I am just testing how AutoCloseWindow or SetAutoClose works, nut all I have is an error!!
AutoCloseWindow is a property like Name and Installdir and must be placed outside functions and sections. If you want to set the autoclose flag at runtime you must use the SetAutoClose command...

nsis custom page sizes

I am trying to create a page that is showing my website (nsWeb::ShowWebInPage).
The problem is, it can't show the whole page.
How can I define new sizes (height x width) to this page?
This is a big task. Here are the steps for making it work, in a somewhat flexible way.
Download Resource Hacker: http://www.angusj.com/resourcehacker/
Then decide if you want to edit the Unicode or the ANSI version of NSIS. You could do both, but why bother. Find your Program Files\NSIS folder first. This will be the BASE folder for the following directories in the next step if you are compiling for ANSI. If you are compiling for unicode, then step into the Program Files\NSIS\Unicode folder, and THIS is now your base folder for the next steps.
Look inside the \Contrib\UIs folder. This folder stores a bunch of executable files. Depending on which configuration of MUI2 you are using you need to edit the respective file AND modern.exe. The version of the file depends on if ou have a header image, if it's adjusted right or not, etc.
For example, in my case, I had these definitions in my installer script
!define MUI_HEADERIMAGE
!define MUI_HEADERIMAGE_RIGHT
Now, when I look in \Contrib\Modern UI 2\Interface.nsh, I can figure out fairly easily which file I need to edit. Here is what I look at:
!insertmacro MUI_DEFAULT MUI_UI "${NSISDIR}\Contrib\UIs\modern.exe"
!insertmacro MUI_DEFAULT MUI_UI_HEADERIMAGE "${NSISDIR}\Contrib\UIs\modern_headerbmp.exe"
!insertmacro MUI_DEFAULT MUI_UI_HEADERIMAGE_RIGHT "${NSISDIR}\Contrib\UIs\modern_headerbmpr.exe"
!insertmacro MUI_DEFAULT MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\modern-install.ico"
!insertmacro MUI_DEFAULT MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico"
!insertmacro MUI_DEFAULT MUI_BGCOLOR "FFFFFF"
Since I'm using the MUI_HEADERIMAGE_RIGHT, I will be editing the modern_headerbmpr.exe file.
Now, open Resource Hacker and load the file you want to edit. Resource Hacker has a GUI, so as you step through each dialog and each control on the dialog, you can see the GUI change side after you press 'recompile'. This part is pretty straight forward. Step through ALL the dialogs (why not) and edit the controls and sizes, including that of the main installer. In this file, there is only one, so you ALSO need to open up modern.exe, which contains the sub-controls that goes into the installer pages. Again, step through all the dialogs and change all the sizes so each control looks good. Compile, and save the files back in to this folder.
Bonus points: For testing, just overwrite the original files. You did take a backup, right? For deployment, name the new files something like "modern-wide.exe", for each file you edit. Later, we can dynamically switch between these with a little magic.
Recompile your installer, and now you should see a new size installer.
If you don't, check that you are in fact in the right ANSI versus UNICODE folder, or your changes won't work.
SOME of the screens, however, add controls dynamically. As an example, look at \Contrib\Modern UI 2\Pages\Welcome.nsh.
This file adds the title label and welcome text in code, and NOT via the exe files. Argh, I know! So locate the Macro:
!macro MUI_FUNCTION_WELCOMEPAGE PRE LEAVE
And these lines of code:
${NSD_CreateBitmap} 0u 0u 109u 193u ""
...
${NSD_CreateLabel} 120u 10u 195u ${MUI_WELCOMEPAGE_TITLE_HEIGHT}u "${MUI_WELCOMEPAGE_TITLE}"
...
${NSD_CreateLabel} 120u ${MUI_WELCOMEPAGE_TEXT_TOP}u 195u 130u "${MUI_WELCOMEPAGE_TEXT}"
As you can see, the units here are X Y WIDTH HEIGHT, so now you get to modify these controls. Of course, if you don't use the welcome page, don't bother. But you may need to edit the pages that doesn't work for you in this manner.
You can overwrite the original, or again, save the file with "-wide" appended to the filename.
Now, your basically done !
Now, to make this MUCH easier to switch, I will assume you saved:
welcome.nsh as welcome-wide.nsh
modern.exe as modern-wide.exe
and let's say modern_headerbmpr.exe as modern_headerbmpr-wide.exe
Now, in your installer, add this !define BEFORE including MUI2.nsh:
!define MUI_ALTERNATE_SIZE_EXT "-wide"
in interface.nsh, change the code to this:
!ifdef MUI_ALTERNATE_SIZE_EXT
!insertmacro MUI_DEFAULT MUI_UI "${NSISDIR}\Contrib\UIs\modern${MUI_ALTERNATE_SIZE_EXT}.exe"
!insertmacro MUI_DEFAULT MUI_UI_HEADERIMAGE "${NSISDIR}\Contrib\UIs\modern_headerbmp.exe"
!insertmacro MUI_DEFAULT MUI_UI_HEADERIMAGE_RIGHT "${NSISDIR}\Contrib\UIs\modern_headerbmpr${MUI_ALTERNATE_SIZE_EXT}.exe"
!insertmacro MUI_DEFAULT MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\modern-install.ico"
!insertmacro MUI_DEFAULT MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico"
!insertmacro MUI_DEFAULT MUI_BGCOLOR "FFFFFF"
!else
!insertmacro MUI_DEFAULT MUI_UI "${NSISDIR}\Contrib\UIs\modern.exe"
!insertmacro MUI_DEFAULT MUI_UI_HEADERIMAGE "${NSISDIR}\Contrib\UIs\modern_headerbmp.exe"
!insertmacro MUI_DEFAULT MUI_UI_HEADERIMAGE_RIGHT "${NSISDIR}\Contrib\UIs\modern_headerbmpr.exe"
!insertmacro MUI_DEFAULT MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\modern-install.ico"
!insertmacro MUI_DEFAULT MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico"
!insertmacro MUI_DEFAULT MUI_BGCOLOR "FFFFFF"
!endif
This essentially switches your installer from regular to "-wide" when you define MUI_ALTERNATE_SIZE_EXT as "-wide". Note how I added the ${MUI_ALTERNATE_SIZE_EXT} directly to the file name include of the files I changed, and you should of course do this for the files YOU ended up changing when you started.
Now, you will also need to do this in the MUI2.NSH file, like so:
!ifdef MUI_ALTERNATE_SIZE_EXT
!include "Pages\Components.nsh"
!include "Pages\Directory.nsh"
!include "Pages\Finish.nsh"
!include "Pages\InstallFiles.nsh"
!include "Pages\License.nsh"
!include "Pages\StartMenu.nsh"
!include "Pages\UninstallConfirm.nsh"
!include "Pages\Welcome${MUI_ALTERNATE_SIZE_EXT}.nsh"
!else
!include "Pages\Components.nsh"
!include "Pages\Directory.nsh"
!include "Pages\Finish.nsh"
!include "Pages\InstallFiles.nsh"
!include "Pages\License.nsh"
!include "Pages\StartMenu.nsh"
!include "Pages\UninstallConfirm.nsh"
!include "Pages\Welcome.nsh"
!endif
As you edit more files, you simply keep a version of each new UI you create in separate filenames, and now you can switch the UI style of your installer with just the one definition. You can name files as you wish, and expand this scheme to other areas where you may run into trouble.
Not an easy task to do this, but it can be done.
You have two options:
Use the ChangeUI instruction along with a custom/resized UI created by Resource Hacker (NSIS ships with the default and modern ui's in the contrib folder, you can just modify those)
Resize the dialog at runtime with the system plugin (call user::SetWindowPos) in the show callback for the page
You have to resize all dialogs using the Resource Hacker.
Standard dialog (inner) size is 300*140 units, increase it as you wish.
Do not forget to increase all dialogs (License page, Installation page, Directory page, etc) also on this new size.

NSIS: Problem reading installdir by InstallDirRegKey

I have a nsi script which starts as following:
Name "myprog"
OutFile "myprog.exe"
InstallDir $PROGRAMFILES32\xx
InstallDirRegKey HKLM "Software\yy\xx" "InstallDir"
RequestExecutionLevel admin
AutoCloseWindow true
BrandingText /TRIMCENTER "me"
LoadLanguageFile "${NSISDIR}\Contrib\Language files\German.nlf"
Caption "Updateprogramm"
It works fine on my dev machine, but not on production (e.g. the user has only readonly permissions for the registry path). It is a Win 2003 server os. Even when the registry key exists, the program tries to install in $PROGRAMFILES32\xx.
InstallDirRegKey only needs read access.
The thing troubling thing for me is that you are talking about read only, but you have "RequestExecutionLevel admin" in your script. This says to me that you require admin rights and when you have "RequestExecutionLevel admin" you also need to use UserInfo::GetAccountType (To handle < NT6 systems and Vista+ when UAC is off)

Resources