- NSIS Discussion
- SHBrowseForFolder problem
Archive: SHBrowseForFolder problem
wraithdu
15th January 2009 19:43 UTC
SHBrowseForFolder problem
Vista SP1 32-bit
NSIS 2.41 (ANSI)
I have 2 problems with this script fragment, and I'm stumped.
1) The icon index always returns 0. I don't think my code is wrong.
2) 9 times out of 10 the script crashes on exit. This is AFTER the System plugin is unloaded. The crash is either in ole32.dll or ntdll.dll. Again, I have no idea why.
Any insight is appreciated!
;=== Program Details
Name "Folder Test"
OutFile "foldertest.exe"
Caption "Folder Test"
;=== Runtime Switches
CRCCheck On
WindowIcon off
SilentInstall Silent
AutoCloseWindow True
RequestExecutionLevel user
XPStyle on
; Best Compression
SetCompress Auto
SetCompressor /SOLID lzma
SetCompressorDictSize 32
SetDatablockOptimize On
Section
System::Call /NOUNLOAD '*(&t 260)i .r0' ; $0 = address to namebuff
; BROWSEINFO struct
System::Call /NOUNLOAD '*(i n, i n, i r0, t "Folder Dialog Title", i 0x40, i n, i n, i n)i .R0' ; $R0 = address of struct
System::Call /NOUNLOAD 'shell32::SHBrowseForFolderA(i R0)i .r5'
System::Call /NOUNLOAD '*$0(&t260 .r3)' ; read namebuff
MessageBox MB_OK "Selected folder: $3"
System::Call /NOUNLOAD 'shell32::SHGetPathFromIDListA(i r5, i $0)i'
System::Call /NOUNLOAD '*$0(&t260 .r3)' ; read namebuff
MessageBox MB_OK "Selected folder path: $3"
System::Call /NOUNLOAD '*$R0(i,i,i,t,i,i,i, i .r2)' ; read icon index
MessageBox MB_OK "Icon index: $2"
; cleanup
System::Call /NOUNLOAD 'ole32::CoTaskMemFree(i r5)v' ; free returned PIDL
System::Free /NOUNLOAD $0 ; free namebuff
System::Free $R0 ; free BROWSEINFO
MessageBox MB_OK "done"
SectionEnd
Anders
15th January 2009 20:25 UTC
I always use SHGetFileInfo to get a icon/iconindex, did not even know that BROWSEINFO had it. But the docs say icon index for folder, not file or drive (it failed on my documents also, so who knows) Do you even need the icon index? or just the HICON?
You also really should add a HWND to BROWSEINFO...
I played around with it a bit and the iconindex is 0 for me also every time. (XP SP2)
Section
System::Call /NOUNLOAD '*(&t 261)i .r0' ; $0 = address to namebuff
; BROWSEINFO struct
System::Call /NOUNLOAD '*(i $hwndparent,i, i r0, t "Folder Dialog Title", i 0x40|0x4000,i,i,i)i.R0'
System::Call /NOUNLOAD 'shell32::SHBrowseForFolderA(i R0)i .r5'
System::Call /NOUNLOAD '*$0(&t260 .r3)' ; read namebuff
DetailPrint "ret = $5, Selected folder: $3"
System::Call /NOUNLOAD 'shell32::SHGetPathFromIDListA(i r5, i $0)i'
System::Call /NOUNLOAD '*$0(&t260 .r3)' ; read namebuff
DetailPrint "Selected folder path: $3"
System::Call /NOUNLOAD '*$R0(i,i,i,i,i,i,i,i.r2)' ; read icon index
DetailPrint "Icon index: $2"
; cleanup
System::Call /NOUNLOAD 'ole32::CoTaskMemFree(i r5)v' ; free returned PIDL
System::Free /NOUNLOAD $0 ; free namebuff
System::Free $R0 ; free BROWSEINFO
DetailPrint "done-----------------"
/*typedef struct _SHFILEINFO {
HICON hIcon;
int iIcon;
DWORD dwAttributes;
TCHAR szDisplayName[MAX_PATH];
TCHAR szTypeName[80];
} SHFILEINFO;*/
!define STRUCTSIZE_SHFILEINFOA 352
#DEFINE SHGFI_ICON 0x000000100
System::Call '*(i,i,i,&t260,&t80)i.r0'
System::Call 'shell32::SHGetFileInfoA(t "$3",i,i $0,i 352,i 0x100)i.r9'
DetailPrint ret=$9,inpath=$3
System::Call '*$0(i.r1,i.r2)'
DetailPrint hIco=$1,icoIdx=$2
System::Free $0
FindWindow $0 "#32770" "" $HWNDPARENT
GetDlgItem $0 $0 0x407
SendMessage $0 ${STM_SETICON} $1 0
SectionEnd
note that it is also possible to use a PIDL with SHGetFileInfo (you did not specify the filesystemonly flag, so you could get virtual paths)
Also, I'm using 2.42 so I don't have to bother with /NOUNLOAD
wraithdu
15th January 2009 20:58 UTC
I don't need the icon index for the folder, but was just curious why it wasn't working.
The bigger issue is why it's crashing consistently on exit on Vista. I'm assuming that it's not crashing on XP since you've tried it...
wraithdu
15th January 2009 21:09 UTC
I just checked with 2.42 and removing /NOUNLOAD, still crashes most of the time.
Anders
15th January 2009 21:26 UTC
and if you don't call CoTaskMemFree or free the buffers?
wraithdu
16th January 2009 04:40 UTC
Still crashes unfortunately. And I've seen the faulting module as both ole32.dll and ntdll.dll.
kichik
16th January 2009 10:03 UTC
You have a space between &t and 260. The buffer you allocate is therefore sized 1 bytes and the initial value of that string is "260".
wraithdu
16th January 2009 15:20 UTC
Wow. Thanks kickik, that did it. I can't believe that was the problem. So it was a buffer overrun type of crash then?
Well, since I have a topic already here instead of starting a new one, can you briefly explain how the &l is used for structure size? The manual doesn't have an example of usage, and I don't see the N for N bytes after it like the others. Thanks again!
kichik
16th January 2009 15:29 UTC
Yes, it caused a heap overflow.
&l is used to get the structure size. It doesn't really set a struct member but only gets the size.
System::Call "*${stBITMAP} (_, &l0 .R7) .R9"
System::Call "${sysGetObject} (r6, R7, R9)"
wraithdu
16th January 2009 15:57 UTC
Ok. So in the above example, the _ character 'skips' all the params and lets you add one to the end of the struct?
kichik
16th January 2009 16:06 UTC
Indeed.
wraithdu
16th January 2009 16:47 UTC
Thanks for all the help!
Maybe add those few tips about &l and _ to the System Plugin Documentation when you have an opportunity.
Keep up the great work!
Anders
16th January 2009 17:53 UTC
DOH, not sure how I missed this one, copy&paste without checking is baaad mmmkay