Archive: To start from a specified folder by Browse button in Directory Page


To start from a specified folder by Browse button in Directory Page
Hello,
in the Directory Page, I would start from a specified folder when clicking the Browse button instead to start from the User directory and would also keep the directory structure tree completely so setup user can choose among all disk directories instead from only the tree of the specified folder.

How to make it ? Which is the code ?


Originally posted by Maxim30
in the Directory Page, I would start from a specified folder when clicking the Browse button instead to start from the User directory
bland NSIS, use...

Var myDirVar

Function .onInit
StrCpy $myDirVar "$PROGRAMFILES\NSIS\"
FunctionEnd

PageEx directory
DirVar $myDirVar
PageExEnd


MUI2, use...

myDirVar

Function .onInit
StrCpy $myDirVar "$PROGRAMFILES\NSIS\"
FunctionEnd

!define MUI_DIRECTORYPAGE_VARIABLE $myDirVar
!insertmacro MUI_PAGE_DIRECTORY


nsDialogs (manually calling the code), use...

nsDialogs::SelectFolderDialog "Title" "$PROGRAMFILES\NSIS\"



Originally posted by Maxim30
and would also keep the directory structure tree completely so setup user can choose among all disk directories instead from only the tree of the specified folder.
Not sure what you mean by that - but if you mean 'expand all the folders and subfolders on the user's entire drive'... bad idea ;) Just let the user expand if they desire to install to a specific location.

I mean to show to user the starting folder I preset and from there he/she can choose (expanding or not) any other directory.

The MUI2 version code works as I want.

But additionaly in my script I have the following code:

this first functon to determine whether a previous installation was made and then whether the system is 32 or 64 bit ...

Function MyGUIInit
ReadRegStr $0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${Nome}" "NSIS:InstallDir"
${If} $0 != ""
StrCpy $INSTDIR $0
${ElseIf} ${RunningX64}
StrCpy $INSTDIR "$PROGRAMFILES64\${Nome}"
${Else}
StrCpy $INSTDIR "$PROGRAMFILES32\${Nome}"
${EndIf}
Function End

and this second function to append always the string ${Nome} to the choosen path ...

Function .onVerifyInstDir
${WordAdd} "$INSTDIR" "\" "+${Nome}" $INSTDIR
FunctionEnd

And instead with my two functions above the MUI2 code you proposed does not work, starting the installation folder still always from User directory; if I write only $PROGRAMFILES64 (and $PROGRAMFILES32) instead of $PROGRAMFILES64\${Nome} (and $PROGRAMFILES32\${Nome}) then the code works as I want.

How to fix my code above with yours ?


the reason that doesn't work is because the folder selection dialog can only be pointed to folders that exist. So when you append ${Nome} (let's say its value is 'myDir'), then $PROGRAMFILES\myDir\ must be a folder that exists for the browser to open in that location.

The simplest solution would be to browse to the main folder (in this case, $PROGRAMFILES), and append the ${Nome} at a later point.


Or alternatively I could append the string ${Nome} only when the Directory Page Browse button is clicked.
How can I add/modify actions when the Browse button is clicked ?


I don't think there are specific callbacks for the user pressing the browse button or having selected a folder in MUI2. You could easily set something up using a custom dialog, though.


And do they exist for normal MUI ?


You could have a peek at the .onVerifyInstDir callback - that gets called whenever the user changes the installation directory; should be able to use that with MUI2 as well, come to think of it.


Ok. If I use the instructions FindWindow and GetDlgItem on the Browse button, how can I write the code to have the installer to open the $PROGRAMFILES32 (or $PROGRAMFILES64) folder instead of preset $PROGRAMFILES32\${Nome} (or $PROGRAMFILES64\${Nome}) every time user click on the Browse button ?


You don't use that - you just use the $myDirVar (or $INSTDIR if you're not using the custom dir var ).

For example:


!include "nsDialogs.nsh"
!include "MUI2.nsh"

OutFile "test.exe"

Section
SectionEnd

!define Nome "NSIS"

Var myDirVar
!define MUI_DIRECTORYPAGE_VARIABLE $myDirVar
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE myFunction
!insertmacro MUI_PAGE_DIRECTORY

Function .onInit
; Default install location / install location read from registry
StrCpy $myDirVar "$PROGRAMFILES\"
FunctionEnd

Function myFunction
StrCpy $INSTDIR "$myDirVar\${Nome}"
MessageBox MB_OK "User selected install location: '$myDirVar'$\r$\nActually installing to: '$INSTDIR'"
FunctionEnd

!insertmacro MUI_LANGUAGE "English"

In any case how can I write a code to perform an action after clicking the Browse button in the Directory Page ?



!include "LogicLib.nsh"
!include "nsDialogs.nsh"
!include "MUI2.nsh"

OutFile "test.exe"

Section
SectionEnd

!define Nome "NSIS"

Var myDirVar
!define MUI_DIRECTORYPAGE_VARIABLE $myDirVar
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE myFunction
!insertmacro MUI_PAGE_DIRECTORY

Function .onInit
; Default install location / install location read from registry
StrCpy $myDirVar "$PROGRAMFILES\"
FunctionEnd

Function .onVerifyInstDir
${If} "$myDirVar" == "$DESKTOP"
MessageBox MB_OK "User clicked browse button (or manually entered desktop location"
${EndIf}
FunctionEnd

Function myFunction
StrCpy $INSTDIR "$myDirVar\${Nome}"
MessageBox MB_OK "User selected install location: '$myDirVar'$\r$\nActually installing to: '$INSTDIR'"
FunctionEnd

!insertmacro MUI_LANGUAGE "English"


But that is a hack.. .onVerifyInstDir gets a message for every folder change within the dialog (and the user typing in the main field); it assumes that the first folder opening when the user presses the browse button is the Desktop folder.
If you want better control, you'd want to use nsDialogs to build your own dialog.

But, again, you're not going to be able to manipulate much in the browse dialog.

I have tried this code but it does not work as I want:

!define MUI_PAGE_CUSTOMFUNCTION_SHOW MyDirPage

...

Function MyGUIInit
GetFunctionAddress $3 MyNewFolder ; get address of MyNewFolder function
FunctionEnd

Function MyDirPage
FindWindow $1 "#32770" "" $HWNDPARENT
GetDlgItem $2 $1 1001 ; Get Browse button Dialog Item
nsDialogs::OnClick $2 $3 ; checks clicks on Browse button and calls MyNewFolder function
FunctionEnd

Function MyNewFolder
; appropriate instructions here
MessageBox MB_OK "Browse button clicked" ; test by now
FunctionEnd

Function .onVerifyInstDir
${WordAdd} "$INSTDIR" "\" "+${Nome}" $INSTDIR ; appends string ${Nome} to the choosen path by Browse button
FunctionEnd

The GetDlgItem instruction works because I tested it with the instruction "EnableWindow $2 0" (disable Browse button). But the function MyNewFolder seems to not work because the MessageBox test is never shown:
are the variables $2, $3 and the instructions GetFunctionAddress, nsDialogs::OnClick correct ?


I don't think you can use nsDialogs' event handlers on existing buttons.

I'm also somewhat confused by what you're actually trying to do.

You want the Browse dialog to open in a specific location, in this case $PROGRAMFILES. Then when the user has selected a folder, you want to append ${Nome}. Is that correct? If so - then the example two posts back should be all that you need.

If you also want to -show- the user that you appended ${Nome}, then you'd have to check if the text on the directory input field has changed, append ${Nome} if it's not already appended, etc. etc.
( all of which is a lot easier with a custom dialog )


Yes, I want to append the string ${Nome} at end of the path choosen by user, and I have realized it.
Furtherly when user clicks on Browse button I want to show to him/her the $PROGRAMFILES32 or $PROGRAMFILES64 folder (and then its subfolders branch too) instead to show to him/her the default User folder, but I have not realized it: how to make it ?


As far as I can see (at least on Windows 7) the Browse dialog never opens to the currently chosen install directory. Is this not the case on XP? I suggest you post a feature request or add the feature yourself.

Stu


Really clicking on the Browse button the current install folder is opened (with its subfolders branch) if it is existing, and this is I want.
Instead if it is not existing then the User folder is opened (default), and this is not I want; I am seaching to open at least the $programfiles32 or $programfiles64 folders in this case, and perhaps it is possible using the nsDislogs::OnClick instruction: is it ?


you're pretty much going to have to edit/make some code to do what you're wanting - it's relatively simple as the callback function to the SHBrowseForFolder just needs to be adjusted to change to a different folder path if the first isn't valid though i've no idea where in NSIS that is being done (which probably doesn't help) but it's a trivial thing to do in response to the BFFM_INITIALIZED message in the OS api's callback function.

-daz


Or you can just change the folder passed to the browse dialog when the folder doesn't exist - you can check all of this with NSIS -before- you open the dialog.
( This works fine in Windows 7 as well )
Expanding that folder or the nodes in the tree below that folder, however, is another matter entirely; in theory it can be done, but you'd probably have to change the code (unless a tricky nsDialogs timer could send the command to expand the currently selected item in the tree).


!include "LogicLib.nsh"
!include "nsDialogs.nsh"
!include "MUI2.nsh"

OutFile "test.exe"

Section
SectionEnd

Var myDirVar
!define MUI_DIRECTORYPAGE_VARIABLE $myDirVar
!insertmacro MUI_PAGE_DIRECTORY

Function .onInit
${If} ${FileExists} "$PROGRAMFILES\SomeFolder\*.*"
StrCpy $myDirVar "$PROGRAMFILES\SomeFolder\"
${Else}
StrCpy $myDirVar "$PROGRAMFILES\"
${EndIf}
FunctionEnd

!insertmacro MUI_LANGUAGE "English"

or that approach :) (had thought it had already been tried though i did only skim through to the end of the thread).

-daz


I reexplain the situation:

at setup start I have as shown in attached screenshot 1: what I have and also wanted.

After clicking on the Browse button I would as shown in attached screenshot 2: what wanted.

After clicking on Browse button I have instead as shown in attached screenshot 3: what I get now instead and to avoid.


Yeh we get it. Did you try Animaether's code?

Stu


Originally posted by Afrow UK
Yeh we get it. Did you try Animaether's code?

Stu
No. Which of the last three should I try ?

Try the last one he posted:
http://forums.winamp.com/showpost.ph...0&postcount=19

Stu


The statement
${If} ${FileExists} "$PROGRAMFILES\SomeFolder\*.*"
is always false because my prompted folder is new non existent so there is not a special in the code, it does nothing.


Did you try it or not? There's an ELSE statement in the code in case you didn't see it.

Edit: I have tried it and it works.

Stu


However, it is the same as just using InstallDir $PROGRAMFILES. This is what I said initially: whatever is in the directory box AND IT EXISTS will cause the Browse dialog to open to it. If the path does not exist then Browse will go to the default (root/user). So the only thing you can do is set InstallDir $PROGRAMFILES and then perhaps add:

Function .onVerifyInstDir
StrCpy $INSTDIR `$INSTDIR\${Name}`
FunctionEnd

This will ensure your app name is appended to the end (use if you need that to happen). Notice that when you click Browse again you are back to root!

I think if you want to do this properly you need to change NSIS itself or post a feature request - i.e. get Browse to open in the parent folder of the current install directory if that exists, or go to the parent of that if it exists etc

Stu

Originally posted by Afrow UK
However, it is the same as just using InstallDir $PROGRAMFILES. This is what I said initially: whatever is in the directory box AND IT EXISTS will cause the Browse dialog to open to it. If the path does not exist then Browse will go to the default (root/user). So the only thing you can do is set InstallDir $PROGRAMFILES and then perhaps add:
Function .onVerifyInstDir
StrCpy $INSTDIR `$INSTDIR\${Name}`
FunctionEnd

This will ensure your app name is appended to the end (use if you need that to happen). Notice that when you click Browse again you are back to root!

I think if you want to do this properly you need to change NSIS itself or post a feature request - i.e. get Browse to open in the parent folder of the current install directory if that exists, or go to the parent of that if it exists etc

Stu
Yes, I think it is better to post a feature request to make Browse to open in the parent folder of the current install directory if the last path portion is not existent.

http://nsis.sourceforge.net/Requests

Stu



!include "LogicLib.nsh"
!include "nsDialogs.nsh"
!include "MUI2.nsh"
!include "FileFunc.nsh"

OutFile "test.exe"

Section
SectionEnd

Var myDirVar

!define MUI_DIRECTORYPAGE_VARIABLE $myDirVar
!insertmacro MUI_PAGE_DIRECTORY

Function .onInit
StrCpy $myDirVar "$PROGRAMFILES\NSIS\ExampleZ\"

${GetRoot} "$myDirVar" $0
${DoUntil} ${FileExists} "$myDirVar"
${GetParent} "$myDirVar" $myDirVar
${Loop}
${If} "$myDirVar" == "$0"
/* Installation would end up in ROOT. Switching to default instead. */
StrCpy $myDirVar "$PROGRAMFILES"
${EndIf}
StrCpy $myDirVar "$myDirVar\"
FunctionEnd

!insertmacro MUI_LANGUAGE "English"

Animaether, the point is this needs to be done when you Browse. As soon as you enter a non existent path on the directory page the browse dialog always starts at the root.

Edit:
i.e. if you have $PROGRAMFILES\MyApp as InstallDir or upon directory selection or manual entry Browse should open initially to $PROGRAMFILES if MyApp does not exist.

Stu


The only case in which things wouldn't work as desired is when the user enters a non-existing path on the directory page itself; the directory browser doesn't let you pick non-existing paths.

So, again, it'd be a lot easier to handle with a custom page - as in that case the directory browser doesn't grab the data from the entry field as authoritative and you can manipulate the path for the directory browser before opening it.

I'm not saying that the feature request isn't valid - just suggesting ways in which one can do the desired with the tools already at one's disposal.