NSIS: Get return code of ExecShell - nsis

I have to use ExecShell because my main programm has only user permissions and the called exe file inside this programm needs admin permissions.
RequestExecutionLevel user
ExecShell "open" "file.exe" SW_HIDE
I want get the return code, I tried to pop $0, pop $1, but I get always zero. Also if the file wasn't succesful.
I believe that pop $0 doesnt't wait for the ExecShell command, but I can't use ExecWait because of the needed admin permissions. How could I get the true return code?

ExecShell does not report a error code because it does not wait for the process.
If you want the exit code you have to call ShellExecuteEx manually:
!include LogicLib.nsh
!include WinCore.nsh
!ifndef SEE_MASK_NOCLOSEPROCESS
!define SEE_MASK_NOCLOSEPROCESS 0x00000040
!endif
Section
StrCpy $1 "Calc.exe" ; File to execute
System::Call '*(&l4, i ${SEE_MASK_NOCLOSEPROCESS}, p$HWNDPARENT, p0, tr1, p0, p0, p5, p0, p0, p0, p0, p0, p0, p)p.r1'
System::Call 'SHELL32::ShellExecuteEx(t)i.r0 (pr1)' ; (t) is a hint for A/W detection
${If} $0 <> 0
System::Call '*$1(i, i, p, p, p, p, p, p, p, p, p, p, p, p, p.r0)'
System::Call 'KERNEL32::WaitForSingleObject(p r0, i ${INFINITE})'
System::Call 'KERNEL32::GetExitCodeProcess(p r0 s,*i.r0)'
System::Call 'KERNEL32::CloseHandle(p s)'
DetailPrint ExitCode=$0
${EndIf}
System::Free $1
SectionEnd

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

Component Page Description-Box Scrollbar

I´m searching for a Solution to implement a Scrollbar to the Descriptionbox on the MUI2 Component page. Because i got a large text to fill in.
To make the UI bigger is the last option what i want to use.
I tried to implement the UMUI, with the option MUIEx to use the big description option, but with no effect.
There is no native support for this but putting a edit box there and hacking the change notification a bit seems to work OK:
OutFile Test.exe
RequestExecutionLevel user
!define MUI_CUSTOMFUNCTION_ONMOUSEOVERSECTION myOnMouseOver
!include MUI2.nsh
!insertmacro MUI_PAGE_WELCOME
!define MUI_PAGE_CUSTOMFUNCTION_PRE myCompPagePre
!insertmacro MUI_PAGE_COMPONENTS
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_LANGUAGE "English"
Var LastText
Var ScrollWindow
!include LogicLib.nsh
!define /IfNDef SB_VERT 1
Function myCompPagePre
StrCpy $ScrollWindow ""
FunctionEnd
Function myOnMouseOver
${If} $ScrollWindow P= 0
System::Call 'USER32::GetWindowRect(p$mui.ComponentsPage.DescriptionText,#r0)' ; NSIS v3+
System::Call 'USER32::GetParent(p$mui.ComponentsPage.DescriptionText)p.s'
System::Call '*$0(i.r1,i.r2,i.r3,i.r4)'
IntOp $3 $3 - $1
IntOp $4 $4 - $2
System::Call 'USER32::MapWindowPoints(p0, pss, pr0, i1)'
System::Call '*$0(i.r1,i.r2)'
System::Call 'USER32::CreateWindowEx(i0, t"EDIT", p0, i ${WS_VISIBLE}|${WS_CHILD}|${WS_VSCROLL}|${ES_MULTILINE}|${ES_READONLY}, i r1, i r2, i r3, i r4, ps, p0, p0, p0)p.s'
Pop $ScrollWindow
ShowWindow $mui.ComponentsPage.DescriptionText 0
SendMessage $mui.ComponentsPage.DescriptionText ${WM_GETFONT} 0 0 $0
SendMessage $ScrollWindow ${WM_SETFONT} $0 1
${EndIf}
${NSD_GetText} $mui.ComponentsPage.DescriptionText $0
System::Call 'USER32::IsWindowEnabled(p$mui.ComponentsPage.DescriptionText)i.r1'
${If} $1 <> 0 ; No hover text?
StrCpy $LastText $0
${EndIf}
${NSD_SetText} $ScrollWindow $LastText
System::Call 'USER32::ShowScrollBar(p $ScrollWindow, i ${SB_VERT}, i 1)'
System::Call 'USER32::GetScrollRange(p $ScrollWindow, i ${SB_VERT}, *i.r0, *i.r1)'
${If} $0 = $1
System::Call 'USER32::ShowScrollBar(p $ScrollWindow, i ${SB_VERT}, i 0)'
${EndIf}
FunctionEnd
Section SecA SID_A
SectionEnd
Section SecB SID_B
SectionEnd
!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
!insertmacro MUI_DESCRIPTION_TEXT ${SID_A} "aaa a a aa a "
!define longstr "Very looooooo o o o o o oo o o o o o ooo o o ng stri i i i i i in ng"
!insertmacro MUI_DESCRIPTION_TEXT ${SID_B} "bbb b b b b b b b b b b b ${longstr} ${longstr} ${longstr} ${longstr} ${longstr} END"
!insertmacro MUI_FUNCTION_DESCRIPTION_END

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 can I resize a NSD_SetImageOLE image

I'm using the plugin macro NSD_SetImageOLE from http://nsis.sourceforge.net/NsDialogs_SetImageOLE - And I would like add another macro NSD_SetStretchedImageOLE the same way nsDialog.nsh works.
But I'm not sure is it's even possible, I've found that the resizing of an IPicture can be done by getting the "HBITMAP, BITMAP and BITMAPINFO" and resizing it (quoted from http://www.mofeel.net/958-microsoft-public-vc-mfc/12516.aspx). Anyway, I'm kind of lost trying to covert these methods to NSIS's System::Call style.
I have updated http://nsis.sourceforge.net/mediawiki/images/6/65/NsDialogs_setImageOle.zip with a ${NSD_SetStretchedImageOLE} which encapsulates Anders' code for reusability. I've also changed it to use the control dimensions rather than you having to specify the size yourself.
!ifndef IID_IPicture
!define IID_IPicture {7BF80980-BF32-101A-8BBB-00AA00300CAB}
!endif
!define SRCCOPY 0xCC0020
!include nsDialogs.nsh
!define IMAGEPATH "$sysdir\migwiz\PostMigRes\Web\base_images\Documents.gif" ;"C:\Windows\Web\Wallpaper\Windows\img0.jpg"
!define NEWSIZEW 200
!define NEWSIZEH 100
Page Custom mypagestretchcreate_GDI ; GDI resize
Page Custom mypagestretchcreate_CTL ; Simple control resize
Function mypagestretchcreate_GDI
nsDialogs::Create 1018
Pop $0
System::Call 'oleaut32::OleLoadPicturePath(w "${IMAGEPATH}",i0r2,i0,i0,g"${IID_IPicture}",*i.r9)i.r1'
${If} $1 = 0
System::Call 'user32::GetDC(i0)i.s'
System::Call 'gdi32::CreateCompatibleDC(iss)i.r1'
System::Call 'gdi32::CreateCompatibleBitmap(iss,i${NEWSIZEW},i${NEWSIZEH})i.r2'
System::Call 'user32::ReleaseDC(i0,is)'
System::Call $9->3(*i.r3)i.r4 ; IPicture->get_Handle
${If} $4 = 0
System::Call 'gdi32::SetStretchBltMode(ir1,i4)'
System::Call '*(&i40,&i1024)i.r4' ; BITMAP / BITMAPINFO
System::Call 'gdi32::GetObject(ir3,i24,ir4)'
System::Call 'gdi32::SelectObject(ir1,ir2)i.s'
System::Call '*$4(i40,i.r6,i.r7,i0,i,i.s)' ; Grab size and bits-ptr AND init as BITMAPINFOHEADER
System::Call 'gdi32::GetDIBits(ir1,ir3,i0,i0,i0,ir4,i0)' ; init BITMAPINFOHEADER
System::Call 'gdi32::GetDIBits(ir1,ir3,i0,i0,i0,ir4,i0)' ; init BITMAPINFO
System::Call 'gdi32::StretchDIBits(ir1,i0,i0,i${NEWSIZEW},i${NEWSIZEH},i0,i0,ir6,ir7,is,ir4,i0,i${SRCCOPY})'
System::Call 'gdi32::SelectObject(ir1,is)'
System::Free $4
${EndIf}
System::Call 'gdi32::DeleteDC(ir1)'
System::Call $9->2() ; IPicture->release()
${EndIf}
${NSD_CreateBitmap} 1u 1u ${NEWSIZEW} ${NEWSIZEH} ""
Pop $9
;Not required when the control size matches: ${NSD_AddStyle} $9 ${SS_CENTERIMAGE}
SendMessage $9 ${STM_SETIMAGE} ${IMAGE_BITMAP} $2
nsDialogs::Show
System::Call 'gdi32::DeleteObject(ir2)'
FunctionEnd
Function mypagestretchcreate_CTL
nsDialogs::Create 1018
Pop $2
${NSD_CreateBitmap} 0 1u 70% 50% ""
Pop $3
${NSD_AddStyle} $3 ${SS_REALSIZECONTROL}
File "/oname=$PLUGINSDIR\image.bmp" "${NSISDIR}\Contrib\Graphics\Header\win.bmp"
${NSD_SetImage} $3 "$PLUGINSDIR\image.bmp" $1
nsDialogs::Show
${NSD_FreeImage} $1
FunctionEnd

NSIS - printing to prompt during command line install

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.

Resources