Is there anyway to call function after nsDialog show? - nsis

I wonder if there is any way which I can call function after nsDialog::show.
My case is a custom page that need to run http get request after the nsDialog show.
Function customPage
nsDialogs::Create 1018
Pop $0
${NSD_CreateButton} 0 0 100% 12u Test
Pop $BUTTON
${NSD_CreateText} 0 35 100% 12u hello
Pop $EDIT
${NSD_CreateCheckbox} 0 -20 100% 8u Test
Pop $CHECKBOX
${NSD_CreateLabel} 0 40u 75% 40u "* Type `hello there` above.$\n* Click the button.$\n* Check the checkbox.$\n* Hit the Back button."
Pop $0
nsDialogs::Show
Call MyFunc
FunctionEnd
Actually, the call for MyFunc is occuring only when im closing the nsDialog..

Use nsDialogs::CreateTimer with a short timeout and kill the timer in the function callback, it is a bit of a hack but seems to work fine.

nsDialog running by solo thread, but actually you can use nsDialogs::CreateTimer to callback a function without specify time which.
You can read more about that on:
http://nsis.sourceforge.net/Docs/nsDialogs/Readme.html#ref-createtimer

Related

NSIS Welcome Image stretching

I have a bitmap 164x314 with my logo which is showing just fine.
When I use header to resize my installer
!include "nsResize.nsh"
and add width and height to it
!define AddWidth 100u
!define AddHeight 75u
I also change dimensions of my bitmap to 164x436 and my logo is looking ugly and stretchy.
Even if I use
!define AddHeight 122
or
!define MUI_WELCOMEFINISHPAGE_BITMAP_NOSTRETCH
it don't do much.
What am I missing?
Left — original, right — NSIS
Solved my problem with using 0px intro file
File "/oname=$PluginsDir\modern-wizard.bmp" "${}\Intro\intro0.bmp"
${NSD_SetImage} "$mui.WelcomePage.Image" "$PLUGINSDIR\modern-wizard.bmp" "$mui.WelcomePage.Image.Bitmap"
${NSD_SetImage} "$mui.FinishPage.Image" "$PLUGINSDIR\modern-wizard.bmp" "$mui.FinishPage.Image.Bitmap"
and setting image later:
${NSD_CreateBitmap} 0 0 164 436 ""
Pop $9
File "/oname=$pluginsdir\welcomeimg.bmp" "${}\Intro\intro96.bmp"
${NSD_SetImage} $9 "$pluginsdir\welcomeimg.bmp" $1

How does gdb start an assembly compiled program and step one line at a time?

Valgrind says the following on their documentation page
Your program is then run on a synthetic CPU provided by the Valgrind core
However GDB doesn't seem to do that. It seems to launch a separate process which executes independently. There's also no c library from what I can tell. Here's what I did
Compile using clang or gcc gcc -g tiny.s -nostdlib (-g seems to be required)
gdb ./a.out
Write starti
Press s a bunch of times
You'll see it'll print out "Test1\n" without printing test2. You can also kill the process without terminating gdb. GDB will say "Program received signal SIGTERM, Terminated." and won't ever write Test2
How does gdb start the process and have it execute only one line at a time?
.text
.intel_syntax noprefix
.globl _start
.p2align 4, 0x90
.type _start,#function
_start:
lea rsi, [rip + .s1]
mov edi, 1
mov edx, 6
mov eax, 1
syscall
lea rsi, [rip + .s2]
mov edi, 1
mov edx, 6
mov eax, 1
syscall
mov eax, 60
xor edi, edi
syscall
.s1:
.ascii "Test1\n"
.s2:
.ascii "Test2\n"
starti implementation
As usual for a process that wants to start another process, it does a fork/exec, like a shell does. But in the new process, GDB doesn't just make an execve system call right away.
Instead, it calls ptrace(PTRACE_TRACEME) to wait for the parent process to attach to it, so GDB (the parent) is already attached before the child process makes an execve() system call to make this process start executing the specified executable file.
Also note in the execve(2) man page:
If the current program is being ptraced, a SIGTRAP signal is sent
to it after a successful execve().
So that's how the kernel debugging API supports stopping before the first user-space instruction is executed in a newly-execed process. i.e. exactly what starti wants. This doesn't depend on setting a breakpoint; that can't happen until after execve anyway, and with ASLR the correct address isn't even known until after execve picks a base address. (GDB by default disables ASLR, but it still works if you tell it not to disable ASLR.)
This is also what GDB use if you set breakpoints before run, manually, or by using start to set a one-time breakpoint on main. Before the starti command existed, a hack to emulate that functionality was to set an invalid breakpoint before run, so GDB would stop on that error, giving you control at that point.
If you strace -f -o gdb.trace gdb ./foo or something, you'll see some of what GDB does. (Nested tracing apparently doesn't work, so running GDB under strace means GDB's ptrace system call fails, but we can see what it does leading up to that.)
...
231566 execve("/usr/bin/gdb", ["gdb", "./foo"], 0x7ffca2416e18 /* 57 vars */) = 0
# the initial GDB process is PID 231566.
... whole bunch of stuff
231566 write(1, "Starting program: /tmp/foo \n", 28) = 28
231566 personality(0xffffffff) = 0 (PER_LINUX)
231566 personality(PER_LINUX|ADDR_NO_RANDOMIZE) = 0 (PER_LINUX)
231566 personality(0xffffffff) = 0x40000 (PER_LINUX|ADDR_NO_RANDOMIZE)
231566 vfork( <unfinished ...>
# 231584 is the new PID created by vfork that would go on to execve the new PID
231584 openat(AT_FDCWD, "/proc/self/fd", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 13
231584 newfstatat(13, "", {st_mode=S_IFDIR|0500, st_size=0, ...}, AT_EMPTY_PATH) = 0
231584 getdents64(13, 0x558403e20360 /* 16 entries */, 32768) = 384
231584 close(3) = 0
... all these FDs
231584 close(12) = 0
231584 getdents64(13, 0x558403e20360 /* 0 entries */, 32768) = 0
231584 close(13) = 0
231584 getpid() = 231584
231584 getpid() = 231584
231584 setpgid(231584, 231584) = 0
231584 ptrace(PTRACE_TRACEME) = -1 EPERM (Operation not permitted)
231584 write(2, "warning: ", 9) = 9
231584 write(2, "Could not trace the inferior pro"..., 37) = 37
231584 write(2, "\n", 1) = 1
231584 write(2, "warning: ", 9) = 9
231584 write(2, "ptrace", 6) = 6
231584 write(2, ": ", 2) = 2
231584 write(2, "Operation not permitted", 23) = 23
231584 write(2, "\n", 1) = 1
# gotta love unbuffered stderr
231584 exit_group(127) = ?
231566 <... vfork resumed>) = 231584 # in the parent
231584 +++ exited with 127 +++
# then the parent is running again
231566 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=231584, si_uid=1000, si_status=127, si_utime=0, si_stime=0} ---
231566 rt_sigreturn({mask=[]}) = 231584
... then I typed "quit" and hit return
There some earlier clone system calls to create more threads in the main GDB process, but those didn't exit until after the vforked PID that attempted ptrace(PTRACE_TRACEME). They were all just threads since they used clone with CLONE_VM. There was one earlier vfork / execve of /usr/bin/iconv.
Annoyingly, modern Linux has moved to PIDs wider than 16-bit so the numbers get inconveniently large for human minds.
step implementation:
Unlike stepi which would use PTRACE_SINGLESTEP on ISAs that support it (e.g. x86 where the kernel can use the TF trap flag, but interestingly not ARM), step is based on source-level line number <-> address debug info. That's usually pointless for asm, unless you want to step past macro expansions or something.
But for step, GDB will use ptrace(PTRACE_POKETEXT) to write an int3 debug-break opcode over the first byte of an instruction, then ptrace(PTRACE_CONT) to let execution run in the child process until it hits a breakpoint or other signal. (Then put back the original opcode byte when this instruction needs to execute). The place at which it puts that breakpoint is something it finds by looking for the next address of a line-number in the DWARF or STABS debug info (metadata) in the executable. That's why only stepi (aka si) works when you don't have debug info.
Or possibly it would use PTRACE_SINGLESTEP one or two times as an optimization if it saw it was close.
(I normally only use si or ni for debugging asm, not s or n. layout reg is also nice, when GDB doesn't crash. See the bottom of the x86 tag wiki for more GDB asm debugging tips.)
If you meant to ask how the x86 ISA supports debugging, rather than the Linux kernel API which exposes those features via a target-independent API, see the related Q&As:
How is PTRACE_SINGLESTEP implemented?
Why Single Stepping Instruction on X86?
How to tell length of an x86-64 instruction opcode using CPU itself?
Also How does a debugger work? has some Windowsy answers.

Whats wrong with my 2nd call to ReadINIStr?

I am a newbiew to NSIS. Trying to build a little sample that help to understand the techniques that I'd like to use in the production-installer that's build eventually...
I'd like to build a silent-installer that gets its parameter from an .INI-File with multiple section. Want to specific the section the command-line of the installer.
So, I have this NSIS-TEST.INI-File:
[PROD]
PATHONE=c:\Folder\Foo
AppName=My little stupid app
The idea is to have command-line like this:
FooSetup config=prod
The actual setup NSIS-TEST.NSI is:
; Script generated by the HM NIS Edit Script Wizard.
var /global REGAPPKEY
var /global PRODUCT_DIR_REGKEY
; HM NIS Edit Wizard helper defines
!define REG_APPKEY ""
!define config "PROD"
!define PATHONE ""
!define PRODUCT_NAME "foo"
!define PRODUCT_VERSION "1.0"
!define PRODUCT_PUBLISHER "foo"
!define PRODUCT_WEB_SITE "http://www.example.com"
!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
!define PRODUCT_UNINST_ROOT_KEY "HKLM"
Name "${PRODUCT_NAME} ${PRODUCT_VERSION}"
OutFile "FooSetup.exe"
InstallDir "c:\foo-goo"
Icon "${NSISDIR}\Contrib\Graphics\Icons\modern-install.ico"
UninstallIcon "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico"
;SilentInstall silent
;SilentUninstall silent
;InstallDirRegKey HKLM "${PRODUCT_DIR_REGKEY}" ""
Section -aHauptgruppe SEC01
ReadINIStr $REGAPPKEY $INSTDIR\nsis-test.ini ${config} "AppName"
ReadINIStr $PATHONE $INSTDIR\nsis-test.ini ${config} "PATHONE"
;MessageBox MB_ICONINFORMATION|MB_OK "config=${config}"
;SetOutPath "$INSTDIR"
;SetOverwrite ifnewer
; File "..\..\..\pfad\zur\datei\AppMainExe.exe"
; CreateDirectory "$SMPROGRAMS\foo"
; CreateShortCut "$SMPROGRAMS\foo\foo.lnk" "$INSTDIR\AppMainExe.exe"
; CreateShortCut "$DESKTOP\foo.lnk" "$INSTDIR\AppMainExe.exe"
; File "..\..\..\path\to\file\Example.file"
SectionEnd
Section -AdditionalIcons
WriteIniStr "$INSTDIR\${PRODUCT_NAME}.url" "InternetShortcut" "URL" "${PRODUCT_WEB_SITE}"
CreateShortCut "$SMPROGRAMS\foo\Website.lnk" "$INSTDIR\${PRODUCT_NAME}.url"
CreateShortCut "$SMPROGRAMS\foo\Uninstall.lnk" "$INSTDIR\uninst.exe"
SectionEnd
Section -Post
WriteUninstaller "$INSTDIR\uninst.exe"
;WriteRegStr HKLM "${PRODUCT_DIR_REGKEY}" "" "$INSTDIR\AppMainExe.exe"
;WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)"
;WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninst.exe"
;WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\AppMainExe.exe"
;WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}"
;WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}"
;WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
SectionEnd
Function un.onUninstSuccess
MessageBox MB_ICONINFORMATION|MB_OK "$(^Name) wurde erfolgreich deinstalliert."
FunctionEnd
Function un.onInit
MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 "M�chten Sie $(^Name) und alle seinen Komponenten deinstallieren?" IDYES +2
Abort
FunctionEnd
Section Uninstall
Delete "$INSTDIR\${PRODUCT_NAME}.url"
Delete "$INSTDIR\uninst.exe"
Delete "$INSTDIR\Example.file"
Delete "$INSTDIR\AppMainExe.exe"
Delete "$SMPROGRAMS\foo\Uninstall.lnk"
Delete "$SMPROGRAMS\foo\Website.lnk"
Delete "$DESKTOP\foo.lnk"
Delete "$SMPROGRAMS\foo\foo.lnk"
RMDir "$SMPROGRAMS\foo"
RMDir "$INSTDIR"
DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}"
;DeleteRegKey HKLM "${PRODUCT_DIR_REGKEY}"
SetAutoClose true
SectionEnd
FooSetup config=prod
If I compile this, the last lines of the output are:
Section: "-aHauptgruppe" ->(SEC01)
ReadINIStr $REGAPPKEY [PROD]:AppName from $INSTDIR\nsis-test.ini
Usage: ReadINIStr $(user_var: output) ini_file section entry_name
Error in script "c:\blabla\setup2019\nsis-test.nsi" on line 29 -- aborting creation process
So it has processed the first of my ReadINIStr-Instructions and barfed on the second one. I have looked at this code for hours, have injected line-feed etc., but I can't see what's so different about the 2nd instruction...
$PATHONE is not a variable. You're missing:
Var PATHONE
Note you do have:
!define PATHONE ""
So be careful not getting the two confused.

Ways to update progress bar

I want to control progressbar in my nsis installer. Actually I'm using ThreadTimer plugin but I've got big problem with it. ThreadTimer runs function every 10 seconds to update progress bar (increace progress bar value by 1%). The problem is that it crashes stack (as I can see ThreadTimer is using the same stack as NSIS). Crashes stack means that when I want to get value from the stack the value is wrong because of ThreadTimer function action. Any ideas? Maybe there are some other ways to update progress bar?
Those are functions/macros which should update progress bar. Macro StartProgressBarIntervalUpdate starts updating progress bar, macro StopProgressBarIntervalUpdate stops doping it.
Var /GLOBAL ProgressBarPosition
Var /GLOBAL ProgressBarParentWindow
Var /GLOBAL ProgressBarItem
Function InitProgressBar
StrCpy $ProgressBarPosition "0"
FindWindow $ProgressBarParentWindow "#32770" "" $HWNDPARENT
GetDlgItem $ProgressBarItem $ProgressBarParentWindow 1004
FunctionEnd
Function UpdateProgressBarTimer
${If} $ProgressBarPosition >= 30000 ; 100% * 300
StrCpy $ProgressBarPosition "0"
${Endif}
IntOp $ProgressBarPosition $ProgressBarPosition + 300
SendMessage $ProgressBarItem ${PBM_SETPOS} $ProgressBarPosition 0
FunctionEnd
!define StartProgressBarIntervalUpdate "!insertmacro StartProgressBarIntervalUpdate"
!macro StartProgressBarIntervalUpdate
Call InitProgressBar
GetFunctionAddress $UpdateProgressBarTimerFunctionAddress UpdateProgressBarTimer
ThreadTimer::Start /NOUNLOAD 20 -1 $UpdateProgressBarTimerFunctionAddress
Sleep 1000
!macroend
!define StopProgressBarIntervalUpdate "!insertmacro StopProgressBarIntervalUpdate"
!macro StopProgressBarIntervalUpdate
ThreadTimer::Stop $UpdateProgressBarTimerFunctionAddress
Sleep 15000
!macroend
Here are sections which uses progressbar
Var /GLOBAL UpdateProgressBarTimerFunctionAddress
Section BeforeMoveData SEC01
${StartProgressBarIntervalUpdate}
Call core.UnpackExeData
SectionEnd
Section OnMoveData SEC02
Call InstallFiles
Call InstallRegistry
Call InstallShortcuts
${StopProgressBarIntervalUpdate}
...
SectionEnd

How to control progress bar from two different tasks

I have a custom page, and and added a progress bar. Now I have two functions to control that progress bar. One function is to stop few services and other is to back up some files from install location.
Function myCustomPage
Var /GLOBAL progressBar
Var /GLOBAL label
!insertmacro MUI_HEADER_TEXT "Setup is preaparing to install updates" "Please wait"
nsDialogs::Create 1018
${NSD_CreateLabel} 10 15 80% 10% ""
Pop $label
${NSD_CreateProgressBar} 10 30 80% 8% ""
Pop $progressBar
${NSD_CreateTimer} BackUp_Files.Callback 10
${NSD_CreateTimer} Stop_Services.Callback 10
nsDialogs::Show
FunctionEnd
Stop_Services call back function
Function Stop_Services.Callback
${NSD_SetText} $label "Stopping services"
${NSD_KillTimer} Stop_Services.Callback
SendMessage $progressBar ${PBM_SETRANGE32} 0 100
SendMessage $progressBar ${PBM_SETPOS} 25 0
Sleep 100
SendMessage $progressBar ${PBM_SETPOS} 25 0
Sleep 100
SendMessage $progressBar ${PBM_SETPOS} 50 0
Sleep 100
SendMessage $progressBar ${PBM_SETPOS} 75 0
Sleep 100
SendMessage $progressBar ${PBM_SETPOS} 100 0
FuncionEnd
Same kind of structure for Backup_files.callback has.
Result:
When I look at the label its kind of switching between "stopping services" and "backing up files".
Can any one tell me how to handle this. I want to stop the services first then I want to copy the backup files. Progress bar needs to be set to 0 after stopping the services and start again for backing up files. I need to do it on single custom page.
Just use one timer and at the end of the first task call the second task function directly...

Resources