Archive: Custom Install Options Page based off directory contents...


Custom Install Options Page based off directory contents...
I'm trying to create a custom Install Options page that has 2 fields, one being a label and one being a listbox. The only thing is, I'd like the list box to be filled with contents of a directory. I read the instructions (and searched, btw ;)) on how to add stuff to the ini file, but how would I get the directory contents through NSIS?

Alternatively, I created a vbscript that creates the ini file completely (with directory contents loaded into it), but I don't know if/how I could execute this vbscript to create the ini file...and would NSIS even like that because the INI file wouldn't be packaged with it, but it would be referenced...

Here is the INI file...the listItems line is the one I am creating at run time:

[Settings]
NumFields=2
NextButtonText=Next

[Field 1]
Type=label
Text=Choose the database to repair from the list:
Left=0
Right=-1
Top=0
Bottom=10

[Field 2]
Type=DropList
ListItems=1775|1776|1777|
Left=0
Right=-100
Top=10
Bottom=100

Use FindFirst, FindNext and FindClose.

You can find an example here:
http://nsis.sourceforge.net/archive/....php?pageid=58

To write to INI files just use WriteINIStr.


is there a quick tutorial somewhere on what Push and Pop do? I tried to figure them out before (because I use the GetParent function) but never really got the hang of it..


Push and Pop "push" and "pop" values onto and off a stack of values. Imagine a stack of plates, you add a plate to the top of the stack by pushing it on, and you remove the top plate on the stack by "pop"ing it off. So, push and pop just give you somewhere to store values. If you push 5 then 4 then 8 when you do three pops you will get the values back in reverse order (think about the plates analogy and you'll see why) i.e. 8, 4 then 5.

Example Code:-

Push 5
Push 4
Push 8
Pop $0
Pop $1
Pop $2

You would now have the value 8 in the variable $0, the value 4 in the variable $1 and the value 5 in variable $2. You can push anything, e.g.
Push "My string"
Push $1
Push $R3


Note: There is only one stack for the entire time your installer runs, so if you Push 5 at the very start it will still be there at the end if you haven't Pop'd it off the stack. It doesn't matter if you enter a function or a section or whatever, you'll still be manipulating the same stack as any other place or time in the script.

ok, to take the GetParent analogy...first I do

Push $INSTDIR
Call GetParent
Pop $0

Push $INSTDIR puts the INSTDIR on the top of the stack, then, when in the GetParent function I say:

Exch $0

I'm really "calling" the top item on the stack, whatever that may be...effectively returning my install directory to $0. But then the next 2 lines read:

Push $1
Push $2

$1 and $2 are empty at this point, so what gets put on the stack? Their empty variables? which are filled later?


In your example Exch $0 swaps the top item on the stack with whatever value $0 contained. The value that was on the stack top before is now stored in $0, and the value that was in $0 is now the top value on the stack.

If $1 and $2 are empty before the Pushes then empty values will be pushed onto the top of the stack. Pushing *never* changes the value pushed so why would you expect $0 or $1 to be different at some later time?

If instead you said

StrCpy $0 "My example string"
Push $0
Then you might be pushing something useful onto the stack rather than an empty value.

Another note, the Exch $0 (a) gets you the value pushed onto the stack by GetParent and stores it in $0 (b) saves whatever value you had in $0 before calling Exch onto the top of the stack. If you didn't care about the value in $0 before calling Exch you could use Pop $0 instead of Exch $0.


ok...I actually was just reading the documentation on "Exch", but I understand your analogy better.

I took the "Push $1" and $2 lines from the GetParent, but I think I see how that is working. Now relating that to my issue, I need to create a line in the INI file with a string of all the file names in that directory (preferably all the .mdb file names, but that can come later). Using the function Kichik pointed to above, it appears I would have to fill a variable with a running list of my files. In vb I would do this via fileStr = fileStr + "|" + newFile. Then, in the end write the INI file using fileStr as my string to write. Is this how I should be going about doing this? And how would I do it in NSIS?


Push $1 and Push $2 are there so when a user calls this function it won't ruin his variables. Unless you are going to create a function out of this code you don't need it.

Yes, you should create the line and then write it. To append text to an existing variable use:

StrCpy$0"$0|moretext..."

This will copy "$0|more text..." into $0 and therefore appending "more text..." to $0.

Yup InstallOptions requires you to use | to separate the list items. You want something like (untested) :-


FindFirst $0 $1 "c:\path\to\my\files\*.mdb"
StrCpy $9 ""
StrCmp $0 "" error
again:
StrCmp $1 "" done
StrCmp $9 "" 0 append
StrCpy $9 $1
Goto readnext
append:
StrCpy $9 "$9|$1"
readnext:
FindNext $0 $1
Goto again
done:
FindClose $0
; now write to the ini file
WriteIniStr "filename.ini" "section_name" "ListItems" $9
goto finished
error:
; hmmm
finished:

Ok, I have a better grasp of what's going on, but I can't figure this out. I have either of 2 functions right now, neither work (one is yours, Sunjammer, the other is the one Kichik linked to).


Function GetFiles
Exch $1 ; Dir
Push $2
Push $3
FindFirst $2 $3 "$1\*.*"
StrCmp $3 "" exitloop
loop:
StrCmp $3 "" exitloop
StrCmp $3 "." next
StrCmp $3 ".." next
IfFileExists "$1\$3\*.*" next
; Append each file to the eventual listitem variable
StrCpy $4 "$4|$1\$3"
next:
FindNext $2 $3
Goto loop
exitloop:
FindClose $2
WriteINIStr "ioA.ini" "[Field 2]" "ListItems" $4
Pop $3
Pop $2
Pop $1
FunctionEnd

Function GetFiles2
FindFirst $0 $1 "C:\Payroll\client\*.mdb"
StrCpy $9 ""
StrCmp $0 "" error
again:
StrCmp $1 "" done
StrCmp $9 "" 0 append
StrCpy $9 $1
Goto readnext
append:
StrCpy $9 "$9|$1"
readnext:
FindNext $0 $1
Goto again
done:
FindClose $0
; now write to the ini file
WriteINIStr "ioA.ini" "[Field 2]" "ListItems" $9
goto finished
error:
; hmmm
finished:
FunctionEnd


With the GetFiles one, this is my section


Section "Add Files to Drop Down List"
Push $INSTDIR
Call GetFiles
Sectionend

by the way, I thank you guys so much for all your help so far...you've been amazing (as always :))


I replace the WriteINIStr with DetailPrint $9 and both gave the right output. You probably didn't give the right path to the INI file. If it's in $PLUGINSDIR use the IO macro or just write $PLUGINSDIR\ioA.ini, if not append the right path.


ok, well, Its just getting extracted to wherever they get extracted to by default. I tried the DetailPrint and did also see that it was working right, but its still not getting into the ini file...

checking it now...this is my extract statement, btw...if it matters.

;Extract InstallOptions INI Files
!insertmacro MUI_INSTALLOPTIONS_EXTRACT "ioA.ini"


If you are using this macro then it goes into $PLUGINSDIR. Use its friend MUI_INSTALLOPTIONS_WRITE :)


ok, I am...trying that now...I found the ini file with the installoptions.dll file in a subfolder in my temp dir.


Yep, that's where $PLUGINSDIR hides.


that didn't seem to work, either. The NSI file is available here if you want to see that

http://webpages.charter.net/dick4/files/JetComp.nsi


This line is wrong:
!insertmacro MUI_INSTALLOPTIONS_WRITE "$PLUGINSDIR\ioA.ini" "[Field 2]" "ListItems" $9

It's either the macro or $PLUGINSDIR, not both. The macro adds $PLUGINSDIR_by itself.


Wow you mean to say that my cobbled together thoughts actually amounted to something usable? I'm amazed :P


I tried that, its still not doing it right...tried it both ways


Ah, there is anoter mistake in that line. The section name isn't "[Field 2]", it's "Field 2". The brackets mark the line being a section opening line. So it should be:
!insertmacro MUI_INSTALLOPTIONS_WRITE "ioA.ini" "Field 2" "ListItems" $9


You're right...but its still not working...crap!


Does it show $9 in the details window? Can you attach the latest script too please?


Also check what is written to the INI file in the plugins dir.


http://webpages.charter.net/dick4/files/JetComp.nsi

INI file, too...if needed: http://webpages.charter.net/dick4/files/ioA.ini

I updated with the latest script and yes, it is showing correctly in the details

*edit* the ListItems line in INI file in the plugins directory is just like the original...no change has been made to it.


Ah... You are calling the function after the page was shown. Call it before MUI_INSTALLOPTIONS_DISPLAY in the SetCustomA function.


Ok, that did it...now my only problem is that this path can change...it should be a path read from the registry...but with my current code:


Function SetCustomA
Call GetFiles2
!insertmacro MUI_HEADER_TEXT "$(TEXT_IO_TITLE)" "$(TEXT_IO_SUBTITLE)"
!insertmacro MUI_INSTALLOPTIONS_DISPLAY "ioA.ini"
FunctionEnd


I'm figuring it out before I get to that part of my code. Is there any way to do what I want? I want to figure that drop down list AFTER I've figured out my $INSTDIR (and actually, after that because i need to get the parent dir of the $INSTDIR)

Make this page show after the user has selected the installation directory. Then all you'll need to do is get the parent in this function and you're set.


But I don't have a directory choosing page...do I need one to do this? I've been trying to do it all in one section and it doesn't appear to be working...


As sections are called after those pages are shown you can't set settings for the custom page in them. If you don't have a directory selection page then $INSTDIR is set right of the begning of the installer you should have no trouble using it in SetCustomA. If you need to work on $INSTDIR before the page shows do it in .onInit.


that worked, btw...thanks a ton!

I thought .onInit happened before anything else...is it listed somewhere the order in which everything happens?


The exact order is not listed anywhere, but in every callback function docs it's mentioned when it's exectued, sections are executed in the instfiles page, and non-callback functions when called.