Skip to content
⌘ NSIS Forum Archive

Updating progressbar via external process

8 posts

dimator#

Updating progressbar via external process

Hi,
I'm curious about the best way to do this:

I need to update a progressbar based on the progress of an external executable, which handles the actual install work.

I'm using the progressbar in InstallOptionsEx. I know that in my PageUpdate function, I can have a loop that "polls" the external process (via nsexec), and updates the progressbar. However, such a loop would block other UI activity, so for example, the user would not be able to click cancel or stop the installer, until it either failed or succeeded completely.

Is there a non-blocking type of "sleep" function maybe, that will callback a function I specify after N msecs? I think something like that would solve my problem, but maybe there is a better way of doing what I'm trying to do?

Thanks
kichik#
If the external process is under your control, it'd be simpler to it change the progress bar itself. If not, you can set a timer using the System plug-in and use System callbacks. There is one example in the System plug-in documentation for callbacks and one in the examples.
dimator#
I've tried gleaming what I need to know out of the System plug-in examples, but no dice. I am trying:


System::Call "${sysSetTimer} (r2, 1, r8,)"
!insertmacro SINGLE_CALLBACK 20 $5 1 MyCallBack
Where r2 is $HWNDPARENT and r8 is the delay in msecs. MyCallBack is never called. Am I doing this the right way?

The plug-in example (System.nsi) has all kinds of other System::Call's, but they all seem to deal with creating the splash window, which I don't need.
kichik#
You have to call something with System::Call and have it return its value on the stack to use SINGLE_CALLBACK. Calling Sleep would probably be the simplest.
T.Slappy#
Hi
I have the same problem: I need to create Timer in regular page (in MUI2 in PRE or SHOW), no with nsDialogs!
Syntax is quite simple:
System::Call "User32::SetTimer(i, i, i, k) i 
(HWND hWnd, UINT_PTR nIDEvent, UINT uElapse, TIMERPROC lpTimerFunc) UINT_PTR" 
I have only problem with that k parameter - TIMERPROC

All I need is to execute my function every uElapse miliseconds:
Function TimerTick
MessageBox MB_OK "Timer tick!"
FunctionEnd 
I tried GetFunctionAddress $0 TimerTick for that k parameter but no success.

Maybe I must use callback as mentioned in System plugin readme http://nsis.sourceforge.net/System_p...adme#Callbacks.
System::Get "(i .r0, i .r1) isR0"
Pop $0
System::Call "dll::UseCallback(k r0)" 
but I am confused from that example.
I also saw included system examle, but it is even more complicated.
Can you explain me how ho call Function TimerTick with that callback?
stass#
Until now there is no answer - how to make Сallback function SetTimer ?
Please tell me an example...
LoRd_MuldeR#
Originally Posted by stass View Post
Until now there is no answer - how to make Сallback function SetTimer ?
Please tell me an example...
I don't think you can do this directly from NSIS, only with System plug-in. That's because SetTimer requires a pointer to a native (e.g. compiled C/C++ code) function that implements the TIMERPROC prototype. You cannot make SetTimer call an NSIS function directly, because that is something completely different! Passing the address of an NSIS function to SetTimer - as if it was the address of a TIMERPROC function - will only cause "undefined" behavior, including installer crash. But what you can do is: Implement your own proper TIMERPROC function (which can be used by SetTimer) and then call the desired NSIS function from there, via ExecuteCodeSegment().

Coincidently, I have created a plug-in which does exactly this, just a day ago 😉
* https://github.com/lordmulder/stduti...Utils.cpp#L104
* http://forums.winamp.com/showpost.ph...2&postcount=12

But be aware that SetTimer requires that the thread, which has called SetTimer (or which has called the plug-in that called SetTimer), is running a message loop. Otherwise the WM_TIMER messages are never going to be processed and thus the timer never actually fires! So you have to create the timer in the NSIS "main" thread, e.g. from within .onGuiInit function, as in the example I included.
T.Slappy#
I forgot to update this thread, sorry 🙂

I solved this problem by writing simple plug-in (can be found here: http://nsis.sourceforge.net/ThreadTimer_plug-in ) which does almost exactly what I needed.

Later my plug-in was updated (fixed and improved) and few days ago LoRd_MuldeR wrote new plug-in with a little different idea [please paste wiki link here].

I need to run some tests but I think all old plug-ins can be replaced by this new plug-in as in old plug-ins there may be troubles in certain situations like cross-thread GUI updating.

For other users I add link where these issues are being solved: http://forums.winamp.com/showthread.php?t=381361