Archive: Default directory


Default directory
Hi!

For few weeks i'm working with NSIS and now i'm stuck in a problem. I want do that in my MUI Directory Page, the name of the directory not to be able to be changed (browse, edit). Also i want to do this only if a condition is satisfied.

The code that i have now is looking like this:

!define MUI_PAGE_CUSTOMFUNCTION_PRE GetDir
!insertmacro MUI_PAGE_DIRECTORY
InstallDir "$PROGRAMFILES\blabla1"

Function GetDir
ReadRegStr $1 HKEY_LOCAL_MACHINE "SOFTWARE\blabla" "DataPath"
StrCmp $1 "" NoDir DirOK
NoDir:
;here i want to show directory page with edit option
DirOk:
StrCpy $INSTDIR $1
;here whitout, only readonly directory name
FunctionEnd


Use the following in the show callback function of the page:

FindWindow $0 "#32770" "" $HWNDPARENT
GetDlgItem $1 $0 <insert control id here>
EnableWindow $1 <0 to disable or 1 to enable>

To find out the control id, open Contrib\UIs\modern.exe, if using the MUI, or Contrib\UIs\default.exe, if not, using Resource Hacker and look at dialog number 103.


Thanks a lot!!!!
It works!!!


hi used this the control ids are 1001 and 1019

but i cant get it working ..can u give me a sample code

sunil


Attach an example code that doesn't work and someone will surely be able to help you fix it.


Sorry to bump this thread, but I have the same problem with the page, MUI_PAGE_STARTMENU. The MUI_PAGE_DIRECTORY page works okay with your suggestions above, but there is no show function for the callback in the MUI_PAGE_STARTMENU page because it is a custom page and not built-in like a directory page. Maybe there is a workaround without being too complicated?


!define MUI_PAGE_CUSTOMFUNCTION_SHOW MyStartShow
!insertmacro MUI_PAGE_STARTMENU
Function MyStartShow
; WARNING: this functions never runs ...
${If} $2 == "1" ; readonly
FindWindow $0 "#32770" "" $HWNDPARENT ; dialog number 103
GetDlgItem $1 $0 1019 ; control id for textbox
EnableWindow $1 0 ; 0 disable, 1 enable
GetDlgItem $1 $0 1001 ; control id for button
EnableWindow $1 0 ; 0 disable, 1 enable
${EndIf}
FunctionEnd


Of course the control id may be different since it is a custom page and resource hacker does not show the information for custom pages? The 'system.nsf' also gives no indication what it might be?

I made the code bellow in order to build a kind of patch, I hope could help. Checking the registry if my software is installed and if so the installer jumps to the install files page.

code:
!define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\MySoft.exe"
.
.
.
; Welcome page -----------
!define MUI_PAGE_CUSTOMFUNCTION_PRE WelcomePre
!insertmacro MUI_PAGE_WELCOME

; Directory page ---------
!define MUI_PAGE_CUSTOMFUNCTION_PRE DirectoryPre
!insertmacro MUI_PAGE_DIRECTORY
.
.
.
.
Function WelcomePre
ReadRegStr "$R0" HKLM "${PRODUCT_DIR_REGKEY}" ""
StrCpy "$R1" "$R0" -13
StrCmp $R1 "" _ShowWelcomePage
IfFileExists "$R1\*.*" _skip _ShowWelcomePage
_skip:
Abort
_ShowWelcomePage:
FunctionEnd

Function DirectoryPre
ReadRegStr "$R0" HKLM "${PRODUCT_DIR_REGKEY}" ""
StrCpy "$R1" "$R0" -13
StrCmp $R1 "" _ShowDirectoryPage
IfFileExists "$R1\*.*" _skip _ShowDirectoryPage
_skip:
StrCpy "$INSTDIR" "$R1"
Abort
_ShowDirectoryPage:
FunctionEnd


Thus, this function is to skip start menu if needed:

Function StartMenuPre
ReadRegStr "$R0" ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "${PRODUCT_STARTMENU_REGVAL}"
StrCmp $R0 "" _ShowSMpage
IfFileExists "$SMPROGRAMS\$R0\*.*" _skip _ShowSMpage
_skip:
StrCpy "$ICONS_GROUP" "$R0"
Abort
_ShowSMpage:
FunctionEnd


Thanks, but not skip the startmenu page with abort. Two problems: 1. see the data for the shortcut, just like the directory page, even though it is readonly. 2. see the 'Install' button, but skipping the page does not show it and confuses people who click 'Next' in the directory page.


The startmenu plugin shows the dialog id 1033 is used in startmenu.dll. The window class is what ? So the next step is to somehow disable control id, 1002, 1004, 1005, when the window is shown.

As a workaround, maybe use the resource hacker to edit the startmenu.dll and disable controls manually. Somehow the installer can switch between the two different dlls as needed. Who knows.


Good news. I found a solution to modify the 'system.nsh' file so that the startmenu page (StartMenu plugin) responds to the constant MUI_PAGE_CUSTOMFUNCTION_SHOW. No special custom pages are needed nor fancy custom routines. The only drawback is that the MUI_PAGE_CUSTOMFUNCTION_PRE has to be executed.

I can not guarentee that it works exactly the same as the 'show' feature in the directory and other built-in pages, but it is close. For backward compatibility, the original code is executed when the constant is not defined. It does not matter if the MUI_PAGE_CUSTOMFUNCTION_PRE is defined or not.

In the 'System.nsh' file, replace each of four 'StartMenu::' with a condition to use 'show' or 'select' as in the example below. The parameters can be copied from 'select' to 'show', but are different for each 'Startmenu'. The long startmenu command was broken into separate lines for this forum only, and does not have to be.


!macro MUI_PAGE_STARTMENUCUSTOM ID VAR
; ... leave all code as is
!macroend

!macro MUI_FUNCTION_STARTMENUPAGE PRE LEAVE
Function "${PRE}"

; ... leave most of code as is

;StartMenu::Select ... is replaced by the following code

!ifndef MUI_PAGE_CUSTOMFUNCTION_SHOW
; this is the original code, no custom code
StartMenu::Select /noicon /autoadd /text \
"${MUI_STARTMENUPAGE_TEXT_TOP}" \
/lastused "${MUI_STARTMENUPAGE_VARIABLE}" \
"${MUI_STARTMENUPAGE_DEFAULTFOLDER}"

!Else
; custom code, same parameters
StartMenu::Init /NOUNLOAD /noicon /autoadd /text \
"${MUI_STARTMENUPAGE_TEXT_TOP}" \
/lastused "${MUI_STARTMENUPAGE_VARIABLE}" \
"${MUI_STARTMENUPAGE_DEFAULTFOLDER}"
Call MUI_PAGE_FUNCTION_CUSTOMinsertmacro
;!undef MUI_PAGE_CUSTOMFUNCTION_SHOW ; already done
StartMenu::Show

!EndIf

; ... leave rest of code as is

FunctionEnd

Function MUI_PAGE_FUNCTION_CUSTOMinsertmacro
; function to insert macro only once or else ignored
!insertmacro MUI_PAGE_FUNCTION_CUSTOM SHOW
FunctionEnd

Function "${SHOW}"
; not applicable for custom page callbacks
FunctionEnd

Function "${LEAVE}"
!insertmacro MUI_PAGE_FUNCTION_CUSTOM LEAVE
FunctionEnd
!macroend
My installer script is changed to use the new feature. I have to define the MUI_PAGE_CUSTOMFUNCTION_PRE too since it contains the code to check MUI_PAGE_CUSTOMFUNCTION_SHOW. Comment out the MUI_PAGE_CUSTOMFUNCTION_SHOW to ignore the custom code. Comment out the MUI_PAGE_CUSTOMFUNCTION_PRE to ignore all code.

Var MyStartMenuReadonly

!define MUI_PAGE_CUSTOMFUNCTION_PRE SelectPageShortcut
!define MUI_PAGE_CUSTOMFUNCTION_SHOW ShowPageShortcut
!insertmacro MUI_PAGE_STARTMENU "StartMenuPageID" "TestFolder"

Function .onInit
; Use one of the following lines for the page
StrCpy $MyStartMenuReadonly "" ; false, access everything
;StrCpy $MyStartMenuReadonly "1" ; true, readonly
FunctionEnd

Function SelectPageShortcut
FunctionEnd

Function ShowPageShortcut
Push $0
Push $1

; readonly options
${If} $MyStartMenuReadonly != ""
FindWindow $0 "#32770" "" $HWNDPARENT ; dialog number ?
GetDlgItem $1 $0 1002 ; control id for editbox
EnableWindow $1 0 ; 0 disable, 1 enable
GetDlgItem $1 $0 1004 ; control id for listbox
EnableWindow $1 0 ; 0 disable, 1 enable
${EndIf}

Pop $1
Pop $0
FunctionEnd
Since I do not like to change the 'system.nsh' because I might loose it after reinstalling NSIS, then copy/paste/change the code into a new file and '!include' it in your program. Add the suffix, 'CUSTOM', to represent the new names. The code to copy is,

!macro MUI_PAGE_STARTMENUCUSTOM ID VAR
;!macro MUI_PAGE_STARTMENU ID VAR ; old name
!insertmacro MUI_FUNCTION_STARTMENUPAGECUSTOM \
${MUI_PAGE_UNINSTALLER_FUNCPREFIX}mui.StartmenuPre_${MUI_UNIQUEID} \
${MUI_PAGE_UNINSTALLER_FUNCPREFIX}mui.StartmenuLeave_${MUI_UNIQUEID}
;!insertmacro MUI_FUNCTION_STARTMENUPAGE ; old name
; ... everything else copied with no other changes
!macroend

!macro MUI_FUNCTION_STARTMENUPAGECUSTOM PRE LEAVE
;!macro MUI_FUNCTION_STARTMENUPAGE PRE LEAVE ; old name
; ... everything else copied with no other changes
!macroend
The installer script refers to the new names with,

!include "MyNewSystem.nsh"
!insertmacro MUI_PAGE_STARTMENUCUSTOM "StartMenuPageID" "TestFolder"
;!insertmacro MUI_PAGE_STARTMENU "StartMenuPageID" "TestFolder" ; old name

I had to fix the code above by adding the function 'MUI_PAGE_FUNCTION_CUSTOMinsertmacro' to only insert one macro, '!insertmacro MUI_PAGE_FUNCTION_CUSTOM SHOW'. It can not be inserted four times, otherwise, the last three inserted macros are ignored.


Correction, change code above:
!insertmacro MUI_PAGE_STARTMENU "StartMenuPageID" "TestFolder"

to,
Var StartMenuFolder
!insertmacro MUI_PAGE_STARTMENU "StartMenuPageID" $StartMenuFolder


In case anyone has default folder screwed by the startmenu page, then always disable the listbox and always use GetWindowText. Otherwise, the leave function might not see the variable nor the MUI_STARTMENU_GETFOLDER because it is not updated yet with the input seen in the window. Otherwise, selecting a folder in the listbox adds to the name, but adds to it again if returning to edit after using 'Back/Next' from other pages.


!include "FileFunc.nsh" ; for ...
!insertmacro GetFileName ; from FileFunc.nsh
!insertmacro GetRoot ; from FileFunc.nsh
Var StartMenuFolder
Function .onInit
StrCpy StartMenuFolder "foldername\subfoldername"
FunctionEnd

!define MUI_STARTMENUPAGE_TEXT_TOP "Enter the name of an existing \
or new folder in which you would like to create the program's \
shortcuts."
!define MUI_STARTMENUPAGE_DEFAULTFOLDER $StartMenuFolder
!define MUI_PAGE_CUSTOMFUNCTION_PRE SelectPageShortcut
!define MUI_PAGE_CUSTOMFUNCTION_SHOW ShowPageShortcut
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE ValidatePageShortcut
!insertmacro MUI_PAGE_STARTMENU "StartMenuPageID" $StartMenuFolder

Function ShowPageShortcut
Push $0
Push $1

FindWindow $0 "#32770" "" $HWNDPARENT ; dialog number ?
GetDlgItem $1 $0 1004 ; control id for listbox
EnableWindow $1 0 ; 0 disable, 1 enable

; (see code above in this thread on how to enable this function)

Pop $1
Pop $0
FunctionEnd

Function ValidatePageShortcut
Push $R0
Push $0
Push $1

; Check results
FindWindow $0 "#32770" "" $HWNDPARENT ; dialog number ?
GetDlgItem $1 $0 1002 ; control id for editbox
System::Call 'user32::GetWindowText(i $1, t .R0, i 256)'
StrCpy $StartMenuFolder $R0 ; overwrite to ignore page problems

${GetRoot} "$StartMenuFolder" $1
${If} "$1" != "" ; name can not have drive/network info
MessageBox MB_OK "WARNING: The name can not have information \
about drives, networks, symbols, etc." IDOK
Abort ; only cancels page, not program
${EndIf}

; (optional)
;${GetFileName} "$StartMenuFolder" $StartMenuFolder ; strip folders
;${If} "$StartMenuFolder" != "$R0" ; name can not have extra info
; MessageBox MB_OK "WARNING: The name can not have information \
; about paths, symbols, etc." IDOK
; Abort ; only cancels page, not program
;${EndIf}

${If} "$StartMenuFolder" == "" ; can not be empty
MessageBox MB_OK "WARNING: The name can not be blank." IDOK
Abort ; only cancels page, not program
${EndIf}

Pop $1
Pop $0
Pop $R0
FunctionEnd