I need some help with SHBrowseForFolder API call in NSIS. I need 2 things to implement:
1.) browse for folders in selected root folder (so other folders outside of defined root folder are not dislpayed at all)
2.) preselect an existing folder.
My problem is that root folder must be served as pointer to PIDL, but ParseDisplayName API call always fails for me. The second problem, that the preselected folder parameter is ignored.
The code:
Function BrowseFolderByRoot
;Input1: A handle to the owner window for the dialog box on top of the stacks.
;Input2: The location of the root folder from which to start browsing
; as 2nd element of stacks. Only the specified folder and its
; subfolders in the namespace hierarchy appear in the dialog box.
; This member can be NULL; in that case, a default location is used.
;Input3: Initially selected folder as 3rd element of stacks
;Input4: Text above the tree view control in the dialog box as 4th element of stacks.
;Output: Selected path on top of the stacks.
;
Exch $0
Exch
Exch $1
Exch 2
Exch $2
Exch 1
Exch 3
Exch $3
Push $4
Push $5
Push $6
Push $7
Push $8
Push $9
IntOp $4 $1 + 0
StrCpy $7 "$2"
!define MAX_PATH 260 ;Windows shell is limited to 260 characters(with null terminating char.)
System::Call /NoUnload "ole32::CoInitialize(*i.r8) i.r5"
StrCmp $5 "error" +3 +4 ;error means error
IntCmp $5 0 +3 0 0 ; 0 means success, other values means error
messageBox MB_ICONEXCLAMATION "DEBUG: CoInitialize error!"
Goto Error
System::Call /NoUnload "shell32::SHGetMalloc(*i.r9) i.r5"
StrCmp $5 "error" +3 +4 ;error means error
IntCmp $5 0 +3 0 0 ; 0 means success, other values means error
messageBox MB_ICONEXCLAMATION "DEBUG: SHGetMalloc error!"
Goto Error
System::Call /NoUnload "shell32::SHGetDesktopFolder(*i.r6) i.r5"
StrCmp $5 "error" +3 +4 ;error means error
IntCmp $5 0 +3 0 0 ; 0 means success, other values means error
messageBox MB_ICONEXCLAMATION "DEBUG: SHGetDesktopFolder error!"
Goto Error
System::Call /NoUnload "*(&w${MAX_PATH}) i.r2" ;Buffer allocation for unicode path
;Path string must be converted to Unicode
;CodePage=0 (CP_ACP), dwFlags=0, string-to-convert, length=-1(null terminated),
System::Call /NoUnload "kernel32::MultiByteToWideChar(i 0, i 0, t r1, i -1, i r2, i ${MAX_PATH}) i.r5"
IntCmp $5 0 0 0 +3 ; Larger value than 0 indicates success
messageBox MB_ICONEXCLAMATION "DEBUG: MultiByteToWideChar error!"
Goto Error
;Convert Unicode path string to PIDL
System::Call /NoUnload "shell32::ParseDisplayName(i n, i n, i r2, i.n, *i.r1, i n) i.r5"
messageBox MB_ICONEXCLAMATION "DEBUG: 1=$1; 2=$2; 5=$5; 7=$7"
IntCmp $1 0 +3 +6 +6 ;0 means error
StrCmp $5 "error" +2 +5 ;error means error
IntCmp $5 0 +4 0 0 ;0 means success, other values means error
messageBox MB_ICONEXCLAMATION "DEBUG: ParseDisplayName error!"
StrCpy $1 ""
; Goto Error
Nop
;Struct to handle the select folder dialog.
IntOp $4 0 + 1 ;0x01=BIF_RETURNONLYFSDIRS; 0x04=BIF_STATUSTEXT
System::Call /NoUnload "*(i $0, i r1, t r7, t '$3', i $4, i n, i n, i n) i.r5"
;Display the dialog window
System::Call /NoUnload "shell32::SHBrowseForFolder(i r5) i.r4"
IntCmp $4 0 0 +2 +2 ;0 means user cancelled, other values means success
Goto Canceled
;Read out the selected path
System::Call /NoUnload "shell32::SHGetPathFromIDList(i r4, t.r0) i.r6"
System::Call /NoUnload "ole32::CoTaskMemFree(i r4)" ;Free up the memory assigned for the output PIDL
IntCmp $6 0 0 +3 +3 ;0 means error, other values means success
messageBox MB_ICONEXCLAMATION "DEBUG: SHGetPathFromIDList error!"
Goto Error
Error:
StrCpy $0 "error"
Goto Finish
Canceled:
StrCpy $0 ""
Finish:
System::Free $6
System::Free $9
System::Call /NoUnload "ole32::CoUninitialize()"
System::Free $1
System::Free $2
System::Free $5
System::Free $6
System::Free $7
Pop $9
Pop $8
Pop $7
Pop $6
Pop $5
Pop $4
Pop $3
Pop $2
Pop $1
Exch $0
FunctionEnd
The compilable script is in attachement.
PS: Sorry, my english is bad.