NSIS - printing to prompt during command line install - nsis

I'm making installers for windows using NSIS and have a number of custom install options that the user can specify using the command line, for example:
installer.exe /IDPATH=c:\Program Files\Adobe\Adobe InDesign CS5 /S
What I want to do is show these options to the person installing. I can easily enough parse the /? or /help parameters with ${GetParameters} and ${GetOptions}, but how do I do the actual printing to the command prompt?

NSIS is a GUI program and does not really have the ability to write to stdout.
On XP and later you can do this with the system plugin:
System::Call 'kernel32::GetStdHandle(i -11)i.r0'
System::Call 'kernel32::AttachConsole(i -1)'
FileWrite $0 "hello"
On < XP, there is no AttachConsole and you need to call AllocConsole on those systems (Will probably open a new console window)
Edit:
You could open a new console if the parent process does not have one already with
!include LogicLib.nsh
System::Call 'kernel32::GetStdHandle(i -11)i.r0'
System::Call 'kernel32::AttachConsole(i -1)i.r1'
${If} $0 = 0
${OrIf} $1 = 0
System::Call 'kernel32::AllocConsole()'
System::Call 'kernel32::GetStdHandle(i -11)i.r0'
${EndIf}
FileWrite $0 "hello$\n"
But it does not really make any sense as far as /? handling goes, you might as well open a message box when there is no console
!include LogicLib.nsh
StrCpy $9 "USAGE: Hello world!!" ;the message
System::Call 'kernel32::GetStdHandle(i -11)i.r0' ;try to get stdout
System::Call 'kernel32::AttachConsole(i -1)i.r1' ;attach to parent console
${If} $0 <> 0
${AndIf} $1 <> 0
FileWrite $0 "$9$\n"
${Else}
MessageBox mb_iconinformation $9
${EndIf}

!include LogicLib.nsh
StrCpy $9 "USAGE: Hello world!!" ;the message
System::Call 'kernel32::AttachConsole(i -1)i.r0' ;attach to parent console
${If} $0 != 0
System::Call 'kernel32::GetStdHandle(i -11)i.r0' ;console attached -- get stdout
FileWrite $0 "$9$\n"
${Else}
;no console to attach -- show gui message
MessageBox mb_iconinformation $9
${EndIf}
First attach console then get std handle. Before attach handles may (often will) be invalid.

Related

How to show the print dilaog to select the option to print when clicked on "print" from the license agreement installer screen using NSIS

How to show the print dialog to select the option to print when clicked on "print" from the license agreement installer screen using NSIS.
I want to display the below screen when clicked on "Print" from the License agreement screen.
If i use the below command it is directly printing the page without popping up the Print dialog.
There is no built-in support but you can display this common dialog with the system plug-in:
!include LogicLib.nsh
!define /IfNDef PD_HIDEPRINTTOFILE 0x00100000
!define /IfNDef PD_NOSELECTION 0x00000004
!define /IFNDef PD_USEDEVMODECOPIESANDCOLLATE 0x00040000 ; Just one copy
Function ShowPrintDlg
System::Call '*(p0,p$hwndparent,p0,p0,p,i${PD_HIDEPRINTTOFILE}|${PD_NOSELECTION}|${PD_USEDEVMODECOPIESANDCOLLATE},&i2,&i2,&i2,&i2,&i2,p,p,p,p,p0,p0,p0,p0,&l.r0)p.r1'
System::Call '*$1(ir0)'
System::Call 'COMDLG32::PrintDlg(pr1)i.r0'
${If} $0 <> 0
System::Call '*$1(p,p,p.r3,p.r4,t""r2)'
System::Free $1
System::Call 'KERNEL32::GlobalFree(pr3)'
System::Call 'KERNEL32::GlobalLock(pr4)p.r1'
${If} $1 P<> 0
System::Call '*$1(&i2,&i2.r2,&i2,&i2)'
System::Call '*$1(&i$2,&t999.r2)'
System::Call 'KERNEL32::GlobalUnlock(pr1)'
System::Call 'KERNEL32::GlobalFree(pr4)'
${EndIf}
MessageBox mb_ok 'User wants to print to "$2"'
${Else}
System::Free $1
${EndIf}
FunctionEnd
Page InstFiles
Section
Call ShowPrintDlg
SectionEnd

NSIS GetVolumeInformation Results

Ok I found this code from another question asked and I'm a newbie for NSIS. Question Below
!define FILE_SUPPORTS_ENCRYPTION 0x00020000
!define FILE_READ_ONLY_VOLUME 0x00080000
!define FILE_VOLUME_QUOTAS 0x00000020
!macro MakeBitFlagYesNo flags bit outvar
IntOp ${outvar} ${flags} & ${bit}
${IfThen} ${outvar} <> 0 ${|} StrCpy ${outvar} "Yes" ${|}
${IfThen} ${outvar} == 0 ${|} StrCpy ${outvar} "No" ${|}
!macroend
StrCpy $0 "c:\"
System::Call 'Kernel32::GetVolumeInformation(t "$0",t,i ${NSIS_MAX_STRLEN},*i,*i,*i.r1,t,i ${NSIS_MAX_STRLEN})i.r0'
${If} $0 <> 0
!insertmacro MakeBitFlagYesNo $1 ${FILE_SUPPORTS_ENCRYPTION} $2
!insertmacro MakeBitFlagYesNo $1 ${FILE_READ_ONLY_VOLUME} $3
!insertmacro MakeBitFlagYesNo $1 ${FILE_VOLUME_QUOTAS} $4
MessageBox mb_ok "flags=$1 $\nFILE_SUPPORTS_ENCRYPTION=$2$\nFILE_READ_ONLY_VOLUME=$3$\nFILE_VOLUME_QUOTAS=$4"
${EndIf}
Here is what I need to get:
Drive Volume Label:
File System: (Fat32, NTFS, exFat, ...)
Disk Capacity: (7.27TB, 5.59TB, ...)
Free Space: (4.62TB , 632GB, ...)
Allocation Unit Size: (4096b, 16kb, 32kb, ...)
and then I need to use that info in a if then statement
Just not sure how to turn the above code and results into code list below.
I have tried searching google about NSIS and GetVolumeInformation, and with the GetVolumeInformation I could not find out how to get and read results anywhere.
${If} $File_System <> "NTFS"
${EndIf}
${If} $Disk_Capacity < "1.86TB"
${EndIf}
${If} $Free_Space < "1.25TB"
${EndIf}
${If} $Allocation_Unit_Size <> "4096 bytes"
${EndIf}
MessageBox mb_ok "$Drive_Volume_Label$\n$File_System$\n$Disk_Capacity$\n$Free_Space$\n$Allocation_Unit_Size"
And if you could post the answer code for me and then point me where you got the info (the explanation of the) code. This help me learn the code faster if I know what its doing for what I need.
Thanks,
Albert
The code in the answer you found does actually return the name of the file system and then it goes on to tell you that that is probably not the best way to do things. You should use the file system flags if possible. Case in point, Microsofts new file system ReFS supports some of the NTFS features and adds some new reliability features.
!include LogicLib.nsh
StrCpy $9 "c:\"
System::Call 'Kernel32::GetVolumeInformation(t "$9",t.r3,i ${NSIS_MAX_STRLEN},*i,*i,*i.r1,t.r2,i ${NSIS_MAX_STRLEN})i.r0'
${If} $0 <> 0
IntFmt $1 "%#.8x" $1
MessageBox MB_OK " FileSystemFlags=$1 $\n FileSystemName=$2 $\n VolumeName=$3"
${If} $2 == "NTFS"
MessageBox MB_OK "$9 is NTFS"
${Else}
MessageBox MB_OK "$9 is $2 and not NTFS but hopefully you don't care"
${EndIf}
${EndIf}
Your other properties are not exposed by this function which would be obvious if you looked at its documentation on MSDN.
!include LogicLib.nsh
StrCpy $9 "c:\"
System::Call 'Kernel32::GetDiskFreeSpaceEx(t "$9", *l.r1, *l.r2, *l.r3)i.r0' ; This function does not work on Windows 95
${If} $0 <> 0
MessageBox MB_OK " FreeBytesAvailable=$1 $\n TotalNumberOfBytes=$2 $\n TotalNumberOfFreeBytes=$3"
System::Call 'ShLwApi::StrFormatByteSizeW(l $1, w.r4, i ${NSIS_MAX_STRLEN})'
MessageBox MB_OK "Friendly FreeBytesAvailable: $4" ; For display in UI only!
!define /math MYSIZE 0x100000 * 666 ; 666 MiB
${If} $1 L>= ${MYSIZE}
MessageBox MB_OK "Disk quota on $9 allows you to write at least ${MYSIZE} bytes on this volume"
${Else}
MessageBox MB_OK|MB_ICONSTOP "Not enough space on volume, ${MYSIZE} bytes required!"
Quit
${EndIf}
${EndIf}
NSIS already provides a directory page that checks the disk space, use that if possible. Note: You cannot compare numbers of different scales (TB vs GB etc.), you must compare a 64-bit count of bytes.
By allocation unit I assume you are talking about the cluster size?
!include LogicLib.nsh
StrCpy $9 "c:\"
System::Call 'Kernel32::GetDiskFreeSpace(t "$9", *i.r1, *i.r2, *i, *i)i.r0'
${If} $0 <> 0
IntOp $1 $1 * $2
System::Call 'ShLwApi::StrFormatByteSizeW(l $1, w.r3, i ${NSIS_MAX_STRLEN})'
MessageBox MB_OK "Cluster size: $3 ($1 bytes)"
${If} 4096 <> $1
; ...
${EndIf}
${EndIf}
(The reported cluster size is probably the logical size, not the physical size)

Product version string from an exe - nsis

I want to read the product version (optional string) from a given executable (actually from the installer I'm trying to create if it makes any difference), if it is possible at the run-time. This string will be further used to download files from a link.
Thank you very much !
NSIS does not have native support for reading anything other than VS_FIXEDFILEINFO->dwFileVersion so you have to call the Windows API directly:
; Add some version information so we have something to test
VIProductVersion 1.2.3.4
VIAddVersionKey "ProductVersion" "One Two Three Four"
VIAddVersionKey "FileVersion" "Whatever"
VIAddVersionKey "FileDescription" "Whatever"
VIAddVersionKey "LegalCopyright" "(C) Whatever"
!include LogicLib.nsh
Function GetFileVerFirstLangProductVersion
System::Store S
pop $3
push "" ;failed ret
System::Call 'version::GetFileVersionInfoSize(t"$3",i.r2)i.r0'
${If} $0 <> 0
System::Alloc $0
System::Call 'version::GetFileVersionInfo(t"$3",ir2,ir0,isr1)i.r0 ? e'
pop $2
${If} $0 <> 0
${AndIf} $2 = 0 ;a user comment on MSDN said you should check GLE to avoid crash
System::Call 'version::VerQueryValue(i r1,t "\VarFileInfo\Translation",*i0r2,*i0)i.r0'
${If} $0 <> 0
System::Call '*$2(&i2.r2,&i2.r3)'
IntFmt $2 %04x $2
IntFmt $3 %04x $3
System::Call 'version::VerQueryValue(i r1,t "\StringFileInfo\$2$3\ProductVersion",*i0r2,*i0r3)i.r0'
${If} $0 <> 0
pop $0
System::Call *$2(&t$3.s)
${EndIf}
${EndIf}
${EndIf}
System::Free $1
${EndIf}
System::Store L
FunctionEnd
Section
Push "$ExePath" ; Read our own version information in this example
Call GetFileVerFirstLangProductVersion
Pop $0
DetailPrint "ProductVersion=$0"
SectionEnd

nsis refresh environment during setup

During my setup i install redistributables. After installing my program i want to execute the program during the setup. For that the redistributables are needed. But the environment is not refreshed during setup, so i can't start the program. Can i refresh the environtment during the setup, or reread the environment? Or read the system environment which has changed after the redistributable installation?
I need the environment changes made during the installation of the redistributables during the setup.
Thanks for your help.
I had your same issue, that I solved with a workaround, but I came across this solution and I would like to share with you.
This should reload environment variables during setup:
!include LogicLib.nsh
!include WinCore.nsh
!ifndef NSIS_CHAR_SIZE
!define NSIS_CHAR_SIZE 1
!define SYSTYP_PTR i
!else
!define SYSTYP_PTR p
!endif
!ifndef ERROR_MORE_DATA
!define ERROR_MORE_DATA 234
!endif
/*!ifndef KEY_READ
!define KEY_READ 0x20019
!endif*/
Function RegReadExpandStringAlloc
System::Store S
Pop $R2 ; reg value
Pop $R3 ; reg path
Pop $R4 ; reg hkey
System::Alloc 1 ; mem
StrCpy $3 0 ; size
loop:
System::Call 'SHLWAPI::SHGetValue(${SYSTYP_PTR}R4,tR3,tR2,i0,${SYSTYP_PTR}sr2,*ir3r3)i.r0' ; NOTE: Requires SHLWAPI 4.70 (IE 3.01+ / Win95OSR2+)
${If} $0 = 0
Push $2
Push $0
${Else}
System::Free $2
${If} $0 = ${ERROR_MORE_DATA}
IntOp $3 $3 + ${NSIS_CHAR_SIZE} ; Make sure there is room for SHGetValue to \0 terminate
System::Alloc $3
Goto loop
${Else}
Push $0
${EndIf}
${EndIf}
System::Store L
FunctionEnd
Function RefreshProcessEnvironmentPath
System::Store S
Push ${HKEY_CURRENT_USER}
Push "Environment"
Push "Path"
Call RegReadExpandStringAlloc
Pop $0
${IfThen} $0 <> 0 ${|} System::Call *(i0)${SYSTYP_PTR}.s ${|}
Pop $1
Push ${HKEY_LOCAL_MACHINE}
Push "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"
Push "Path"
Call RegReadExpandStringAlloc
Pop $0
${IfThen} $0 <> 0 ${|} System::Call *(i0)${SYSTYP_PTR}.s ${|}
Pop $2
System::Call 'KERNEL32::lstrlen(t)(${SYSTYP_PTR}r1)i.R1'
System::Call 'KERNEL32::lstrlen(t)(${SYSTYP_PTR}r2)i.R2'
System::Call '*(&t$R2 "",&t$R1 "",i)${SYSTYP_PTR}.r0' ; The i is 4 bytes, enough for a ';' separator and a '\0' terminator (Unicode)
StrCpy $3 ""
${If} $R1 <> 0
${AndIf} $R2 <> 0
StrCpy $3 ";"
${EndIf}
System::Call 'USER32::wsprintf(${SYSTYP_PTR}r0,t"%s%s%s",${SYSTYP_PTR}r2,tr3,${SYSTYP_PTR}r1)?c'
System::Free $1
System::Free $2
System::Call 'KERNEL32::SetEnvironmentVariable(t"PATH",${SYSTYP_PTR}r0)'
System::Free $0
System::Store L
FunctionEnd
Section
Call RefreshProcessEnvironmentPath
SectionEnd
Source: http://forums.winamp.com/showpost.php?p=3028153&postcount=12

How to change the text box value Using NSIS Script?

I am new to NSIS Script and creating installers.
In My page there is a text box. While the page loading the text box show the value of reading the text from one text file. I want to know how to do this Using NSIS Scripts.. Need code samples...
Function .onInit
InitPluginsDir
FileOpen $0 "$pluginsdir\text.txt" w ; Normally the text file would come from a File command
FileWrite $0 "Hello World$\r$\nfrom$\r$\nNSIS$\r$\n" ; Add some dummy text
FileClose $0
FunctionEnd
Page Custom MyCustomPageInit
Page InstFiles
Var TxtCtl
!include nsDialogs.nsh
!include LogicLib.nsh
Function MyCustomPageInit
nsDialogs::Create 1018
Pop $0
!define MYMULTILINEEDIT_STYLE ${DEFAULT_STYLES}|${WS_TABSTOP}|${ES_AUTOHSCROLL}|${ES_MULTILINE}|${ES_READONLY}
nsDialogs::CreateControl EDIT ${MYMULTILINEEDIT_STYLE} ${WS_EX_WINDOWEDGE}|${WS_EX_CLIENTEDGE} 5% 10u 90% 50% ""
Pop $TxtCtl
FileOpen $0 "$pluginsdir\text.txt" r
loop:
FileRead $0 $1 ; Read a line
IfErrors eof
SendMessage $TxtCtl ${EM_REPLACESEL} 0 "STR:$1$\n"
Goto loop
eof:
FileClose $0
nsDialogs::Show
FunctionEnd

Resources