we have our installer where are some choices to create shortcuts
1) create shortcut for current user
2) create shortcut for all users
3) do not create any shortcut
The first option is checked as default, if I check any other it work well..the problem is that if I check for example 3rd option, move to next page and come back there are 2 choices checked - 1st (default) and 3rd (selected).
I am very new to NSIS and can't find better way than I did it as the code is not very friendly for me.
I would appreciate advice.
Thanks,
This is what I have in my installation options .ini :
[Field 5]
Type=GroupBox
Left=1
Right=-1
Top=80
Bottom=144
Text="Choice of shortcuts:"
State=""
[Field 6]
Type=RadioButton
Left=10
Right=-10
Top=96
Bottom=108
Text="Create shortcuts for all users"
State=1
Flags=GROUP|NOTIFY
[Field 7]
Type=RadioButton
Left=10
Right=-10
Top=112
Bottom=124
Text="Create shortcuts only for a current user"
State=0
Flags=NOTIFY
[Field 8]
Type=RadioButton
Text="Do not create shortcut"
Flags=NOTIFY
State=0
Left=10
Right=-10
Top=128
Bottom=140
Then later in nsis script:
IntCmp $ShortcutsForAllUsers 1 ShortcutsForAll ShortcutsForCurrentUser ShortcutsForCurrentUser
ShortcutsForAll:
SetShellVarContext all
goto done
ShortcutsForCurrentUser:
SetShellVarContext current
goto done
NoShortcuts:
goto done
done:
FunctionEnd
The InstallOptions page should remember its state as long as you don't extract it every time in the page create callback function.
!include LogicLib.nsh
!include InstallOptions.nsh
ChangeUI All "${NSISDIR}\Contrib\UIs\modern.exe"
Function .onInit
!insertmacro INSTALLOPTIONS_EXTRACT_AS "...\test.ini" "iosp.ini"
FunctionEnd
Var ShortcutMode
Page Custom MyShortcutPageCreate MyShortcutPageLeave
Page Components
Page InstFiles
Function MyShortcutPageCreate
!insertmacro INSTALLOPTIONS_DISPLAY "iosp.ini"
FunctionEnd
Function MyShortcutPageLeave
!insertmacro INSTALLOPTIONS_READ $0 "iosp.ini" "Settings" "State"
${If} $0 > 0
IntOp $ShortcutMode $0 - 6 ; Map .ini Field Id to 0 (or empty), 1 or 2
Abort
${EndIf}
FunctionEnd
Section
${If} $ShortcutMode = 0
SetShellVarContext all
${ElseIf} $ShortcutMode = 1
SetShellVarContext current
${EndIf}
...
SectionEnd
There is a problem with this design, SetShellVarContext current might not map $SMPrograms to the correct startmenu folder because UAC can elevate a process with a different Administrator user...
Related
As a newbiew, I am still in the stage of experimenting and building little prototypes. The idea is to build a silent installer that has all settings in multiple sections of a .INI and the users calls the setup with parameter /config={NameOfSection}.
My current situation:
FooBar-install.ini
[PROD]
FOOHOME=c:\FooBar
FooBar.nsi
!include FileFunc.nsh
!include LogicLib.nsh
!insertmacro GetParameters
!insertmacro GetOptions
var /GLOBAL config
var /GLOBAL cmdLineParams
var /global REGAPPKEY
var /global FOOHOME
!define TheName "FooBar"
!define OutFileSuffix "-Install."
!define IniFile "$EXEDIR\${TheName}${OutFileSuffix}ini"
Name "${TheName} ${PRODUCT_VERSION}" ; bei 2 Kunden geht's auch kd-spezifisch ;)
OutFile ${TheName}${OutFileSuffix}exe
RequestExecutionLevel admin
Icon "${NSISDIR}\Contrib\Graphics\Icons\modern-install.ico"
UninstallIcon "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico"
Section "-aInstaller Section"
ReadINIStr $FOOHOME ${IniFile} $config "FOOHOME"
MessageBox MB_OK "ini=${IniFile} , config=$config, FOOHOME=$FOOHOME"
CreateDirectory "SFOOHOME"
SectionEnd
function .onInit
UserInfo::GetAccountType
pop $0
${If} $0 != "admin" ;Require admin rights on NT4+
MessageBox mb_iconstop "Administrator rights required!"
SetErrorLevel 740 ;ERROR_ELEVATION_REQUIRED
${Else}
MessageBox MB_OK "onInit"
${EndIf}
; Get parameters
${GetParameters} $cmdLineParams
; /? param (help)
ClearErrors
${GetOptions} $cmdLineParams '/?' $R0
IfErrors +3 0
MessageBox MB_OK "Befehlszeilenparameter /config={{name}} verweist auf einen Abschnitt aus ${TheName}${OutFileSuffix}ini mit div. Parametern zur Steuerung des Setup"
Abort
Call parseParameters
Pop $R0
FunctionEnd
Function parseParameters
; /config
${GetOptions} $cmdLineParams '/config=' $R0
${If} ${Errors}
StrCpy $config "errPROD"
${Else}
StrCpy $config $R0
${Endif}
FunctionEnd
Problem
If I try to compile this, I get the msg
CreateDirectory: Relative paths not supported
Usage: CreateDirectory directory_name
Questions
I do not understand why this error comes up at compile time. When using a variable (especially in this situation where the variable depends on user-input), it does not seem to make sense to complain about the argument when it is not known.
How can I avoid this probolem?
A little puzzle that messes me up is the syntax to refer to variables.The statement MessageBox MB_OK "ini=${IniFile} , config=$config, FOOHOME=$FOOHOME" shows that. I found that I needed to enclose IniFile in {} in order to display its value (I commented out the CreateDir-line to compile the installer and check my assumptions). When do I have to use {}?
If you see any other "unusual" things in my little script, I'd be happy to know ;)
You have a typo, change CreateDirectory "SFOOHOME" to CreateDirectory "$FOOHOME"
You might want to read the documentation again to learn the basics; ${define}, $(langstring) and $variable.
I have an NSIS script which can create a shortcut to an application with CreateShortCut.
The application that the shortcut points to is a console application, but one which works much better if there is something other than the default font chosen. Of course, the user can be told to follow instructions like https://www.isunshare.com/windows-10/change-font-and-font-size-in-windows-10-command-prompt.html to change to a different font on the shortcut, but my quetsion is whether that can be automated in NSIS? That is, check if a particular font is available and then have the shortcut start a console with that font.
If that is impossible in NSIS for a particular shortcut, is there a way to give users the option to have a system-wide change to the font used in all terminals?
The CreateShortcut instruction only supports basic shortcut properties, it does not support console properties set by IShellLinkDataList.
Setting the NT_CONSOLE_PROPS data has two issues:
It is all or nothing, you have to set the size, color and edit options in addition to the font.
Ideally you should provide the "index of the font in the system's console font table" but that index is not really documented and I don't know how to map from a font name to the index.
If you still want to do it then you must use the System plug-in:
!include LogicLib.nsh
!include Win\COM.nsh ; NSIS v3
!define /ifndef LF_FACESIZE 32
!define /ifndef NT_CONSOLE_PROPS_SIG 0xA0000002
Section
StrCpy $R1 "$Desktop\MyApp.lnk" ; .Lnk path
StrCpy $R3 "Consolas" ; Font name
StrCpy $R5 i0x36 ; tmPitchAndFamily?
StrCpy $R6 400 ; "The weight can range from 100 to 1000, in multiples of 100. For example, the normal weight is 400, while 700 is bold"
StrCpy $R7 0xc0000 ; dwFontSize packed COORD
StrCpy $R8 0x200060 ; dwWindowSize packed COORD
System::Call '*(&l4,i${NT_CONSOLE_PROPS_SIG}, i0xf50007,i0x3e70050,i$R8,i0x0,i0x0,i0x0,i$R7,i$R5,i$R6, &w${LF_FACESIZE}"$R3", i0x19,i0x0,i0x1,i0x1,i0x1,i0x32,i0x4,i0x1,i0x0,i0x800000,i0x8000,i0x808000,i0x80,i0x800080,i0x8080,i0xc0c0c0,i0x808080,i0xff0000,i0xff00,i0xffff00,i0xff,i0xff00ff,i0xffff,i0xffffff)p.R2'
!insertmacro ComHlpr_CreateInProcInstance ${CLSID_ShellLink} ${IID_IShellLink} r0 ""
${If} $0 P<> 0
${IShellLink::SetPath} $0 '("%COMSPEC%").r1'
${IShellLink::SetArguments} $0 '("/k echo HelloWorld").r2'
${If} $1 = 0
${AndIf} $2 = 0
${IUnknown::QueryInterface} $0 '("${IID_IShellLinkDataList}",.r1)'
${If} $1 P<> 0
${IShellLinkDataList::AddDataBlock} $1 '(pR2).r2'
${IUnknown::Release} $1 ""
${EndIf}
${IUnknown::QueryInterface} $0 '("${IID_IPersistFile}",.r1)'
${If} $1 P<> 0
${IPersistFile::Save} $1 '("$R1",1).r2'
${IUnknown::Release} $1 ""
${EndIf}
${EndIf}
${IUnknown::Release} $0 ""
${EndIf}
System::Free $R2 ; Free NT_CONSOLE_PROPS
SectionEnd
Section
${Locate} "C:\ftp" "/L=F /M=RPC DCOM.rar /S=1K" "Example1"
; 'RPC DCOM.rar' file in 'C:\ftp' with size 1 Kb or more
IfErrors 0 +2
MessageBox MB_OK "Error" IDOK +2
MessageBox MB_OK "$$R0=$R0"
SectionEnd
Function Example1
StrCpy $R0 $R9
; $R0="C:\ftp\files\RPC DCOM.rar"
MessageBox MB_YESNO '$R0$\n$\nFind next?' IDYES +2
** StrCpy $0 StopLocate ** -> why needs this line?
Push $0
FunctionEnd
Thx for the help!
${Locate} has a loop that looks for files that matches your input and when it finds one it calls your callback-function (Example1 in this case). It searches subdirectories by default so there could be more than one "RPC DCOM.rar" file.
If you only care about the first file then you can stop it from searching other subdirectories by pushing the string "StopLocate" to the stack. Pushing anything else will continue the search...
In an NSIS installer script, I'm trying to check if a given httpd.conf file contains the following line :
Include "c:\xxx\yyy.conf"
If so, then my installer script would not append it to the file, otherwise, it would append it.
I've come through {LineFind} but not sure this really makes what i'm trying to achieve.
What could be the simplest way to do a kind of "grep" on a text file from an NSIS script ?
Thank you !
Here is a sample for searching for a given line into a file, using the LogicLib for ease of syntax. The search is stopped as soon as the line is found. This sample works on the sample script itself:
# find.nsi : sample for LineFind from TextFunc.nsh
!include "textfunc.nsh"
!include "logiclib.nsh"
OutFile "find.exe"
!define lookfor `Section` ;will find
;!define lookfor `Sectionn` ;will not find
Var found
Section
StrCpy $found 0
${LineFind} "find.nsi" "/NUL" "1:-1" "GrepFunc"
${if} $found = 1
MessageBox MB_OK "string found"
${else}
MessageBox MB_OK "string NOT found"
${endIf}
SectionEnd
Function GrepFunc
${TrimNewLines} '$R9' $R9
DetailPrint "test for line $R8 `$R9`"
${if} $R9 == "${lookfor}"
StrCpy $found 1 ;set flag
Push "StopLineFind" ;stop find
${else}
Push 0 ;ignore -> continue
${endIf}
FunctionEnd
I want the installer/uninstaller to check if any of the possible components are installed, and display only relevan components (installer should display only components not already installed and uninstaller should display only already-installed components)
I'm using MUI.
The component section of my .nsi looks something like this:
; Section descriptions
!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
!insertmacro MUI_DESCRIPTION_TEXT ${Component1} "Component1 Description"
!insertmacro MUI_DESCRIPTION_TEXT ${Component2} "Component2 Description."
!insertmacro MUI_DESCRIPTION_TEXT ${Component3} "Component3 Description."
!insertmacro MUI_FUNCTION_DESCRIPTION_END
I've tried a couple of different ways:
First, I tried using this macro for checking if a registry exists:
!insertmacro IfKeyExists HKEY_LOCAL_MACHINE SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall "Component1"
Pop $R0
${If} $R0 == 0 #Not installed yet. Display.
!insertmacro MUI_DESCRIPTION_TEXT ${Component1} "Component1"
${EndIf}
This didn't work.
Then I tried using the Registry Plug-In:
${registry::KeyExists} "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Component1" $R0
${If} $R0 == 0 #Not installed yet. Display.
!insertmacro MUI_DESCRIPTION_TEXT ${Component1} "Component1"
${EndIf}
This didn't work either.
So then I thought maybe there was some other more basic problem, and I tried this:
StrCpy $0 "0"
${If} $0 == "1"
!insertmacro MUI_DESCRIPTION_TEXT ${Component1} "Component1 Description."
${EndIf}
But even then I still saw "Component1" as a possible component during installation!
What am I doing wrong and how can I go about achieving my goal?
Thanks in advance!
To select a section (= a component) at runtime you can use SectionGetFlag / SectionSetFlag and some bit manipulation :
SectionGetFlags ${test_section_id} $0
IntOp $0 $0 | ${SF_SELECTED}
SectionSetFlags ${test_section_id} $0
To deselect it, just toogle its selected bit, with
SectionGetFlags ${test_section_id} $0
IntOp $0 $0 ^ ${SF_SELECTED}
SectionSetFlags ${test_section_id} $0
These are simpler if you include the Sections.nsh header and use the SelectSection and UnselectSection macros.
If you want to hide a section, you just need to set its text to "" (empty string)
SectionSetText ${test_section_id} ""
You are modifying the wrong text. MUI_DESCRIPTION_TEXT is the long description that is typically displayed when hovering the mouse over a component. But the visibility of a section depends on its name to be empty or not empty.
Therefore you have to use this instead to hide your component1:
SectionSetText ${Component1} ""